A Linux client for the Helm feature of Garmin ActiveCaptain — live-view and control your Garmin chartplotter's screen from a Linux laptop over Wi‑Fi, without the phone app.
Reverse-engineered from the ActiveCaptain app and verified against a GPSMAP 923xsv. See PROTOCOL.md for the wire protocol.
Not affiliated with or endorsed by Garmin. For use with your own hardware on your own network.
- Discovery of the plotter over mDNS.
- Pairing — registers this machine as an ActiveCaptain user on the plotter.
- Live video — the chartplotter screen as RTSP/H.264.
- Touch control — click = tap, click‑and‑drag = pan, over the real session protocol (verified byte-for-byte against a capture).
Hardware keys (zoom/menu buttons) aren't implemented — a touchscreen unit is fully controllable by touch; see PROTOCOL.md for how to add them.
- Python 3.10+ (standard library only — no pip packages required)
- mpv (recommended; required for the GUI's touch input).
ffplayorvlcalso work for view-only. - Optionally
zeroconffor more robust discovery on busy networks.
Join the chartplotter's Wi‑Fi network, then:
# 1. one-time: register this machine with the plotter
python3 helm-cli.py pair
# -> the plotter shows "a new ActiveCaptain user was added"
# On the plotter, set App permissions to "View and Control"
# (Settings -> Communications -> Wi-Fi Network -> Wi-Fi Devices)
# 2. live screen + touch control
python3 helm-gui.py
# Auto-discovers and connects on launch (remembers the last plotter; shows a
# picker if several are found). A control panel opens plus an mpv video window.
# Interact with the VIDEO window:
# click = tap
# click-and-drag = pan
# scroll wheel = zoom in / out (two-finger pinch)Headless / view-only:
python3 helm-cli.py discover # find the plotter
python3 helm-cli.py helm # open the session and play the video
python3 helm-cli.py helm --no-video # session only (prints status/stream URL)| Command | Description |
|---|---|
helm-cli.py discover [--all] |
find Helm devices (or all Garmin services) |
helm-cli.py pair [--role guest|owner] [--reset] |
register this machine |
helm-cli.py helm [--host IP] [--tap X Y] |
open session + play video |
helm-cli.py view <url> |
play any RTSP/MJPEG stream |
helm-cli.py analyze <pcap> |
decode a captured Helm session |
helm-gui.py |
GUI: video window + touch control |
mDNS discover ─▶ pair (HTTP :80, bl-id register) ─▶ Helm session (TCP :51200)
├─ handshake + touch input
└─ RTSP URL ─▶ video (:554)
helm/discovery.py— mDNS browserhelm/credential.py— pairing (bl-id registration)helm/helm_client.py— the:51200session: framing, handshake, touchhelm/video.py+helm/mpv_input.lua— RTSP playback and the mpv→touch bridgehelm/analyze.py— decode a session pcap (for extending the protocol)helm/inputtest.py— test the mouse→touch bridge without a plotterhelm/keys.py— reverse-engineered key enum (reference; not wired up)
- Touch input in the GUI is bridged from the mpv window over its IPC socket, so
it works on Wayland and X11 without embedding. mpv runs with
--window-dragging=noso click‑drag pans instead of moving the window. - The plotter's RTSP server is UDP-only; the players are configured accordingly.
- If the video player crashes (corrupt frames, decoder hiccups), it is relaunched automatically — the Helm session and touch control keep running across the restart. Closing the video window on purpose (clean quit) stops it.
MIT — see LICENSE.