2025-03-31 23:27:57 +02:00
2025-03-31 23:27:57 +02:00
2025-03-31 23:27:57 +02:00
2025-03-31 23:27:57 +02:00
2025-03-31 23:27:57 +02:00
2025-03-31 23:27:57 +02:00
2025-03-31 23:27:57 +02:00
2025-03-31 23:27:57 +02:00
2025-03-25 21:40:18 +01:00
2025-03-31 23:27:57 +02:00
2025-03-31 23:27:57 +02:00
2025-03-31 23:27:57 +02:00
2025-03-31 23:27:57 +02:00

Flic to PWA WebPush Backend

This project provides a self-hosted backend service that listens for HTTP requests from Flic smart buttons and triggers Web Push notifications to specific Progressive Web App (PWA) instances. The goal is to allow a Flic button press (Single Click, Double Click, Hold) to trigger actions within the PWA via push messages handled by a Service Worker.

It's designed to be run as a Docker container and integrated with Traefik v3 for SSL termination and routing.

Features

  • Receives GET requests on /webhook.
  • Receives POST requests on /subscribe to manage button-PWA mappings.
  • Uses HTTP headers Button-Name and Timestamp from the Flic request.
  • Gets click_type from URL path.
  • Looks up the target PWA push subscription based on the Button-Name header in a JSON file.
  • Sends a Web Push notification containing the click details (action, button, timestamp) to the corresponding PWA subscription.
  • Integrates with Traefik v3 via Docker labels.
  • Configurable via environment variables (.env file).
  • Optional Basic Authentication for securing the /webhook and /subscribe endpoints.

