signalk-pypilot-newui 2.12.0 → 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,235 @@
1
1
  # Changelog
2
2
 
3
+ ## 3.1.0 — 2026-10-10 — Fullscreen auto, configurable bottom chip, heading precision, AIS polish
4
+
5
+ Rolls up Rev439 → Rev449 (11 revs) on top of 3.0.0. Minor bump: a
6
+ family of UX refinements + a couple of safety-oriented fixes;
7
+ backward-compatible with 3.0.0 plugin config and SK paths. The theme
8
+ of the release is **"glance information at a distance"** — the sailor
9
+ mounts the tablet across the cockpit and reads the visor as a true
10
+ instrument, so chip sizes, legibility, precision indicators, and
11
+ fullscreen-by-default all got tightened in this bump.
12
+
13
+ ### Added
14
+
15
+ - **Fullscreen + Screen Wake Lock auto-on by default** (Rev446/Rev448).
16
+ On the very first user tap, the visor requests browser fullscreen
17
+ on `<html>` and takes a `navigator.wakeLock("screen")` so the
18
+ display never dims nor locks — same UX as YouTube's player. A
19
+ floating ⛶ button top-right toggles both and persists the sailor's
20
+ choice (`localStorage[pypilot-newui.fullscreenAuto]`), so later
21
+ reloads honour "I opted out".
22
+ - **Configurable bottom chip on the rose — up to 4 datapoints
23
+ cycled** (Rev439 → Rev445). Short-tap on the chip under the compass
24
+ cycles through the user-picked set (default: SOG → Depth → %Polar);
25
+ long-press opens a modal where the sailor picks up to 4 datapoints
26
+ from the same catalog as the four configurable corners (base paths +
27
+ performance extras + any custom SK path registered in a corner).
28
+ Persisted in `localStorage[pypilot-newui.roseBottomChipPaths]`.
29
+ Replaces the old "always AWS/TWS mirror" behaviour.
30
+ - **Heading-precision gauge under the compass readout** (Rev443/Rev444).
31
+ Second line inside the `#rose-hdg-chip` shows how far off the pilot
32
+ still is from its own target — the sailor's "glance accuracy
33
+ reading", not the target value itself. Signed `target - current`:
34
+ negative = pilot must correct to port (babor), positive = to
35
+ starboard (estribor). Colour: `|err|<3°` green, `<10°` orange, else
36
+ red. In compass / gps / nav uses heading − target; in wind / aproado
37
+ uses AWA − target; in true wind / empopado uses TWA − target.
38
+ Shows `--` when the AP is OFF (`state.engaged === false`) so a
39
+ stale `state.target` can never mislead the sailor.
40
+ - **Safe-exit to compass after APROADO / EMPOPADO** (Rev440). When
41
+ the user finishes an aproado or empopado without opting in to full
42
+ `restoreAll`, the visor now auto-switches the pilot back to COMPASS
43
+ with the current heading as target. Rationale: leaving the pilot in
44
+ WIND / TRUE WIND after the manoeuvre is less stable for "hold what
45
+ I have now" than COMPASS. Carlos sea-trial 2026-10-10. Falls back
46
+ to no-op if the heading sensor is absent.
47
+ - **AIS target as a tinted top-view hull sprite** (Rev442 → Rev443,
48
+ Rev447 → Rev449). Replaces the plain red triangle with the
49
+ `boat-cenital.svg` sprite (same asset as the own-vessel sprite in
50
+ the rose centre), tinted via SVG `feColorMatrix` filters per state:
51
+ red (alarm, blinking, 150 % scale) · orange (warn, fixed, 100 %) ·
52
+ blue-grey (acked, no blink, 100 %). Bow always points toward the
53
+ self vessel (rotation now `rotate(relDeg + 90)` to match the
54
+ horizontal asset). Alarm sprite blinks; acked stays fully visible
55
+ but muted. Paints as the LAST element inside the rose SVG so it
56
+ stays on top of wind arrows, sectors and HUDs.
57
+ - **Only the 3 most urgent AIS targets painted** (Rev441). When more
58
+ than 3 collision alarms are active, only the 3 lowest-TCPA ones
59
+ render on the rose. The infobox navigator still walks ALL alarms so
60
+ the sailor can scroll through the hidden ones.
61
+ - **Tap on an AIS target opens its data popup** (Rev441). Click
62
+ delegation on `#ais-alarm-layer`: tapping a hull sets
63
+ `_aisInfoboxIdx` to that MMSI and forces the popup open — works for
64
+ both pending and silenced targets. Auto-resets to the newest threat
65
+ after 20 s if no further interaction.
66
+ - **ACK keeps the AIS target arrow on the rose** (Rev441 → Rev442).
67
+ ACK no longer deletes the MMSI from `state.aisAlarms`; the hull
68
+ stays visible (silenced style) until the plugin declares the
69
+ threat gone. Button toggles ACK ↔ ACKED (ES: SILENCIAR ↔
70
+ SILENCIADO), with `disabled` + `.is-acked` styling when the MMSI is
71
+ already acknowledged.
72
+ - **X close button on the AIS infobox** (Rev442). When the sailor
73
+ opened the popup by tapping a hull, the X dismisses it and clears
74
+ the user-pick flag so new threats can take over.
75
+ - **Long "Viento Aparente" / "Viento Real" labels in the mode-selector
76
+ modal** (Rev441). The modal shows the long names so wind modes are
77
+ explicit on first open; the bbar button keeps the short labels
78
+ (APARENTE / REAL) to fit the narrow chip.
79
+ - **Landscape tabbar made compact** (Rev446). `.tab-btn` padding
80
+ `12→4 px`, font-size `14→12 px` inside
81
+ `@media (orientation: landscape)`. Saves ~20 vertical pixels for
82
+ tablets mounted horizontally.
83
+
84
+ ### Changed
85
+
86
+ - **Heading chip grows UPWARD** (Rev444). The chip rect height
87
+ expands toward `-y` (bottom edge still at `-84`), so the new
88
+ precision line never covers the target diamond that sits just
89
+ below the top of the compass ring.
90
+ - **AWS / TWS sub-line font-size bumped three steps** (Rev443 →
91
+ Rev445). From `clamp(11, 2vw, 16px)` to `clamp(20, 3.8vw, 32px)`
92
+ so the kn number sits halfway between the dim corner label and
93
+ the big angle value when read from the helm.
94
+ - **AIS voice is a short safety nudge, not a report** (Rev441,
95
+ Rev449). The voice line used to spell CPA / TCPA / MMSI, which TTS
96
+ mangled on long numbers. Now it just says *"Alarma AIS, target en
97
+ rumbo de colisión"* / *"AIS alarm, target on collision course"*;
98
+ the data stays visible in the infobox. ES says "AIS" as a word
99
+ (Rev449 — was "A I S" letter-by-letter).
100
+
101
+ ### Fixed
102
+
103
+ - **AIS target bearing was 180° off in some geometries** (Rev448 —
104
+ found during 2026-10-10 sea trial). `renderAisAlarms` checked
105
+ `state.position.latitude` but `state.position` carries short keys
106
+ `{lat, lon}` — the test always failed and the code fell back to
107
+ `cpaPositions.self` (= *projected* self position at CPA future
108
+ time). Bearing was then computed between two **future** positions,
109
+ which can be nowhere near the current geometry. The adapter now
110
+ converts `{lat, lon}` → `{latitude, longitude}` once at render
111
+ time, so the hull always paints at the real bearing to the target
112
+ as-of-now.
113
+ - **Signal K server token kept being asked "every once in a while"**
114
+ (Rev446). `handleAuthWrite` wiped the permanent device token on
115
+ the FIRST `401` and kicked off an access-request modal — a single
116
+ transient 401 (SK restart in flight, proxy hiccup, DNS blip) was
117
+ enough to invalidate a perfectly good token. Now requires THREE
118
+ consecutive 401 writes before wiping; one successful write resets
119
+ the counter.
120
+ - **Precision gauge sign convention** (Rev444). First pass used
121
+ `heading − target`; Carlos's convention is "the correction the
122
+ pilot still has to apply" → `target − heading`. Negative therefore
123
+ means *pilot must go to port* and positive *pilot must go to
124
+ starboard*.
125
+
126
+ ## 3.0.0 — 2026-10-10 — AIS collision overlay + Freeboard-SK embedded
127
+
128
+ Rolls up Rev431 through Rev438 (8 revs). The headline feature of 3.0.0
129
+ is an AIS collision overlay on the compass rose and a Freeboard-SK
130
+ chart embedded in the rose box on double-tap. Pypilot-newui is a pure
131
+ CONSUMER of the external
132
+ [`signalk-collision-alerts`](https://github.com/dirkwa/signalk-collision-alerts)
133
+ plugin (by @dirkwa, the maintainer of @signalk/app-dock and
134
+ server-admin-ui) and of the Signal K v2 Notifications API — no
135
+ CPA/TCPA engine lives here. The decision rationale is captured in the
136
+ new memory `feedback_signalk_ecosystem_first.md`: Signal K is a
137
+ cooperative ecosystem; reinventing a well-maintained plugin is
138
+ anti-pattern. See `docs/_feature_ais_overlay.md` for the full
139
+ operator guide + install.
140
+
141
+ Carlos classified this bump as **major (3.0.0)** at the start of the
142
+ sprint: it adds a new optional external-plugin dependency, changes
143
+ double-tap-on-rose behaviour (was no-op; now opens Freeboard) and
144
+ introduces a user-facing concept — AIS alarms with ACK — that was
145
+ not present in the 2.x line.
146
+
147
+ ### Added
148
+
149
+ - **AIS collision overlay (Rev431 → Rev438)**. Subscribes to
150
+ `notifications.navigation.closestApproach.<mmsi>` emitted by
151
+ `signalk-collision-alerts`. For each active `warn` / `alarm`:
152
+ - **Red / orange triangle** painted on the compass circle at the
153
+ bearing from the self vessel to the target *as of now* (not the
154
+ CPA future projection — Rev436 fetches the target's current
155
+ position + SOG via `/signalk/v1/api/vessels/<ctx>/...` on each
156
+ delta with a 30 s cache).
157
+ - **Infobox** on top of the self boat with level badge
158
+ (`ALARM` / `WARN`), target name (or "objetivo" when the target
159
+ has no name yet — MMSI never shown or spoken), CPA · TCPA,
160
+ closing speed, ACK button, and when > 1 target is active a
161
+ `N/M` navigator with `‹` / `›`.
162
+ - **Voice**: short Spanish sentence built from the raw data, not
163
+ the plugin's English string (which TTS garbled into "ce-pe-a cero
164
+ coma cero cuatro ene eme"). Example: *"Alarma A I S, PIRATA DE
165
+ ONS, a 47 metros, ya"*.
166
+ - **ACK** button sends `POST /signalk/v2/api/notifications/<id>/acknowledge`
167
+ (so Freeboard + every SK consumer sees it) AND silences the MMSI
168
+ locally for 10 min — survives the plugin re-publishing the same
169
+ threat with a fresh UUID.
170
+ - **"Silenciadas…" modal** (Rev438) lists every locally-silenced
171
+ MMSI with remaining minutes + per-row *Reactivar* + bulk *Reactivar
172
+ todas*.
173
+ - **Stationary filter** (Rev436): targets whose cached SOG < 0.15 kn
174
+ are dropped from the UI even if the plugin keeps emitting the
175
+ alarm. Mandatory in a Ría with dozens of moored vessels.
176
+ - **Overlay-card in Setup → ROSE OVERLAYS**: master on/off, voice
177
+ sub-toggle, link to the plugin's config page, access to the
178
+ silenced modal.
179
+ - **Freeboard-SK embedded in the rose box** (Rev432 → Rev433). Double-
180
+ tap `#wind-rose` opens `/@signalk/freeboard-sk/` as an iframe
181
+ positioned inside the compass square so the side panels (mode,
182
+ nudges, AP) stay visible. Chrome row has ⤢ Maximize (full
183
+ viewport) / ⤡ Restore / × Close. Iframe `src` cleared on close so
184
+ Freeboard releases its websocket.
185
+
186
+ ### Changed
187
+
188
+ - No breaking API changes to the pypilot-newui plugin itself —
189
+ everything existing in 2.12.0 still works identically. The 3.0.0
190
+ bump reflects the new user-facing concepts (AIS alarms, Freeboard
191
+ entry point) and the optional external-plugin dependency.
192
+
193
+ ### Fixed
194
+
195
+ Bugs found and fixed during the AIS sprint, each informed by Carlos's
196
+ QA notes and the real SK bus on Tunatunes:
197
+ - **ACK button did not close the infobox** (Rev436). Was keyed by
198
+ notification UUID (Rev434); plugin cycles the id while the threat
199
+ persists → infobox resurrected on the next delta. Now keyed by
200
+ MMSI with a 10-minute TTL.
201
+ - **Triangle 180° off** (Rev436). Rev431 pointed at
202
+ `data.cpaPositions.target` which is the *projected* position at the
203
+ CPA future instant — hence "me avisa babor cuando el target me
204
+ viene por aleta estribor". Now uses the current self + target
205
+ positions fetched from the SK REST API.
206
+ - **Multiple alarms, including moored vessels** (Rev436). Added the
207
+ stationary SOG < 0.15 kn drop filter so a Ría with 30 moored boats
208
+ doesn't fire false alarms through the plugin's own thresholds.
209
+ - **TTS garble on Freeboard open** (Rev436). Removed the
210
+ `_alSpeak("abriendo carta")` that the English TTS read as "ICE
211
+ open chat".
212
+ - **Overlay-card nested checkbox hidden under the master** (Rev437).
213
+ CSS `.overlay-card input[type=checkbox]` matched every checkbox and
214
+ stacked them at top-right. Scoped to direct child so the AIS
215
+ card's "Voice alert" sub-toggle renders in-flow.
216
+
217
+ ### Known limitations / upstream work
218
+
219
+ - **Upstream `signalk-collision-alerts` issue #17** —
220
+ https://github.com/dirkwa/signalk-collision-alerts/issues/17 — the
221
+ admin UI does not render the `Alert sensitivity` / `Level`
222
+ dropdowns because the plugin's typebox schema emits `anyOf+const`
223
+ instead of `enum`. We filed the issue with a fix proposal; the
224
+ workaround is to hand-edit the plugin JSON config or patch the
225
+ built `config.js` locally. See `docs/_feature_ais_overlay.md`.
226
+ - **Needs sea-trial QA** on real moving traffic with mixed `warn` /
227
+ `alarm` targets. Default sensible config documented
228
+ (preset: `harbour`, `maxRange`: 3 NM) for a Ría-style navigation
229
+ env; switch to `coastal` / `offshore` as needed.
230
+
231
+ ---
232
+
3
233
  ## 2.12.0 — 2026-10-08 — Virtual-tack audit cycle + Profile UX overhaul + safety aproado/empopado
4
234
 
5
235
  Rolls up Rev410 through Rev430 (21 revs). Driven by two sea trials
package/README.md CHANGED
@@ -10,9 +10,36 @@ watches how your autopilot is behaving and quietly suggests how to
10
10
  sharpen its settings, so you spend more time sailing and less time
11
11
  guessing which slider to move.
12
12
 
13
+ Since **3.0.0** the visor also ships with an **integrated
14
+ chartplotter**: double-tap the compass rose and
15
+ [Freeboard-SK](https://www.npmjs.com/package/@signalk/freeboard-sk)
16
+ opens embedded inside the rose box with every AIS target, your route
17
+ and all overlays — side panels (mode, nudges, AP) stay reachable, no
18
+ tab switching, no re-authentication. **For charts to render you need a
19
+ Signal K chart provider installed and configured in Freeboard-SK**
20
+ (see [Chart provider is required](#chart-provider-is-required-for-the-embedded-plotter)
21
+ below).
22
+
13
23
  Runs alongside [`pypilot-autopilot-provider`](https://www.npmjs.com/package/pypilot-autopilot-provider)
14
24
  by Panaaj — see [Working alongside pypilot-autopilot-provider](#working-alongside-pypilot-autopilot-provider).
15
25
 
26
+ ## Chart provider is required for the embedded plotter
27
+
28
+ The chartplotter embedded in the rose uses Freeboard-SK, which itself
29
+ is only a renderer — it needs a Signal K **chart provider** plugin to
30
+ know where to fetch tiles from. Any of the standard providers works:
31
+
32
+ - **[`@signalk/charts-plugin`](https://www.npmjs.com/package/@signalk/charts-plugin)**
33
+ — serves local MBTiles / S57 / XYZ chart sets you drop into
34
+ `~/.signalk/charts/` (OpenCPN-style). Recommended default.
35
+ - **[`signalk-chart-tiler`](https://www.npmjs.com/package/signalk-chart-tiler)**
36
+ or any other upstream raster/vector provider.
37
+
38
+ Without a provider, Freeboard-SK will open embedded in the rose but
39
+ the map area will stay empty. Install one from the SK App Store, add
40
+ your chart sources, and the chartplotter inside pypilot-newui lights
41
+ up automatically.
42
+
16
43
  ## Screenshots
17
44
 
18
45
  ![Control - compass rose with concentric target + wind arrows](https://raw.githubusercontent.com/Aitonos/signalk-pypilot-newui/main/public/screenshots/01-control-rose.jpg)
@@ -235,6 +262,40 @@ pypilot version, restart pypilot_web).
235
262
 
236
263
  **Webapp URL**: `http://<sk-host>:3000/signalk-pypilot-newui/`
237
264
 
265
+ ## Works well with
266
+
267
+ Pypilot-newui is built as a well-behaved citizen of the Signal K
268
+ ecosystem — it consumes other mature plugins and standard APIs instead
269
+ of reinventing them. The sections below describe the plugins we
270
+ integrate with; none are hard dependencies (the autopilot visor works
271
+ on its own), but installing them unlocks the features listed.
272
+
273
+ - **[`@signalk/freeboard-sk`](https://www.npmjs.com/package/@signalk/freeboard-sk)**
274
+ — Double-tap the compass rose to open Freeboard-SK embedded inside
275
+ the rose box (side panels stay visible and usable). Lets you drop
276
+ from the autopilot view to the full chart with every AIS target in
277
+ one tap, without leaving the pypilot-newui session. **Pair with a
278
+ Signal K chart provider (e.g. `@signalk/charts-plugin`) or the chart
279
+ area will stay empty** — see
280
+ [Chart provider is required](#chart-provider-is-required-for-the-embedded-plotter).
281
+ See `docs/_feature_ais_overlay.md`.
282
+
283
+ - **[`signalk-collision-alerts`](https://www.npmjs.com/package/signalk-collision-alerts)**
284
+ by @dirkwa — Provides the CPA/TCPA engine behind our AIS collision
285
+ overlay. Pypilot-newui subscribes to
286
+ `notifications.navigation.closestApproach.*` and renders a red /
287
+ orange triangle on the rose + an infobox with ACK that routes
288
+ through the Signal K v2 Notifications API, so an ACK from
289
+ pypilot-newui is also seen by Freeboard-SK and every other SK
290
+ client.
291
+ See `docs/_feature_ais_overlay.md`.
292
+
293
+ - **[`pypilot-autopilot-provider`](https://www.npmjs.com/package/pypilot-autopilot-provider)**
294
+ by Panaaj — Shares the single pypilot socket cleanly with our
295
+ autopilot provider (see next section) so KIP, Freeboard's Autopilot
296
+ Console and any other SK v2 Autopilot API client all drive the same
297
+ pilot without duplicate connections.
298
+
238
299
  ## Working alongside `pypilot-autopilot-provider`
239
300
 
240
301
  We build on top of the excellent
package/dist/index.js CHANGED
@@ -28,7 +28,7 @@ const trip_recorder_1 = require("./trip-recorder");
28
28
  const maneuver_trace_1 = require("./maneuver-trace");
29
29
  // Rev counter bumped on every build so the user can distinguish deploys
30
30
  // from the webapp header (feedback_revision_bump_each_build).
31
- const PLUGIN_REVISION = "Rev430";
31
+ const PLUGIN_REVISION = "Rev449";
32
32
  // Rev59: read package.json once at load time so /status can report the
33
33
  // npm package version alongside the internal Rev counter.
34
34
  // eslint-disable-next-line @typescript-eslint/no-require-imports
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "signalk-pypilot-newui",
3
- "version": "2.12.0",
3
+ "version": "3.1.0",
4
4
  "description": "Signal K friendly UI for the pypilot autopilot, with first-class Signal K paths and Simple Switches so any downstream Signal K client can drive or monitor the pilot. Touch-first mobile visor + full pypilot data (servo, gains, calibration, tack, warnings). Coexists with pypilot-autopilot-provider.",
5
5
  "main": "./dist/index.js",
6
6
  "scripts": {
@@ -15,12 +15,19 @@
15
15
  "signalk-webapp",
16
16
  "signalk-category-instruments",
17
17
  "signalk-category-utility",
18
+ "signalk-category-ais",
19
+ "signalk-category-notifications",
18
20
  "pypilot",
19
21
  "tinypilot",
20
22
  "autopilot",
21
23
  "steering",
22
24
  "kip",
23
- "mobile-first"
25
+ "mobile-first",
26
+ "ais",
27
+ "cpa",
28
+ "tcpa",
29
+ "collision-avoidance",
30
+ "freeboard-sk-companion"
24
31
  ],
25
32
  "author": {
26
33
  "name": "Aitonos",