mirror of
https://github.com/screentinker/screentinker.git
synced 2026-06-29 17:32:53 -06:00
Brings device:command (reboot / screen_off / screen_on / shutdown / update /
launch) to the Tizen player, at parity with the Android player. Previously app.js
only handled device:reload and device:command did nothing on SSSP panels.
- NEW tizen/js/device-control.js: self-contained IIFE (window.STDeviceControl =
{ run, capabilities, backend }). Feature-detects two Samsung surfaces newest-first
— webapis.systemcontrol.* (Tizen 6.5/7, synchronous/throws) then
b2bapis.b2bcontrol.* (SSSP/Tizen 4, async onSuccess/onError) — and normalises both
to Promises, re-probing each call since the APIs can be injected late. run() never
rejects; it resolves a uniform { ok, supported, action, note, reload }. Panel power
tries setPanelMute (mute ON = backlight OFF) then falls back to setDisplayPanel /
setPanelStatus before declaring unsupported. shutdown is honest: SSSP web API has
no true power-off, so it mutes the panel and says so. update/reload resolve
reload:true.
- tizen/js/app.js: keep device:reload; add a device:command handler that calls
STDeviceControl.run and reports the outcome via reportCmd (device:log tag=command,
which surfaces as dashboard:device-log, plus a structured device:command-result),
reloading ~1.2s later when result.reload so the log reaches the server first.
reportCapabilities() runs on device:registered so the dashboard sees the backend
("none" on web/consumer TV).
- tizen/config.xml: add partner-level b2bcontrol + systemcontrol privileges, with a
note that they need a Samsung Partner distributor cert and are ignored (not fatal)
on unsigned/URL-Launcher/web/consumer builds.
- tizen/index.html: load $WEBAPIS/webapis.js + $B2BAPIS/b2bapis.js before the app
scripts (404 harmlessly off-hardware) and device-control.js just before app.js.
- tizen/README.md: document the mapping table + partner-signing caveat; update the
"Not yet ported" note now that remote control exists.
Verified: node --check on both JS files; config.xml well-formed (xmllint). Not yet
validated on a real SSSP panel — the control surface only takes effect on a
partner-signed .wgt (backend reports "none" on the dev/URL-Launcher build).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
120 lines
6.7 KiB
Markdown
120 lines
6.7 KiB
Markdown
# ScreenTinker — Tizen TV Player (`.wgt`)
|
|
|
|
A Samsung **Tizen TV / signage** web port of the ScreenTinker player. It speaks the
|
|
**exact same `/device` socket.io protocol** as the Android player, so a Tizen
|
|
display pairs and plays from the same dashboard with no server changes.
|
|
|
|
## What it does
|
|
- Enter a server URL → connects to `{server}/device` (socket.io v4).
|
|
- Registers, shows a **6-digit pairing code**; you claim it in the dashboard
|
|
(Devices → Pair a display). On `device:paired` it switches to playback.
|
|
- Reconnects automatically with a stored `device_id` + `device_token`.
|
|
- Renders **fullscreen single-zone** playlists, looping:
|
|
- **image** → shown for `duration_sec` (min 3s)
|
|
- **video** (`/api/content/{id}/file` or `remote_url`) → plays to end, then next; single item loops
|
|
- **YouTube** (`mime video/youtube`) → muted autoplay `<iframe>` embed
|
|
- **widget** → `<iframe>` of `{server}/api/widgets/{id}/render`
|
|
- Sends `device:heartbeat` every 15s (with best-effort Tizen telemetry).
|
|
- Keeps the screen awake (`tizen.power` / Samsung `appcommon` screensaver-off).
|
|
|
|
## Files
|
|
```
|
|
config.xml Tizen TV web-app manifest (privileges, profile, icon)
|
|
index.html setup / pairing / stage screens
|
|
css/style.css
|
|
js/app.js device protocol client (register, pair, heartbeat, state)
|
|
js/device-control.js Samsung B2B/system fleet control (device:command) — #125
|
|
js/player.js fullscreen playlist renderer
|
|
js/socket.io.min.js socket.io-client v4.7.5 (bundled)
|
|
icon.png
|
|
build-wgt.sh package (signed if Tizen CLI present, else unsigned)
|
|
```
|
|
|
|
## Fleet control / `device:command` (#125)
|
|
The dashboard can send `device:command { type, payload }`; `js/device-control.js`
|
|
maps it onto a Samsung panel-control surface and reports the outcome back via
|
|
`device:log` (tag `command`, shown live on the device-detail screen) plus a
|
|
structured `device:command-result`. If a command needs a content re-pull, the
|
|
player reloads ~1.2s after reporting.
|
|
|
|
| `type` | Action on a Samsung panel |
|
|
|---------------------|------------------------------------------------------------------------|
|
|
| `reboot` | `rebootDevice()` |
|
|
| `screen_off` | `setPanelMute("ON")` — **mute ON = backlight OFF** (note the inversion)|
|
|
| `screen_on` | `setPanelMute("OFF")` |
|
|
| `shutdown` | `setPanelMute("ON")` + note: SSSP web API has **no true power-off** |
|
|
| `update` | reload to re-pull URL-Launcher content (no in-app OTA) |
|
|
| `launch` | no-op (already foreground) |
|
|
| `reload` / `refresh`| reload |
|
|
| _unknown_ | reported as `unsupported` |
|
|
|
|
Two surfaces are feature-detected, newest first: **`webapis.systemcontrol.*`**
|
|
(Tizen 6.5/7, synchronous) then **`b2bapis.b2bcontrol.*`** (SSSP/Tizen 4, async).
|
|
For panel power, `setPanelMute` is tried first, falling back to `setDisplayPanel` /
|
|
`setPanelStatus` on older firmware before declaring it unsupported. `run()` never
|
|
throws — it always resolves a uniform `{ ok, supported, action, note, reload }`.
|
|
|
|
> **Partner-signing caveat.** The `b2bcontrol` / `systemcontrol` privileges in
|
|
> `config.xml` only take effect on a **partner-signed `.wgt` running on a real SSSP
|
|
> panel**. On the dev/URL-Launcher/web build (or a consumer TV) the surfaces are
|
|
> absent, so every command returns **"unsupported"** and the startup capability log
|
|
> reports `backend=none`. Only a partner-signed build on real hardware fully
|
|
> validates reboot / panel power.
|
|
|
|
## Build
|
|
```bash
|
|
./build-wgt.sh # -> ScreenTinker.wgt
|
|
```
|
|
Without the Tizen CLI this is an **unsigned** `.wgt`.
|
|
|
|
> **Why the released `.wgt` is unsigned:** Samsung **distributor** certificates
|
|
> are locked to the **DUID** of the signer's own TVs, so a `.wgt` we signed would
|
|
> not install on your TV anyway. Releases therefore ship it unsigned (for
|
|
> inspection only). To actually run it, use **path A** (no signing) or sign it
|
|
> yourself with your own certificate (**path B**).
|
|
|
|
## Deploy — two paths
|
|
|
|
### A) URL Launcher / TV browser (easiest, no signing)
|
|
No package, no Tizen Studio. Point the TV's **URL Launcher** (or just its web
|
|
browser) at your server's built-in web player: `https://<your-instance>/player`.
|
|
The TV runs it as a web app on boot, pairs with a 6-digit code, and plays - best
|
|
for Samsung B2B signage (SSSP). (You can instead self-host this `tizen/` folder
|
|
and point the URL Launcher at `…/index.html` for the Tizen-specific build.)
|
|
|
|
### B) Signed `.wgt` (installed app)
|
|
A signing profile is already set up on the build box (Tizen Studio CLI 6.1):
|
|
- **Profile `ScreenTinker`** = a self-signed **author** cert
|
|
(`~/tizen-studio-data/keystore/author/st_author.p12`) + the default Tizen
|
|
**distributor** cert. `./build-wgt.sh` auto-detects the CLI and signs with it,
|
|
producing a `.wgt` with `author-signature.xml` + `signature1.xml`.
|
|
- This installs on **developer-mode** Samsung TVs and the **Tizen emulator** —
|
|
the right path for a **self-hosted fleet you control** (enable Developer Mode
|
|
on each TV once: Apps → enter `12345` → set the host IP).
|
|
|
|
Install onto a dev-mode TV:
|
|
```bash
|
|
sdb connect <tv-ip>
|
|
tizen install -n ScreenTinker.wgt -t <tv-device>
|
|
```
|
|
|
|
**Production / retail (no developer mode):** re-sign with a Samsung **Partner**
|
|
or **Public** distributor certificate from the Tizen **Certificate Manager**
|
|
(free Samsung account; distributor cert tied to each TV's **DUID**), then
|
|
`./build-wgt.sh <thatProfile>`. The self-signed author cert is not committed (it
|
|
lives in `~/tizen-studio-data`, password `screentinker`).
|
|
|
|
## Validated (2026-06-09)
|
|
- **Protocol**: headless test against the live server passed end-to-end —
|
|
`register(pairing_code) → device:registered → pair → reconnect(device_id+token)
|
|
→ device:playlist-update(2 items) → GET /api/content/{id}/file = 200`.
|
|
- **Runtime**: loads + renders in Chromium with no JS errors (setup screen verified).
|
|
- Not yet on real Tizen hardware — needs signing + a TV (or URL Launcher).
|
|
|
|
## Not yet ported (Android player has these; fullscreen single-zone covers most signage)
|
|
Multi-zone layouts, video walls (`wall:sync`), screenshots, and remote touch.
|
|
Self-OTA is N/A (Tizen apps update via Samsung's store / URL Launcher refresh, not
|
|
the Android `PackageInstaller` flow). **Fleet control (`device:command`: reboot /
|
|
screen on-off / shutdown / update / launch) is now wired** — see the section above
|
|
(needs a partner-signed build on real SSSP hardware to fully take effect).
|