screentinker/Examples/PIP-Crypto-Ticker/README.md
ScreenTinker ab771ec595 Add PiP overlay example recipes
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>
2026-06-18 20:17:38 -05:00

113 lines
4.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# PiP Crypto Ticker
A live cryptocurrency **price ticker** for ScreenTinker screens. Polls
[CoinGecko](https://www.coingecko.com/en/api)'s keyless `simple/price` endpoint and
pushes a wide ticker-strip overlay via the **PiP API**. Each poll refreshes the same
overlay in place; prices update without a flash.
No API key required. Zero runtime dependencies (Node 18+ global `fetch`).
```
┌────────────────────────────────────────────────────────────────┐
│ BTC $64,012.34 ▲ +1.23% • ETH $3,380.10 ▼ -0.46% • SOL … │
└────────────────────────────────────────────────────────────────┘
```
## How it works
1. `ticker.js` fetches `GET /api/v3/simple/price?ids=…&vs_currencies=…&include_24hr_change=true`.
2. It normalises the response into ordered items and encodes them compactly into the
overlay URL's query string (`items=BTC:64012.34:+1.23,…`).
3. It pushes a `type: "web"` PiP overlay (`duration: 0`, i.e. persistent) pointing at
`ticker-overlay.html`, which renders the strip. Up = green ▲, down = red ▼, flat = grey.
4. On the next poll it pushes again — the player keeps a single overlay slot
(last-show-wins), so the numbers refresh in place.
5. `Ctrl-C` (SIGINT) clears the overlay.
## Files
| file | purpose |
|------|---------|
| `ticker.js` | poller + PiP pusher (and the pure, exported normaliser/encoder) |
| `ticker-overlay.html` / `ticker-overlay.js` | the overlay page (served by the signage server) |
| `config.example.json` | copy to `config.json` and fill in |
| `fixture-prices.json` | a saved CoinGecko response for the offline test |
| `test.js` | offline test — no network, no PiP push |
## Setup
The overlay page must be served **same-origin** with the signage server (the player
loads it in an iframe, and the server CSP only allows same-origin scripts). Copy the
two overlay files into the server's static frontend directory:
```sh
cp ticker-overlay.html ticker-overlay.js /path/to/screentinker/frontend/
```
Then they're reachable at `https://<your-server>/ticker-overlay.html`.
Create a **full-scope** `st_` API token in the dashboard (Settings → API tokens), then:
```sh
cp config.example.json config.json
# edit config.json: api_base, api_token, overlay_base_url, device_id, coins
node ticker.js
```
`device_id` may be a single device **or** a device group id.
### Config
| key | meaning |
|-----|---------|
| `api_base` | signage server base URL |
| `api_token` | full-scope `st_` token |
| `overlay_base_url` | URL of the served `ticker-overlay.html` |
| `device_id` | target device or group id |
| `vs_currency` | `usd`, `eur`, `gbp`, … |
| `coins` | array of `{ id, symbol }``id` is the CoinGecko id |
| `poll_interval_sec` | refresh cadence (default 120; respect CoinGecko rate limits) |
| `position` | `bottom-right` (default), `top-left`, … |
| `width` / `height` | overlay box px (default 1100×110) |
## Local quick-start (this machine)
A local ScreenTinker instance is already running on `https://localhost:3443` with a
paired web player (device `DEVICE_OR_GROUP_ID`). It uses a self-signed
cert, so set `NODE_TLS_REJECT_UNAUTHORIZED=0`.
```sh
# 1. serve the overlay assets from the local frontend dir
cp ticker-overlay.html ticker-overlay.js /home/owner/Downloads/remote_display/frontend/
# 2. config.json
cat > config.json <<'JSON'
{
"api_base": "https://localhost:3443/",
"api_token": "st_REPLACE_WITH_A_FULL_SCOPE_TOKEN",
"overlay_base_url": "https://localhost:3443/ticker-overlay.html",
"device_id": "DEVICE_OR_GROUP_ID",
"vs_currency": "usd",
"coins": [
{ "id": "bitcoin", "symbol": "BTC" },
{ "id": "ethereum", "symbol": "ETH" },
{ "id": "solana", "symbol": "SOL" }
],
"poll_interval_sec": 120,
"position": "bottom-right"
}
JSON
# 3. run
NODE_TLS_REJECT_UNAUTHORIZED=0 node ticker.js
```
## Test (offline)
```sh
npm test
```
Validates price/percent formatting, up/down/flat direction, and that the compact
`items` encoding round-trips through the overlay's decoder. Prints `RESULT: PASS ✅`.