npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

signalk-espos-stream

v0.1.0

Published

Streams a browser-rendered Signal K dashboard to an espOS panel as ACK-paced MJPEG with a touch backchannel, running the capture chain (Xvfb + Chromium + ffmpeg) in a managed container.

Downloads

220

Readme

signalk-espos-stream

Streams a browser-rendered Signal K dashboard (Freeboard-SK, KIP, any URL) to an espOS panel — an ESP32-P4 cockpit display — as ACK-paced MJPEG, with a touch backchannel so the panel can drive the page. The whole capture chain runs in a single managed container; the plugin's only host-side job is configuration, lifecycle and health.

How it works

┌────────────────────────────── sk-espos-stream container ─────────────┐
│ Xvfb :99 ── Chromium kiosk (capture URL) ── ffmpeg x11grab (MJPEG)   │
│      ▲                                             │                 │
│   XTEST                                     latest-frame slot        │
│      │                                             │                 │
│ UDP :5005 touch ◄──────────┐            TCP :5004 ACK-paced stream   │
│ http://127.0.0.1:5006/health (plugin-only)         │                 │
└────────────────────────────┼───────────────────────┼─────────────────┘
                             │                       ▼
                        espOS panel  ◄──── [u32 BE len][JPEG], 1-byte ACK
  • Stream (TCP): [u32 BE length][baseline JPEG]; the panel sends a 1-byte ACK after each frame reaches its renderer, and the server responds with only the newest frame — at most one frame in flight, so the panel paces its own frame rate and the ESP32's WiFi link is never flooded.
  • Touch (UDP): 8-byte packets; the first 5 bytes are significant — little-endian u16 x, u16 y, u8 type (0 down / 1 move / 2 up) — and bytes 5–7 are reserved padding the server ignores. Injected into the kiosk via XTEST; only packets from the connected stream client's IP are accepted.
  • Host networking: the container shares the host network namespace, so the default capture URL http://localhost:80/... reaches Signal K directly and the stream/touch ports bind on the host as-is.

The matching panel-side widget is the stream widget in espos-p4-cockpit; layouts are designed with signalk-hmi-designer.

Requirements

  • Signal K server ≥ 2.x, Node ≥ 22
  • signalk-container installed and enabled (this plugin declares it via signalk.requires)
  • podman or docker reachable by signalk-container
  • linux/arm64 or an image you built locally (see below)

Configuration

| Setting | Default | Notes | | ---------------------- | -------------------------------------------- | --------------------------------------------------- | | Capture URL | http://localhost:80/@signalk/freeboard-sk/ | page the kiosk renders | | Image tag | auto | image released in lockstep with this plugin version | | Width x Height | 1024x600 | match the panel display | | Frame rate | 15 | ceiling; the panel self-paces below it | | JPEG quality | 6 | ffmpeg -q:v, lower is better | | Stream port | 5004 (TCP) | panel stream widget port | | Touch port | 5005 (UDP) | panel stream widget touch_port | | Touch injection | on | | | Advanced: health port | 5006 | loopback-only | | Advanced: memory limit | 1g | Chromium peaks ~500 MB at 1024x600 |

Kiosk login (no keyboard)

On a server with security enabled, Freeboard-SK pops a login dialog that a touch-only panel can never answer. Set the Access token option instead: the plugin appends it to the capture URL as ?token=…, which Freeboard-SK reads at launch and uses for both REST and its stream connection — the login dialog never appears (this is FSK's supported kiosk path; the Login menu item is hidden when a URL token is present).

Click Generate (1 year) next to the Access token field in the plugin's config panel: it mints a token for your logged-in user through the server's own security strategy (the same signing path as signalk-generate-token) and fills the field — then Save. The admin-only POST /plugins/signalk-espos-stream/api/kiosk-token route behind the button accepts {"expiration": "90d"} for a shorter life; it always mints for the authenticated requester, so for a dedicated read-mostly kiosk user, log into the Admin UI as that user and click Generate there (or use the CLI below).

Alternatively, mint one by hand with the server's bundled tool:

signalk-generate-token -u <user> -e 1y -s ~/.signalk/security.json

The token inherits the named user's permissions, and it appears in the container's command line locally (podman inspect), so treat host access as equivalent to holding the token. A device access token works here too if you still have it — paste it into the field — but the plugin cannot recover one for you: the server stores only device metadata, never the token itself.

The Chromium profile persists in the plugin's data directory (.../plugin-config-data/signalk-espos-stream/chromium-profile), so a login performed in the kiosk (e.g. Freeboard credentials) survives container recreation.

Local image build (development)

The released image lives at ghcr.io/dirkwa/signalk-espos-stream and is published by CI on release tags. For development on the server itself:

npm run build-image   # tags ghcr.io/dirkwa/signalk-espos-stream:dev and :<version>

Set the plugin's Image tag to dev (or leave auto, which matches the version tag the script also applies).

Security notes

  • The stream and touch ports have no authentication; the touch injector is gated to the connected stream client's source IP, and the stream serves one client at a time. Only expose these ports on trusted (boat) networks.
  • Chromium runs --no-sandbox inside the container (required for kiosk use in a container); the container itself is the sandbox boundary.

License

Source-available, no redistribution — see LICENSE.md.