Self-contained examples for the PiP overlay API (POST /api/pip), each with a CSP-safe query-param overlay (external JS), config.example.json, zero runtime deps, an offline test, and a README: - PIP-Announce-Broadcast manual one-shot message to a screen/group - PIP-Weather-Widget Open-Meteo current conditions (keyless) - PIP-Air-Quality Open-Meteo US AQI widget (keyless) - PIP-Crypto-Ticker CoinGecko price strip (keyless) - PIP-News-Ticker scrolling RSS/Atom headlines - PIP-Room-Status-Calendar ICS-driven Available/Busy room sign - PIP-Event-Countdown client-side countdown, auto-clears at zero - PIP-Welcome-Board rotating welcome/birthday cards from CSV - PIP-Fundraiser-Thermometer goal-progress bar from local/URL JSON - PIP-QR-Rotator rotating QR codes, encoded client-side - PIP-Incident-Webhook event-driven: red on firing, clear on resolved Also includes the CAP-AU (NSW RFS) and US NWS/NOAA emergency-alert monitors that push expiry-aware PiP overlays. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
3.9 KiB
PiP Incident Webhook
An event-driven PiP example: a tiny webhook receiver that turns your monitoring stack's alerts into a floating ScreenTinker overlay — perfect for an engineering wall TV or NOC screen.
- alert firing → red overlay appears (kept until cleared)
- alert resolved → overlay disappears
Unlike the CAP / NOAA examples (which poll a feed), nothing happens here until your
alerting system pushes to POST /webhook. Zero runtime dependencies — just Node 18+
(http + global fetch).
Payload shapes
It accepts either:
Generic (great for curl, cron jobs, custom scripts):
{ "status": "firing", "key": "db-down", "title": "Primary DB unreachable", "detail": "conn refused on 5432", "severity": "critical" }
Prometheus Alertmanager (point a webhook_config straight at it):
{ "status": "firing", "alerts": [
{ "status": "firing", "fingerprint": "abc123",
"labels": { "alertname": "HighCPU", "severity": "warning", "instance": "web-1" },
"annotations": { "summary": "CPU > 90%", "description": "web-1 hot for 5m" } }
]}
severity drives the band colour: critical→dark red, warning→orange, info→amber,
anything else→red. The key (or Alertmanager fingerprint) is what matches a later
resolve back to the overlay it should clear.
Setup
cp config.example.json config.jsonand fill in:api_token— anst_API token with thefullscope.api_base/overlay_base_url— your signage server.device_id— a device or group id.shared_secret(optional) — if set, callers must send it as theX-Webhook-Secretheader or?secret=query param.
- Serve the overlay assets. The overlay is a
webPiP rendered in an iframe, so the player fetchesoverlay_base_urldirectly. Copyincident-overlay.htmlandincident-overlay.jsinto the directory your signage server serves at the web root (e.g. the server'sfrontend/dir) so thathttps://<server>/incident-overlay.htmlresolves. They must be same-origin with the player (the server CSP only allows same-origin scripts — that's why the JS is an externalincident-overlay.js, not inline). node server.js(ornpm start).
Local quick-start (this repo's dev server)
cp config.example.json config.json
# edit config.json:
# "api_base": "https://localhost:3443/"
# "api_token": "st_REPLACE_WITH_A_FULL_SCOPE_TOKEN"
# "overlay_base_url": "https://localhost:3443/incident-overlay.html"
# "device_id": "DEVICE_OR_GROUP_ID"
# copy the overlay assets into the server's web root (served same-origin as the player):
cp incident-overlay.html incident-overlay.js ../../frontend/
# self-signed cert on localhost -> let Node accept it:
NODE_TLS_REJECT_UNAUTHORIZED=0 node server.js
Then drive it with curl:
# fire a critical incident -> red overlay appears on the player
curl -s localhost:8088/webhook -H 'Content-Type: application/json' -d \
'{"status":"firing","key":"db-down","title":"Primary DB unreachable","detail":"conn refused on 5432","severity":"critical"}'
# ...later, resolve it -> overlay clears
curl -s localhost:8088/webhook -H 'Content-Type: application/json' -d \
'{"status":"resolved","key":"db-down"}'
# health
curl -s localhost:8088/healthz
Ctrl-C clears any still-showing overlays before exiting.
Heads-up: this dev box has a shared player. If someone else is demoing on
d7c88aa0-…, pointdevice_idat your own device/group instead.
Wire up Alertmanager
# alertmanager.yml
route:
receiver: signage
receivers:
- name: signage
webhook_configs:
- url: http://YOUR_HOST:8088/webhook
send_resolved: true # so "resolved" clears the overlay
If you set a shared_secret, append it to the URL: ...:8088/webhook?secret=YOUR_SECRET.
Test
npm test # offline; exercises both payload shapes + the colour map