mirror of
https://github.com/screentinker/screentinker.git
synced 2026-06-29 09:23:16 -06:00
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>
113 lines
4.2 KiB
Markdown
113 lines
4.2 KiB
Markdown
# 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 ✅`.
|