Trigger nodes now self-contained inputs (inputs:0): - Each registers POST /api/internal/<topic> on RED.httpNode - Angie returns 404 for any /api/* not whitelisted (kiosk/pair/admin) so external requests cannot trigger BF nodes - Server bridge POSTs direct to nodered container (bypasses Angie) - nodered-bridge.ts updated to use /api/internal/<topic> - 6 trigger nodes converted: display-power, layout-changed, kiosk-changed, camera-changed, status, kiosk-camera-event - Optional per-node filters (display_id, kiosk_id, camera_id) - close handler removes only this node's route layer |
||
|---|---|---|
| .. | ||
| icons | ||
| src | ||
| package.json | ||
| README.md | ||
@betterframe/nodered-nodes
BetterFrame integration nodes for Node-RED. Drag-and-droppable nodes for the BetterFrame admin REST API and kiosk event ingest.
Nodes
| Node | Category | Purpose |
|---|---|---|
bf-server-config |
config | Shared server URL + admin API key |
bf-kiosk-camera-event |
Triggers | Filter incoming kiosk camera events (default camera.*) |
bf-trigger-display-power |
Triggers | Fires on display.power.changed |
bf-trigger-layout-changed |
Triggers | Fires on layout.changed |
bf-trigger-kiosk-changed |
Triggers | Fires on kiosk.changed (connect/disconnect/heartbeat) |
bf-trigger-camera-changed |
Triggers | Fires on camera.changed (created/updated/deleted) |
bf-trigger-status |
Triggers | Fires on kiosk.status (heartbeat-only telemetry; optional kiosk_id filter) |
bf-layout-switch |
BetterFrame | Switch a display's active layout |
bf-power |
BetterFrame | Wake / standby a kiosk display |
bf-fan |
BetterFrame | Set fan mode (auto/pwm) on a kiosk |
bf-cameras |
BetterFrame | Fetch the camera list |
bf-config-get |
BetterFrame | Fetch BF state (displays/kiosks/cameras/layouts/entities, by id or full list) |
bf-config-set |
BetterFrame | Mutate BF state (default layout, enabled, priority, name) |
bf-status |
BetterFrame | Fetch current kiosk state by ID (telemetry, last_seen_at, etc.) |
bf-snapshot |
BetterFrame | Fetch a JPEG snapshot for a camera entity (binary Buffer payload) |
Authentication
All action/query nodes use an admin-scoped API key created in the
BetterFrame admin UI. The key is sent as Authorization: Bearer bf-....
Configure once on a bf-server-config node and reference it from the others.
Event ingest path
Trigger nodes are self-contained — each one registers its own
POST /in/<topic> handler on Node-RED's user-facing HTTP server (via
RED.httpNode.post) when the flow is deployed. You do not need to wire
an upstream http in node anymore.
The BetterFrame server's nodered-bridge.forward(topic, payload) posts
events directly to http://<nodered-host>:1880/in/<topic>. Each trigger
node listens on its own fixed topic:
| Node | Internal route |
|---|---|
bf-trigger-display-power |
POST /in/display.power.changed |
bf-trigger-layout-changed |
POST /in/layout.changed |
bf-trigger-kiosk-changed |
POST /in/kiosk.changed |
bf-trigger-camera-changed |
POST /in/camera.changed |
bf-trigger-status |
POST /in/kiosk.status |
bf-kiosk-camera-event |
POST /in/camera.event |
The server emits these topics from coordinator-ws (kiosk WS lifecycle) and the admin routes (layout/power/camera mutations). Multiple instances of the same trigger node on the same canvas are fine — Express runs all matching handlers in registration order.
If the Angie proxy fronts Node-RED, the otherwise-unmatched root paths
(public HTTP-in URLs) and the /in/kiosk/<topic> (kiosk-key gated) /
/in/public/<topic> (public, rate-limited) routes are still available
for user-authored flows that use stock http in nodes — those layers
strip the prefix before proxying. The trigger nodes' fixed
/in/<topic> routes are reserved for internal server-to-Node-RED
delivery and are not exposed through the proxy's gated surfaces by
default.
Each trigger node also offers an optional ID filter (display_id / kiosk_id / camera_id) so you can drop one node per entity without a downstream switch.
Installation
Dev (single-host BetterFrame install)
# Symlink the package into Node-RED's user dir so edits hot-reload.
ln -s "$(pwd)/nodered" ~/.node-red/node_modules/@betterframe/nodered-nodes
# Restart Node-RED.
Docker compose
The compose stack mounts nodered-data as /data. Either:
- bake the package into the Node-RED image by extending the Dockerfile with
npm install /repo/nodered, or - mount
./noderedinto/data/node_modules/@betterframe/nodered-nodesand restart the container.