Prerequisites

  • Docker: Install Docker
  • Traefik: A running Traefik v3 instance configured with SSL (Let's Encrypt recommended) and connected to a Docker network named traefik. You need to know your certificate resolver name.
  • Domain Name: A domain or subdomain pointing to your Traefik instance (e.g., webpush.virtonline.eu). This will be used for the webhook URL.
  • Flic Hub/Service: Configured to send HTTP requests for button actions. You'll need the serial number(s) of your Flic button(s).
  • Node.js & npm/npx (Optional): Needed only locally to generate VAPID keys easily. Not required for running the container.
  • PWA Push Subscription Details: You need to obtain the Push Subscription object (containing endpoint, keys.p256dh, keys.auth) from your PWA after the user grants notification permission.

System Architecture

Subscription Flow

Subscription Flow

Interaction Flow

Interaction Flow

Project Structure

Setup

  1. Clone the Repository:

    git clone https://gitea.virtonline.eu/2HoursProject/flic-webhook-webpush.git
    cd flic-webhook-webpush
    
  2. Generate VAPID Keys: Web Push requires VAPID keys for security. Generate them once and store them into .env. You can use npx:

    npx web-push generate-vapid-keys
    

    This will output a Public Key and a Private Key.

  3. Configure Environment Variables:

  • Copy the example .env file:
    cp .env.example .env
    
  • Edit the .env file with your specific values:
    • VAPID_PUBLIC_KEY: The public key generated in step 2. Your PWA will also need this key when it subscribes to push notifications.
    • VAPID_PRIVATE_KEY: The private key generated in step 2. Keep this secret!
    • VAPID_SUBJECT: A mailto: or https: URL identifying you or your application (e.g., mailto:admin@yourdomain.com). Used by push services to contact you.
    • PORT: (Default: 3000) The internal port the Node.js app listens on. Traefik will map to this.
    • SUBSCRIPTIONS_FILE: (Default: subscriptions.json) The path inside the container where the button-to-subscription mapping is stored.
    • DEFAULT_BUTTON_NAME: (Default: game-button) The default button name to use when the Button-Name header is not provided in the webhook request.
    • BASIC_AUTH_USERNAME: (Optional) Username for Basic Authentication. If set along with BASIC_AUTH_PASSWORD, authentication will be enabled for /webhook and /subscribe.
    • BASIC_AUTH_PASSWORD: (Optional) Password for Basic Authentication. If set along with BASIC_AUTH_USERNAME, authentication will be enabled.
    • NOTIFICATION_MAX_RETRIES: (Default: 3) Number of retry attempts for failed push notifications. Must be a number.
    • NOTIFICATION_FIRST_RETRY_DELAY_MS: (Default: 10) Delay in milliseconds for the first retry attempt. Setting to 0-10ms provides near-immediate first retry for transient DNS issues. Must be a number.
    • NOTIFICATION_SUBSEQUENT_RETRY_DELAY_MS: (Default: 1000) Base delay in milliseconds for subsequent retries. Each additional retry uses this value with exponential backoff and jitter. Must be a number.
    • DNS_TIMEOUT_MS: (Default: 5000) DNS resolution timeout in milliseconds. Must be a number.
    • HTTP_TIMEOUT_MS: (Default: 10000) HTTP request timeout in milliseconds. Must be a number.
    • LOG_LEVEL: (Default: info) Controls verbosity of logs. Valid values are error, warn, info, or debug. Use debug to see detailed header information and other diagnostic messages.
  1. Configure Traefik Labels:
  • Copy the example labels file:
    cp labels.example labels
    

Running the Service

  1. Build the Docker Image: Make sure you are in the flic-webhook-webpush directory.

    docker build -t flic-webhook-webpush:latest .
    
  2. Run the Container: This command runs the container in detached mode (-d), names it, connects it to the traefik network, passes environment variables from the .env file, applies the Traefik labels from the labels file, and mounts the subscriptions.json file into the container.

    docker run --rm -d --name flic-webhook-webpush \
      --network traefik \
      --env-file .env \
      --label-file labels \
      --mount type=bind,src=./subscriptions.json,dst=/app/subscriptions.json \
      flic-webhook-webpush:latest
    
  3. Check Logs: Monitor the container logs to ensure it started correctly and to see incoming webhook requests or errors.

    docker logs -f flic-webhook-webpush
    

    You should see messages indicating the server started, configuration details, and subscription loading status.

  4. Verify Traefik: Check your Traefik dashboard to ensure the flic-webhook-webpush service and router are discovered and healthy.

Flic Button Configuration

In your Flic app or Flic Hub SDK interface:

  1. Select your Flic button.
  2. Add an "Internet Request" action.
  3. Fill in the following details:
    • Select the GET method.
    • Set URL with query parameter: https://webpush.virtonline.eu/webhook/SingleClick
    • If Basic Authentication is enabled:
      • Set the Headers:
        • Set the Key fields to Authorization.
        • Set the Value fields to Basic <base64 encoded username:password> (e.g., Basic dXNlcm5hbWU6cGFzc3dvcmQ=). Use $(echo -n 'user:password' | base64) to generate the base64 encoded string.
        • Click ADD.
    • Tap on SAVE ACTION.
  4. Repeat for Double Click (i.e., /DoubleClick) and Hold (i.e., /Hold) events.
    The request for the Hold event should look like this:
Flic Button Request

App Example: "HTTP Shortcuts" by waboodoo

Search the Play Store - there might be others with similar names.

  1. Install the App: Download and install "HTTP Shortcuts" or a similar app from the Google Play Store.
  2. Create a New Shortcut within the App:
    • Open the app and usually tap a '+' or 'Add' button.
    • Give your shortcut a Name (e.g., "Turn on Office Light", "Log Water Intake").
    • Choose an Icon.
    • Enter the URL you want the request sent to (your webhook URL, IFTTT URL, Home Assistant webhook trigger, etc.).
    • Select the HTTP Method (GET, POST, PUT, DELETE, etc. - often GET or POST for simple triggers).
    • For POST/PUT: You'll likely need to configure the Request Body (e.g., JSON data) and Content Type (e.g., application/json).
    • Authentication: Configure Basic Auth, Bearer Tokens, or custom Headers if your endpoint requires authentication.
    • Other Options: Explore settings for response handling (show message on success/failure), timeouts, etc.
    • Save the shortcut configuration within the app.
  3. Add the Widget/Shortcut to your Home Screen:
    • Go to your Android Home Screen.
    • Long-press on an empty space.
    • Select "Widgets".
    • Scroll through the list to find the "HTTP Shortcuts" app (or the app you installed).
    • Drag the app's widget or shortcut option onto your home screen.
    • The app will likely ask you to choose which specific shortcut (the one you just created) this widget should trigger. Select it.
  4. Test: Tap the newly created button on your home screen. It should trigger the internet request you configured.

API Endpoints

  • POST /subscribe

    • Description: Adds or updates the Web Push subscription associated with a specific Flic button ID.
    • Authentication: Optional Basic Authentication via Authorization header if BASIC_AUTH_USERNAME and BASIC_AUTH_PASSWORD are configured.
    • Request Body: JSON object containing:
      • button_id (string, optional): The unique identifier for the Flic button (lowercase recommended, e.g., "game-button", "lights-button"). If not provided, the value of DEFAULT_BUTTON_NAME environment variable will be used as a fallback.
      • subscription (object, required): The PushSubscription object obtained from the browser's Push API.
      {
        "button_id": "game-button",
        "subscription": {
          "endpoint": "https://your_pwa_push_endpoint...",
          "expirationTime": null,
          "keys": {
            "p256dh": "YOUR_PWA_SUBSCRIPTION_P256DH_KEY",
            "auth": "YOUR_PWA_SUBSCRIPTION_AUTH_KEY"
          }
        }
      }
      
    • Responses:
      • 201 Created: Subscription saved successfully.
      • 400 Bad Request: Missing or invalid subscription object in the request body.
      • 401 Unauthorized: Missing or invalid Basic Authentication credentials (if authentication is enabled).
      • 500 Internal Server Error: Failed to save the subscription to the file.
  • GET /webhook/:click_type

    • Description: Receives Flic button events.
    • Authentication: Optional Basic Authentication via Authorization header if BASIC_AUTH_USERNAME and BASIC_AUTH_PASSWORD are configured.
    • URL Parameters:
      • click_type (required): The type of button press (e.g., SingleClick, DoubleClick, or Hold).
    • Optional Headers:
      • Button-Name: The identifier of the Flic button (sent by the Flic system). If not provided, the value of DEFAULT_BUTTON_NAME environment variable will be used as a fallback.
      • Timestamp: Timestamp of the button event (sent by the Flic system).
      • Button-Battery-Level: The battery level percentage of the button (sent by the Flic system).
    • Responses:
      • 200 OK: Webhook received, push notification sent successfully.
      • 400 Bad Request: Missing Button-Name header or click_type URL parameter.
      • 401 Unauthorized: Missing or invalid Basic Authentication credentials (if authentication is enabled).
      • 404 Not Found: No subscription found in subscriptions.json for the given Button-Name.
      • 410 Gone: The push subscription associated with the button was rejected by the push service (likely expired or revoked).
      • 500 Internal Server Error: Failed to send the push notification for other reasons.

Testing the Webhook

Once your service is up and running, you can test the webhook endpoint using curl or any API testing tool. This example assumes Basic Authentication is enabled.

Note: Replace <username>, <password> with your actual values. The Button-Name header is optional and will default to the value of DEFAULT_BUTTON_NAME if not provided.

curl -X GET "https://webpush.virtonline.eu/webhook/SingleClick"   \
  -H "Authorization: Basic $(echo -n 'user:password' | base64)"   \
  -H "Button-Name: game-button"   \
  -H "Timestamp: $(date -u +%Y-%m-%dT%H:%M:%SZ)"   \
  -H "Button-Battery-Level: 100"

The expected response should be:

{"message":"Push notification sent successfully"}

If successful, the above response indicates that:

  1. Your webhook endpoint is properly configured
  2. The button name was found in your subscriptions.json file
  3. The web push notification was successfully sent to the registered PUSH API endpoint (e.g. https://jmt17.google.com/fcm/send/cf907M...)

If you receive a different response, refer to the Troubleshooting section below.

Troubleshooting

  • Check Backend Logs: docker logs flic-webhook-webpush. Look for errors related to configuration, file access, JSON parsing, authentication, or sending push notifications.
  • To see detailed debug information including all headers received from the Flic button, set LOG_LEVEL=debug in your .env file.
  • Check Traefik Logs: docker logs traefik. Look for routing errors or certificate issues.
  • Verify .env: Ensure all required variables are set correctly, especially VAPID keys and Traefik settings.
  • Verify labels: Double-check that variables were correctly substituted manually and match your .env and Traefik setup.
  • Verify subscriptions.json: Ensure it's valid JSON and the button serial number (key) matches exactly what Flic sends (check backend logs for "Received webhook: Button=..."). Check if the subscription details are correct. Case sensitivity matters for the JSON keys (button serials).
  • Check Flic Configuration: Ensure the URL, Method, click_type parameter, and authentication details (Username/Password if enabled) are correct in the Flic action setup. Use curl or Postman to test the endpoint manually first.
  • PWA Service Worker: Remember that the PWA needs a correctly registered Service Worker to receive and handle the incoming push messages. Ensure the PWA subscribes using the same VAPID_PUBLIC_KEY configured in the backend's .env.
  • Push Notification Retry Mechanism: The service includes an optimized retry mechanism for handling temporary DNS resolution issues:
    • First retry happens immediately or with minimal delay (controlled by NOTIFICATION_FIRST_RETRY_DELAY_MS, default 10ms)
    • Subsequent retries use exponential backoff with jitter (starting from NOTIFICATION_SUBSEQUENT_RETRY_DELAY_MS, default 1000ms)
    • Maximum number of retries is controlled by NOTIFICATION_MAX_RETRIES (default 3)
    • This approach minimizes latency for transient DNS issues while preventing excessive requests for persistent problems
    • Adjust these values in your .env file based on your network conditions and reliability requirements
Description
solution for handling Flic smart button events and sending web push notifications to a Progressive Web App
Readme 888 KiB
Languages
JavaScript 92.6%
Dockerfile 3.9%
Mermaid 3.5%