signalk-pypilot-newui
v2.5.1
Published
Signal K friendly UI for the pypilot autopilot, with the capability to spread its functions and buttons to other programs like KIP, WilhelmSK and freeboard. Touch-first mobile visor + full pypilot data (servo, gains, calibration, tack, warnings) as first-
Downloads
2,399
Maintainers
Readme
signalk-pypilot-newui
⚠️ 2.5.0 ships new features that have not been tested at sea yet
The day we cut this release there was not enough wind to validate the tack countdown, the post-tack stats, the tack log, the gust marker, or the "auto brain" that switches profiles and reacts to gusts for you. Your feedback is GOLD: install it, try it, and if anything looks off, tell us at https://github.com/Aitonos/signalk-pypilot-newui/issues That is how we tune the thresholds before we sign these features off as stable.
⚠️ 2.5.0 trae funciones que aun no hemos probado en el mar
El dia de sacarla no habia viento suficiente para validar el contador de virada, el resumen post-virada, el historial de bordos, la marca de rafagas ni el "cerebro auto" que gestiona perfiles y rafagas por ti. Nos vale ORO tu feedback: instalala, usala y si algo va raro cuentanoslo en https://github.com/Aitonos/signalk-pypilot-newui/issues Con eso tuneamos los limites antes de dar todo por bueno.
PyPilot New-UI + SK Paths — a modern, touch-first control panel for the open-source pypilot autopilot, plus every pypilot value exposed as a first-class Signal K path so tools like KIP, WilhelmSK and freeboard can build custom gauges and switches out of the box.
Runs alongside pypilot-autopilot-provider
by Panaaj — see Working alongside pypilot-autopilot-provider.
Screenshots
| Control | Chart |
|---|---|
|
|
|
| Tune | Setup |
|---|---|
|
|
|
| Race | Info |
|---|---|
|
|
|
What's new in 2.4.0
Feature release. The plugin has learnt to behave itself around the Pi
Zero and now speaks the sailor's language instead of pilot-programmer
jargon. The rework was driven by direct feedback from Sean D'Epagnier
(pypilot author) on how his pypilot_web handles a firehose of
subscriptions, and by field observations from Carlos on Tunatunes.
- Dynamic watch focus (per Sean D'Epagnier's advice) — before, the
plugin permanently subscribed ~170 pypilot values, which pressured
pypilot_webon the Pi Zero W and eventually locked its socket buffer. Now the backend keeps a minimal always-on "core" set (~15 paths) and accepts short-livedfocusrequests from the visor: the Tune tab bumps its gain paths to 2 Hz only while it is on screen, same for the Calibration sliders in Setup. When the tab closes the TTL expires and the rate drops back. New endpoints/watch/focus,/watch/releaseand/watch/status, a live inspector in Setup → Remote Control Console, plus aRestart pypilot_webbutton that runssv restart pypilot_webvia SSH. - Navigation session recorder + shared-advice loop — every engaged
AP session is now saved as JSONL to
~/.signalk/plugin-config-data/signalk-pypilot-newui/nav-sessions/. Users label conditions (wind, sea state, propulsion, point of sail, crew) from a modal in Setup → Doctor, share the file via WhatsApp or email, receive an "advice" JSON back and upload it to the visor, where it renders as "Consejos recibidos". First step towards an AI-tuned Doctor: the plugin does not run any AI at runtime - all the learning happens off-boat and gets injected into future Revs as plain heuristics. - Pi Zero log capture — piCore keeps
/var/login tmpfs, so a hang wipes the logs the moment the user hits the hard reset relay. A new opt-in poller SSHes into the Pi Zero on a configurable cadence, tails/var/log/pypilot/*and appends the new lines to a persistent daily file on the Pi 5. Toggle + downloader live in the Remote Control Console. - Plain-language help for every gain — every P / I / D / DD / PR
/ FF slider in Tune and every documented RangeSetting slider in
Setup → Calibration now carries a short "what it does" line plus a
?button that expands into "when to raise, when to lower". EN / ES / DE / FR. Directly inspired by Sean's own suggestion in the pypilot forum. - Alarm engine and Doctor speak the user's language — the seven
built-in alarm rules and the Doctor findings + summary now render
in the active language (EN / ES / DE / FR); the backend still ships
English strings on
notifications.autopilot.*for KIP / WilhelmSK compatibility. - Mode selector proper i18n and uppercase tabs — pypilot mode
strings (
compass,wind,true wind,nav) plus the plugin's ownaproadopseudo-mode all render as translated UPPERCASE labels ("COMPAS", "VIENTO APARENTE", "APROADO", ...). Sailing tab labels are UPPERCASE too so accents remain optional per RAE convention. - Doctor UX polish — every suggestion carries a Hide/Discard button that stays visible even after the suggestion has been applied, so stale advice never sticks in the list; the Setup tile chip mirrors the visible count.
- Setup launcher — live status chips on every tile — pypilot host+port, active language, last calibration adjustment timestamp (with a Reset button), count of active SK sentences vs the total catalogue (all 181 keys), and an SSH-configured pill on Remote Control Console. Sensor Quality gains a per-row Ignore / Restore button so a rudder feedback that does not exist on this boat stops turning the chip red.
- Chart tab — hover freeze + per-band Y-axis — touch or hover over the timeline to freeze the auto-refresh and read the exact value at that point for every band. Min / mid / max ticks appear inside the right gutter of each band.
- Tune — per-slider ↺ restore and profile-fork prompt — every
gain gets a ↺ that snaps back to the frozen "was:" baseline. The
first change per unlock triggers a Doctor-style modal to keep the
tweaks in the current profile, save them in a new
tune-YYYYMMDD-HHMMfork, or Cancel and revert. - Nav bar slide-down gesture — swipe from the top of the visor to bring the tab bar back (counterpart to the existing slide-up hide).
What's new in 2.3.0
Feature batch on top of 2.2.x:
- Chart tab — interactive hover — freeze the auto-refresh and read the exact value of every band at any point in the history window by hovering the graph. Y-axis ticks (min / mid / max) now sit inside the right gutter for each band.
- Tune tab — per-slider restore + profile fork prompt — every
gain slider gets a ↺ button that snaps back to the frozen
baseline captured when you unlocked the panel. On the first
change of an unlock session a modal asks whether to keep the
tweaks in the current profile, save them in a new
tune-YYYYMMDD-HHMMfork (mirroring the Doctor pattern), or Cancel and revert. - Setup launcher — live status chips on every tile — Pypilot
Connection shows
host:port, Language shows the active locale, Calibration shows the timestamp of the last slider adjustment (with aReset historialbutton on the card), Signal K Sentences shows the count of published SK paths, and Remote Control Console says whether SSH creds are stored. Sensor Quality now counts missing sensors into the failure tally and each row gains an Ignore / Restore button so a sensor you don't have on this boat (rudder without a rudder feedback, temp probe absent, ...) stops turning the chip red. - Nav bar slide-down gesture — the counterpart to the existing slide-up hide; drag from the top of the visor to bring the tab bar back.
- Doctor tab — Hide / Discard on every suggestion — the
Descartar / Ocultar button stays visible even after a suggestion
has been applied so you can clear stale advice from the list.
Hidden suggestions also drop off the tile chip's counter so the
card goes back to
sanoonce you've cleared everything. Backend now emits i18n keys + args for findings and summary so the whole Doctor panel reads in the active language. - Alarm engine i18n — the seven built-in alarm rules
(heading-deviation, unable-to-steer, servo-overcurrent, etc.) now
render banners and speak the message in the active language
(EN / ES / DE / FR). The backend still publishes the English
notification message on
notifications.autopilot.*for KIP / WilhelmSK compatibility. - Better DE / FR coverage — Setup tile titles, calibration strings, Tune fork modal and Info tab now translate in Deutsch and Français instead of falling back to English.
- Remote Control Console defaults — the tile no longer wears
its emergency red frame; the SSH user field is pre-filled with
the TinyPilot default (
tc) and a hint spells out that the default password istctoo, so the setup is a two-click job on a stock TinyPilot.
What's new in 2.2.0
2.2.0 turns the plugin into an intelligence layer over pypilot. Forty in-session Revs on top of the 2.1.0 visual foundation. Highlights:
- Aproado pseudo-mode — a new "raise the sails" AP mode not in
pypilot upstream. Pick BY BOW / BY STERN via a 5 s modal, the
plugin switches pypilot to wind mode with target 0° (head to
wind), and a floating HUD over the boat shows elapsed time,
straight-line distance from the start and the compass heading
captured at activation. SALIR restores the previous mode + target
- engaged state. BY STERN forces a stern-through swing by walking a chain of intermediate targets 60° apart so pypilot cannot shortcut through the bow.
- Telemetry historian + Chart tab — RAM ring buffer at 1 Hz for the last 30 min (backend, Pi 5 friendly). Nine Trip Stats cards (AP engaged time, distance, energy, mean / RMS / p95 heading error, servo runtime, tacks / gybes, peak servo A) fed live via SK paths, plus a canvas with 30 s / 2 min / 10 min windows.
- Sensor Quality + Servo Health + Alarm engine + Pre-departure
check — new backend modules that grade every SK path the AP
depends on, learn a baseline servo current and flag anomalies,
evaluate seven alarm rules that publish canonical
notifications.autopilot.*, and roll everything into a single READY / READY-WITH-CAVEATS / DO-NOT-ENGAGE verdict. - Pypilot Doctor — press DIAGNOSE, the plugin records 2-3 min
with the AP engaged, runs heuristic rules on the heading error
stream (bias / oscillation / low authority) and proposes P / I /
D adjustments with a plain explanation. Nothing is applied
automatically. The first Apply of a session forks the current
pypilot profile into a new
doctor-YYYYMMDD-HHMMprofile so the previous gains stay one profile-select away. - Setup as a launcher grid — every setup block is now a square tile in a 2 / 3 / 4-column grid. Tap opens fullscreen with a small X to close and ESC support. Live summary pill on every tile. Connection consolidated (status + LAN scan + manual host + Autopilot Provider in one card). "Emergency" renamed to "Remote Control Console".
- Interactive SSH console — free-form command input with on-screen arrow buttons for mobile history navigation, accumulative output textarea, clipboard fallback for HTTP LAN, and 14 preset buttons with plain human labels (Memory / IP table / WiFi / Temperature / Who is connected / ...). BusyBox / piCore-safe fallbacks for every command.
- Full RangeSetting sliders in Calibration — every pypilot
RangeSettinggrouped by category (rudder / servo / imu / ap / other) with the same look as the Tune tab, a lock checkbox with the padlock emoji, a frozen "before:" baseline that never moves as you drag, and a per-slider ↺ restore button. - Gota Chain shape swap — after iterations with skippers using the plugin: the AMBER "A" arrow (apparent wind) is now the LARGE piece and the TEAL "T" arrow (true wind) the SMALL outer one. Colors and letters kept their canonical meaning; only the SVG paths moved so the amber piece is visually the dominant one.
- Full i18n audit across EN / ES / FR / DE — every hard-coded English string in the non-EN bundles purged, alarm messages and Doctor suggestion reason / effect exposed as i18n keys + args so the frontend renders in the user's language.
See CHANGELOG.md for the full detailed list in
four languages.
Upgrading from 1.0.0 to 2.0.0
2.0.0 is a breaking release addressing feedback from Sean D'Epagnier
(pypilot author). Every pypilot key now maps 1:1 to
steering.autopilot.pypilot.<key> verbatim - no more hand-picked renames
or C -> K / deg -> rad conversions. If you have KIP widgets or WilhelmSK
dashboards wired to 1.0.0 paths, see the full migration table in
CHANGELOG.md - most notable examples:
.servo.controllerTemperature(K) ->.servo.controller_temp(C).calibration.rudderRange(rad) ->.rudder.range(deg).gains.<pilot>.<gain>->.ap.pilot.<pilot>.<gain>
Setup -> Emergency ships two remote restart buttons (RESTART pypilot
and reboot Pi), both guarded by a helm-manned confirmation modal.
restart pypilot_web (the safe web-only restart that does not interrupt
steering) lives as a preset in the Debug console — an SSH-based
whitelist of preset diagnostic commands (logs, dmesg, top, uptime, df,
pypilot version, restart pypilot_web).
What it does
Touch webapp (mobile / tablet / chart-plotter, dark theme):
- Compass rose with HDG readout, colour-coded cardinals (N orange, E green, S blue, W red) + degree ticks, hull-fixed green/red sailing wedges, and 4 configurable corner tiles (long-press to reconfigure).
- Gota Chain overlay: three concentric arrow pieces on the rose — cyan
target diamond, amber
A(AWA), sea-greenT(TWA). Interlock into one clean droplet when all three angles coincide; the V-hembra of any piece that drifts opens up as a visible hollow, and a colour ring-tick marks the exact angle on the compass. Optional COG line from the bow (yellow chevrons) and current vector (SOG − SOW, blue wavy arrow) can be toggled from a 4-card selector opened by long-press on any corner or on the boat sprite. - Big-touch AP engage / disengage with optimistic UI + auto-retry over flaky links (Tailscale-safe).
- Tack port / starboard, mode selector (compass / GPS / wind / true wind / nav), nudge ±1 / ±10 with configurable step size, current heading snap on engage.
- Tune tab with locked-by-default gain sliders (auto-relock on tab exit), ±10 / ±1 buttons flanking each slider, orange "previous value" reference.
- Race timer T1/T2 with beeps, screen flash, spoken seconds countdown ("10, 5, 4, 3, 2, 1, Start"). Runs in the background across tabs.
- Setup with LAN scan, manual host+port, KIP absorb-provider toggle,
SSH-based remote
RESTART pypilotbutton (credentials stored in plugin config), nudge step size, language, IMU / rudder calibration. - Paths & API tab with live catalog of published paths, per-path publish toggles, KIP copy-to-clipboard helpers.
- Info tab with quick-start, coexistence rules, credits, license, GitHub
link, config export / import (Web Share API → email / WhatsApp / Signal /
AirDrop,
.jsondownload, clipboard). - Full i18n: English / Español / Deutsch / Français (auto-detected from browser, override in Setup → Language).
- Regatta-safe swipe navigation between tabs with vertical-axis-lock so scrolling never triggers a stray tab flip.
- Signal K polar-performance and any custom SK path bindable to a corner tile.
~60 Signal K paths under steering.autopilot.pypilot.* (opt-in per path):
- Gains per pilot (
P,I,D,DD,PR,FF). - Servo telemetry (voltage, current, controller / motor temperatures, flags, amp-hours, clutch engaged, controller error).
- Rudder calibration (offset, scale, non-linearity, range, calibration state).
- IMU heading offset, errors, warnings.
- Active pilot, active profile, available pilots / profiles / modes.
- Tack state, tack direction, tack timeout.
- Runtime, version.
KIP-ready Simple Switches under electrical.switches.pypilot.*:
ap.state— momentary boolean, engage / disengage.nudge.{bigPort,smallPort,smallStar,bigStar}— momentary, auto-reset.tack.{port,starboard,cancel}— momentary.mode.{compass,gps,wind,trueWind,nav}— radio (mutually exclusive).profile.<name>— radio, dynamic per pilot profile.
Installation
- Signal K Server → App Store → search PyPilot New-UI.
- Server → Plugin Config → PyPilot New-UI + SK Paths.
- Enter the
pypilot_webhost (IP or hostname) and port. On TinyPilot the default is port80; on a classic pypilot install it is8000. - The Scan LAN button in the webapp auto-detects hosts running
pypilot_webon ports 80 / 8000 of your subnet if you don't know the IP. - Enable the plugin.
Webapp URL: http://<sk-host>:3000/signalk-pypilot-newui/
Working alongside pypilot-autopilot-provider
We build on top of the excellent
pypilot-autopilot-provider
by Panaaj — the plugin that gives Signal K the standard
Autopilot API v2 surface (/signalk/v2/api/vessels/self/autopilots/*) so
WilhelmSK, freeboard and other clients can drive pypilot through the canonical
interface. Panaaj focuses tightly on that API and opens its own socket.io
connection to pypilot_web.
This plugin adds ~60 additional pypilot values on top (gains, servo telemetry,
calibration, warnings, profiles, tack detail, etc.), ships the touch webapp,
and can optionally register the Autopilot API v2 itself via the
absorbProvider option in Setup, so a single socket hits pypilot_web
instead of two — useful when pypilot runs on a Pi Zero W.
Signal K only allows one provider per pilot ID, so if you turn on absorbProvider here you should disable Panaaj's plugin (otherwise both register the same ID and behaviour is undefined). Valid setups:
| Panaaj pypilot-autopilot-provider | signalk-pypilot-newui absorb | Result |
|---|---|---|
| Enabled | Off (default) | Both run happily side by side. Panaaj owns the AP v2 API; this plugin adds the extra paths + UI. 2 sockets to pypilot_web. |
| Disabled | On | Only this plugin. Same AP v2 API + all the extras. 1 socket. Handy on Pi Zero W. |
| Enabled | On | Both try to register the same AP ID — leave one off. |
| Disabled | Off | WilhelmSK / freeboard / KIP won't see the AP. Only useful if you exclusively use this plugin's own webapp. |
Absorb mode lives in Setup → Autopilot Provider (one-socket mode).
Remote restart / reboot + Debug console
When the autopilot process on the TinyPilot gets wedged you don't need to open an SSH session by hand. In Setup → Emergency, save the TinyPilot's SSH user + password once. From then on you get two big restart buttons, each guarded by a helm-manned confirmation modal that asks whether someone is at the helm before executing:
- RESTART pypilot (~10-15 s) —
sv restartof the pypilot core + web (runit under piCore). The AP drops the heading briefly and re-engages when it comes back up. - reboot Pi (~35-60 s) — full
sudo rebootof the Raspberry Pi. No autopilot for almost a minute. Last-resort when the box is in a bad state.
The safe restart pypilot_web (web server only, does not interrupt
steering) lives as a preset button in the Debug console below,
alongside a closed whitelist of preset diagnostic commands over the same
SSH session: logs pypilot, logs pypilot_web, dmesg, top, uptime,
df, pypilot --version. Output goes into a scrollable textarea, a
"Follow logs" toggle polls journalctl --since '30 s ago' every 3
seconds, and Copy / Share buttons let you paste the dump straight into a
GitHub issue or a WhatsApp / email conversation with your friendly rigger.
The endpoint (POST /plugins/*/debug-cmd) refuses any command that is
not in the whitelist, so a leaked JWT cannot be used to run arbitrary
shell on the TinyPilot.
Signal K stores plugin configs in plain text under
~/.signalk/plugin-config-data/ so use credentials that are only valid for
that isolated TinyPilot.
HTTP endpoints (plugin router)
| Method | Path | Purpose |
|---|---|---|
| GET | /plugins/signalk-pypilot-newui/status | Connection + last-seen catalog summary + Rev + version + historian header + KPI computedTs |
| GET | /plugins/signalk-pypilot-newui/scan | Scan LAN for pypilot_web hosts |
| GET | /plugins/signalk-pypilot-newui/paths | Live list of published SK paths with GET / PUT URLs and units |
| GET | /plugins/signalk-pypilot-newui/catalog | Raw pypilot catalog (all values + metadata) |
| GET | /plugins/signalk-pypilot-newui/values | Current pypilot value cache |
| PUT | /plugins/signalk-pypilot-newui/raw | Send raw name=value to pypilot (protected by allowWrites) |
| GET | /plugins/signalk-pypilot-newui/history | Historian slice. Query ?window=30s\|2m\|10m and ?paths=headingCmd,rudder,.... RAM ring buffer at 1 Hz. |
| GET | /plugins/signalk-pypilot-newui/stats | KPI snapshot: session (engaged time, distance, energy, tacks, gybes, max servo A) + window1m (mean / RMS / p95 heading error, servo duty). |
| POST | /plugins/signalk-pypilot-newui/session/reset | Reset the KPI session counters. History buffer is kept. |
| GET | /plugins/signalk-pypilot-newui/quality | Sensor Quality snapshot: age / observed Hz / jitter / source / status per watched SK path. |
| GET | /plugins/signalk-pypilot-newui/servo-health | Servo Health snapshot: learned baseline current, deviation ratio, peak A, samples in the learn window. |
| GET | /plugins/signalk-pypilot-newui/alarms/state | Active alarms + short resolved history. |
| GET | /plugins/signalk-pypilot-newui/alarms/rules | Rule metadata (id / label / severity / enabled / muted / active). |
| POST | /plugins/signalk-pypilot-newui/alarms/ack/:id | Acknowledge one active alarm (silences the sound, banner stays visible). |
| POST | /plugins/signalk-pypilot-newui/alarms/mute/:id | Mute the RULE for N minutes (query ?min=15). |
| POST | /plugins/signalk-pypilot-newui/alarms/enable/:id | Enable / disable a rule (query ?on=1\|0). |
| GET | /plugins/signalk-pypilot-newui/prechecks | Pre-departure autopilot check verdict: ready / ready-with-caveats / do-not-engage + per-item detail. |
| POST | /plugins/signalk-pypilot-newui/doctor/start | Start a diagnostic session (query ?duration=180). Requires AP engaged. |
| POST | /plugins/signalk-pypilot-newui/doctor/cancel | Cancel the current session. |
| GET | /plugins/signalk-pypilot-newui/doctor/status | Session state + progress + result (when completed). |
| POST | /plugins/signalk-pypilot-newui/doctor/apply/:id | Apply one gain suggestion. The FIRST apply of the session forks the profile into doctor-YYYYMMDD-HHMM. |
| POST | /plugins/signalk-pypilot-newui/doctor/apply-all | Apply every non-dismissed suggestion (all land in the same forked profile). |
| POST | /plugins/signalk-pypilot-newui/doctor/dismiss/:id | Mark a suggestion as dismissed (user rejects it). |
| POST | /plugins/signalk-pypilot-newui/doctor/reset | Clear result, back to idle. |
| POST | /plugins/signalk-pypilot-newui/restart-pypilot | SSH sv restart of pypilot core+web on the TinyPilot. |
| POST | /plugins/signalk-pypilot-newui/debug-cmd | Run one of a closed whitelist of preset diagnostic / restart commands over SSH. Body: { "preset": "<name>" }. |
| POST | /plugins/signalk-pypilot-newui/ssh-exec | Free-form SSH command (Remote Control Console). Body: { "cmd": "<any shell>" }. Requires allowWrites. |
| POST | /plugins/signalk-pypilot-newui/pause | Disconnect local socket (for scripts). |
| POST | /plugins/signalk-pypilot-newui/resume | Reconnect local socket (for scripts). |
Safety
allowDirectServodefaults to off — the directservo.commandback-door used by pypilot's own UI for manual steering is not exposed until you enable it explicitly in the plugin config.- All PUT handlers validate ranges from the pypilot catalog before sending.
- On plugin stop the socket closes cleanly; the visor auto-reconnects on Signal K restart.
- This plugin is an aid to navigation and steering. It does not replace the vigilance of the skipper, correct manoeuvring, direct observation of the surroundings, or official charts and notices. Verify in safe waters before relying on the autopilot for demanding manoeuvres.
Acknowledgements
- Sean D'Epagnier — creator of pypilot, the open-source autopilot that makes this plugin possible.
- Jean-Marc at Navitop — for the TinyPilot hardware and marine integrations, and for making pypilot accessible to European sailors.
- The Signal K community and OpenPlotter for the open ecosystem this plugin runs on.
- Panaaj — for
pypilot-autopilot-provider, the reference AP v2 provider this plugin builds on top of.
Reporting issues / feature requests
Open an issue on GitHub —
github.com/Aitonos/signalk-pypilot-newui/issues.
Include the Rev (visible in the app under Info → top header, or via
GET /plugins/signalk-pypilot-newui/status), what you expected, what happened,
and a screenshot if possible.
Development
git clone https://github.com/Aitonos/signalk-pypilot-newui
cd signalk-pypilot-newui
npm install
npm run buildDeploy from a Windows laptop to a Raspberry Pi: .\deploy.ps1 -Restart.
License
Apache-2.0, Aitonos. See NOTICE for third-party attributions.
