signalk-pypilot-newui 2.11.0 → 2.12.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 +246 -0
- package/README.md +1 -0
- package/dist/autopilot-provider.js +685 -24
- package/dist/index.js +289 -29
- package/dist/test/virtual-tack.test.js +436 -0
- package/dist/virtual-tack.js +320 -0
- package/package.json +1 -1
- package/public/app.js +1600 -115
- package/public/index.html +65 -6
- package/public/style.css +343 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,251 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 2.12.0 — 2026-10-08 — Virtual-tack audit cycle + Profile UX overhaul + safety aproado/empopado
|
|
4
|
+
|
|
5
|
+
Rolls up Rev410 through Rev430 (21 revs). Driven by two sea trials
|
|
6
|
+
(2026-10-03 and 2026-10-04) that exposed critical virtual-tack bugs
|
|
7
|
+
and a batch of UX problems around profiles and the mode selector.
|
|
8
|
+
Six audit MDs accompany the fixes (`docs/_audit_commit[2-6]_pre_rev*.md`
|
|
9
|
+
+ `docs/_sea_trial_2026-10-04.md`) following the "audit before fix"
|
|
10
|
+
rule that paid for itself after three failed attempts at the drag/drop
|
|
11
|
+
bug.
|
|
12
|
+
|
|
13
|
+
### Added
|
|
14
|
+
|
|
15
|
+
- **Virtual-tack audit cycle (Commits 2–6 of the Rev407 plan)**.
|
|
16
|
+
- *Commit 2 (Rev410)* — Mando trace enrichment (`ap.tack.state` and
|
|
17
|
+
`ap.tack.direction` deltas now log heading + AWA + mode + vtPhase),
|
|
18
|
+
VT `remainingDeg` on the mirror HUD (shows "N°" while turning,
|
|
19
|
+
"settling" during the handover phase), explicit "VT fallida: X"
|
|
20
|
+
toast when the backend publishes a terminal `failed` snapshot.
|
|
21
|
+
- *Commit 3 (Rev411)* — Writes propagate pypilot refusal through
|
|
22
|
+
`PUT /raw`, the SignalK v2 PUT handler and the `/ap/*` fallbacks
|
|
23
|
+
(503 instead of a false 200), and `dodge()` throws so KIP sees
|
|
24
|
+
the failure.
|
|
25
|
+
- *Commit 5 (Rev412)* — Empopado hot-gains that **actually apply**
|
|
26
|
+
(silent no-op since Rev320: the code read `catalog[path].value`
|
|
27
|
+
which never existed). Reads from `state.pypilotValues[path]`
|
|
28
|
+
now. New `data-hot={on|off|failed}` badge inside the active HUD
|
|
29
|
+
makes the PID state visible.
|
|
30
|
+
- *Commit 6 (Rev413)* — Yellow (warn) toast when settling times out
|
|
31
|
+
but the compass rotation finished: "Virada completada, viento sin
|
|
32
|
+
converger". Target is still applied; sailor sees it did not fully
|
|
33
|
+
confirm.
|
|
34
|
+
- *Commit 4 (Rev414)* — AWA settling EMA with τ ≈ 2 s applied to the
|
|
35
|
+
noisy raw apparent-wind sample. Fixes the "settling-timeout" seen
|
|
36
|
+
on light-wind sea trials. 4 unit tests cover seed / convergence /
|
|
37
|
+
±π wrap-around / α = 0 identity.
|
|
38
|
+
- **Virtual-tack final-angle override** (Rev416, fix #12). Backend
|
|
39
|
+
accepts optional `finalAngleRad` on `/virtual-tack/start`; the visor
|
|
40
|
+
forwards whatever is set in `localStorage.pypilotnewui.tackFinalAngleDeg`.
|
|
41
|
+
Sailor can trim the destination AWA ±170° without having to nudge
|
|
42
|
+
after the tack. Backend validates (`|rad| ≤ π`) and falls back to
|
|
43
|
+
the AWA mirror on any invalid value.
|
|
44
|
+
- **EMA staleness guard** (Rev415). The settling loop now reads
|
|
45
|
+
`p.timestamp` from the SK path; samples older than
|
|
46
|
+
`STALE_SAMPLE_MS = 3000` are ignored, the dwell counter resets, and
|
|
47
|
+
the EMA state is cleared so a frozen value (e.g. after a WiFi
|
|
48
|
+
dropout) cannot sneak into the "ok" window.
|
|
49
|
+
- **Nudge target trace** (Rev415, fix #1 instrumentation).
|
|
50
|
+
`apSetTargetRad` logs the current target / heading / AWA / TWA /
|
|
51
|
+
mode / engaged BEFORE each PUT and the status / ok AFTER, so a
|
|
52
|
+
stale-UI vs. real-refusal diagnosis is trivial on the next sea trial.
|
|
53
|
+
- **Mode selector custom modal** (Rev425 → Rev430, fix #13 iterated).
|
|
54
|
+
Replaces the native `<select>` with a centered modal built lazily
|
|
55
|
+
under `<body>` (`.mode-select-modal-backdrop`). Contents:
|
|
56
|
+
- "MODO" label + list; the active mode highlighted in accent blue.
|
|
57
|
+
- "PERFIL" label + autowrapping button (1–2 lines so long names
|
|
58
|
+
like "Ceñida fondo medio viento" fit).
|
|
59
|
+
- Nested list opens **upward** (position: absolute; bottom: 100%)
|
|
60
|
+
so expanding profiles does not force the modal to scroll.
|
|
61
|
+
- Idempotent repaint — SK deltas never flash the open modal.
|
|
62
|
+
- **Doctor suggestions sorted + numbered** (Rev417, fix #8). Visor
|
|
63
|
+
pre-sorts by the same priority map the backend `applyAll` uses
|
|
64
|
+
(`bias < authority < oscillation < noise`), stamps a 1-based
|
|
65
|
+
ordinal prefix ("1.", "2.", "3.") on each card and gives the first
|
|
66
|
+
pending suggestion a `.top-priority` accent border so the sailor
|
|
67
|
+
can see which card the "Apply top priority" button will target.
|
|
68
|
+
- **Unlock prompt** (Rev421, fix #7). Flipping a group's unlock
|
|
69
|
+
checkbox opens a 3-choice modal ("Editar en perfil actual" /
|
|
70
|
+
"Cambiar a 'basic' primero" / "Cancelar") so the sailor explicitly
|
|
71
|
+
chooses the edit scope before touching sliders. Modal body answers
|
|
72
|
+
the second half of Carlos's question: "Los cambios se aplican en el
|
|
73
|
+
acto, no hace falta cerrar la pantalla."
|
|
74
|
+
|
|
75
|
+
### Changed
|
|
76
|
+
|
|
77
|
+
- **Safety: aproado/empopado restoreAll default = false** (Rev415,
|
|
78
|
+
fix #11). Carlos: "hay que anular el restituir rumbo cuando salimos
|
|
79
|
+
de aproado o empopado porque es peligroso". Pre-Rev415 the finish
|
|
80
|
+
path unconditionally restored mode + target + disengage; now it
|
|
81
|
+
leaves the pilot where it is unless the caller opts in. The
|
|
82
|
+
"lost stern" auto-cancel in empopado passes `restoreAll:false` too.
|
|
83
|
+
- **Fork modal wording** (Rev418, fix #6). The "Keep in '{pilot}'"
|
|
84
|
+
button was filling `{pilot}` with `state.pilot` (always "basic"),
|
|
85
|
+
misleading when the active profile was called something else. Now
|
|
86
|
+
reads "Guardar en el perfil activo" + an info line showing the
|
|
87
|
+
actual profile + pilot pair. Cancel label clarified to
|
|
88
|
+
"Cancelar (deshacer último cambio)".
|
|
89
|
+
- **VT mirror watchdog raised 60 s → 120 s** (Rev410, fix U.2) so it
|
|
90
|
+
does not race the backend's own `PYPILOT_STUCK_MS = 60 s`.
|
|
91
|
+
- **Pypilot-silent watchdog gated on VT state** (Rev410, fix U.1).
|
|
92
|
+
During a VT the backend owns the authoritative stuck detection;
|
|
93
|
+
the legacy 40 s time-since-delta heuristic only fires on native
|
|
94
|
+
tack paths (no VT active) to avoid false "virada cancelada" toasts.
|
|
95
|
+
- **Fork modal strings fully translated** (Rev419, fix #6 follow-up).
|
|
96
|
+
Modal title, body and name label were English fallbacks because
|
|
97
|
+
`data-i18n` is not walked on dynamic `innerHTML`; now set
|
|
98
|
+
explicitly from `t()` after creation.
|
|
99
|
+
|
|
100
|
+
### Fixed
|
|
101
|
+
|
|
102
|
+
- **Profile Manager drag/drop ping-pong flicker** (Rev420 after Rev418
|
|
103
|
+
and Rev419 attempts). The live-reorder approach was intrinsically
|
|
104
|
+
unstable — after each `insertBefore` the next `pointermove`
|
|
105
|
+
re-triggered a swap. Rewritten with the deferred-commit pattern:
|
|
106
|
+
only `translateY` the dragged item during the gesture, mark the
|
|
107
|
+
nearest drop-target with a visual line, commit one `insertBefore`
|
|
108
|
+
at the end. Also moved listeners to `window` + pointerId filter
|
|
109
|
+
(was on the handle, failed silently on tablet browsers) and gave
|
|
110
|
+
`.pm-item.dragging { touch-action: none }` so the gesture is not
|
|
111
|
+
interpreted as a scroll. Flash animation `.just-moved` on commit
|
|
112
|
+
confirms the move landed.
|
|
113
|
+
- **Tack stats HUD "dejaron de salir" + z-index + X not clickable**
|
|
114
|
+
(Rev416, fix #10). The HUD was only wired to the native pypilot
|
|
115
|
+
tack path (`_tackCountdownTick` arrived); VT (wind mode) never
|
|
116
|
+
triggered it. Terminal `virtualTack` snapshots now call
|
|
117
|
+
`_tackStatsOnTackCompleted` (completed) or
|
|
118
|
+
`_tackStatsOnTackCancelled` (cancelled/failed). Corner tiles had
|
|
119
|
+
`z-index:3` and the SVG wind-rose had no stacking context, so the
|
|
120
|
+
HUD painted behind corners; added a `stats-hud-up` class on
|
|
121
|
+
`.dash-rose` that raises `.rose-wrap` to `z-index:5` while the HUD
|
|
122
|
+
is open and drops corners to `z-index:1` with
|
|
123
|
+
`pointer-events:none`. Close × hit area widened to 34 × 34 so
|
|
124
|
+
off-centre taps still land.
|
|
125
|
+
- **Mode modal "se carga dos veces"** (Rev428). `refreshPypilotValues`
|
|
126
|
+
called `_rebuildModeSelect()` twice back-to-back (once when
|
|
127
|
+
`profiles` landed, once when `profile` landed) and each call
|
|
128
|
+
wiped-and-repopulated the modal's sub-select, producing a visible
|
|
129
|
+
double flash. Consolidated into a single `needsModeRebuild` flag
|
|
130
|
+
+ made `_rebuildModePopupProfiles` idempotent (diffs the current
|
|
131
|
+
option list and skips the repaint when it matches).
|
|
132
|
+
- **Mode popup viewport cropping** (Rev426 before the Rev427 full
|
|
133
|
+
redesign). Pre-Rev427 the anchored popup overflowed the viewport
|
|
134
|
+
bottom on 80 %-zoom laptops and phone portrait; added
|
|
135
|
+
viewport-aware placement + internal scroll before deciding to
|
|
136
|
+
switch to a centered modal anyway.
|
|
137
|
+
- **Doctor "Apply top priority" button targets the right card**
|
|
138
|
+
(Rev417 side-effect of #8). The visor now mirrors the backend's
|
|
139
|
+
priority sort so the highlighted card is always the one the button
|
|
140
|
+
will apply.
|
|
141
|
+
|
|
142
|
+
### Known limitations / pending real-water verification
|
|
143
|
+
|
|
144
|
+
- Rev410 U.2 / U.3 — 120 s watchdog + "VT fallida" toast on backend
|
|
145
|
+
`outcomeReason` need a real pypilot-dead moment to confirm.
|
|
146
|
+
- Rev411 J.1 / J.2 / J-1.5 — 503 propagation on `PUT /raw`, SK v2 PUT
|
|
147
|
+
handler and `dodge()` need pypilot genuinely offline to exercise.
|
|
148
|
+
- Rev412 — "aggressive PID" on empopado now ACTUALLY writes gains to
|
|
149
|
+
pypilot (dormant since Rev320). Validate in water that the new
|
|
150
|
+
P × 1.5 / D × 1.7 / servo-slew × 1.3 does not cause oscillation.
|
|
151
|
+
- Rev414 — AWA EMA τ = 2 s needs confirmation in light wind that the
|
|
152
|
+
dampened sample reaches the ±10° / 2 s dwell to produce
|
|
153
|
+
`completed:ok` instead of `settling-timeout`.
|
|
154
|
+
- Rev416 — final-angle override is exposed via `localStorage` only; a
|
|
155
|
+
slider UI will come in a later rev.
|
|
156
|
+
- Observation #2 from the 2026-10-04 sea trial (pilot behaves as if
|
|
157
|
+
tracking true wind in `wind` mode) is still open and awaits the
|
|
158
|
+
next sea trial's nav-session data with the Rev415 instrumentation
|
|
159
|
+
to confirm it as a real bug vs. a PID-tuning symptom.
|
|
160
|
+
- Observation #9 — AIS collision overlay on the rose — is planned for
|
|
161
|
+
the next **major (3.0.0)** bump; the design is drafted in
|
|
162
|
+
`docs/_audit_feature9_ais_overlay.md` but not implemented yet.
|
|
163
|
+
|
|
164
|
+
---
|
|
165
|
+
|
|
166
|
+
## 2.11.0 — 2026-09-30 — Sea-trial Sprint K fixes + severity override + portrait layout
|
|
167
|
+
|
|
168
|
+
Rolls up Rev324 through Rev376. Between 2.10.0 (Rev323) and 2.11.0 the
|
|
169
|
+
plugin went through a second sea trial (2026-09-28, 27 min on Tunatunes)
|
|
170
|
+
that surfaced 13 bugs. The ones not requiring open water are fixed in
|
|
171
|
+
this release; the remainder (aproado/empopado true-wind, mando-físico
|
|
172
|
+
HUD mirror) are implemented and awaiting sea-trial QA.
|
|
173
|
+
|
|
174
|
+
### Added
|
|
175
|
+
|
|
176
|
+
- **Per-rule alarm severity override** (Rev342 backend + Rev374 frontend).
|
|
177
|
+
Each rule in Setup > Alarms now has an inline `🔴 Alarma / 🟡 Aviso /
|
|
178
|
+
🔵 Info` dropdown. Changes are persisted via `props.alarmSeverityOverrides`
|
|
179
|
+
so they survive restarts. The shipped default is marked with `★` so the
|
|
180
|
+
sailor can see which option is the factory setting before changing it.
|
|
181
|
+
Endpoint: `POST /alarms/severity/:id {severity}`.
|
|
182
|
+
- **Mute countdown mm:ss** (Rev375). The muted-rule status pill now shows
|
|
183
|
+
real-time `MM:SS` (updated every second) instead of coarse `N minutes`.
|
|
184
|
+
- **Maneuver HUD mirror for external tacks** (Rev348 → Rev355). When a
|
|
185
|
+
tack is triggered from the pypilot native UI or physical remote, the
|
|
186
|
+
visor opens the overlay, animates the orange buttons, and emits the
|
|
187
|
+
post-tack stats panel — the same experience as a visor-initiated tack.
|
|
188
|
+
- **Tack cancellation stats** (Rev355). Cancelling mid-tack shows the HUD
|
|
189
|
+
immediately with `pre` + "CANCELADO" and no post window.
|
|
190
|
+
- **Pypilot-silence watchdog** (Rev367). If pypilot stops sending `ap.tack.state`
|
|
191
|
+
deltas for more than 60 s during a maneuver, the visor closes the mirror
|
|
192
|
+
overlay itself so the UI doesn't hang indefinitely on a lost connection.
|
|
193
|
+
- **Observability instrumentation** (Rev346). `maneuver-trace` now logs
|
|
194
|
+
stage events (`wallTs + monoTs`) for frontier debugging, plus `mtLog`
|
|
195
|
+
calls in `pluginRaw` and the `ap.tack.state/direction` handleDelta
|
|
196
|
+
branch tag the event source as `external` vs visor-local.
|
|
197
|
+
- **Heap diagnostics** sidecar (preserved from Rev885-equivalent work):
|
|
198
|
+
internal structure sizes under `/api/diagnostic.heapAudit` for
|
|
199
|
+
long-term RSS tracking.
|
|
200
|
+
|
|
201
|
+
### Changed
|
|
202
|
+
|
|
203
|
+
- **Tack stats post window shortened** 60 s → 15 s (Rev371). Was 30 s
|
|
204
|
+
wait + 30 s measurement; now 5 s wait + 10 s measurement. 10 samples at
|
|
205
|
+
1 Hz still yield a stable TWS/AWA/SOG average.
|
|
206
|
+
- **Rate-of-turn fallback more conservative** (Rev345). Minimum completion
|
|
207
|
+
threshold raised to `max(20°, total × 0.4)` so brief rotations don't
|
|
208
|
+
trigger a premature "tack completed" verdict.
|
|
209
|
+
- **Portrait tablet layout** (Rev370). `font-size` media queries at
|
|
210
|
+
900 / 1200 / 1600 / 2000 px heights cascade through `em` units to
|
|
211
|
+
scale both the rose and the surrounding buttons on tall tablets.
|
|
212
|
+
Confirmed working on Opera Mobile (where `zoom` had no effect).
|
|
213
|
+
- **Button labels in wind mode** (Rev343). `±100°` becomes `VIRAR ← / →`
|
|
214
|
+
when the pilot is in `wind` or `truewind`, matching the actual
|
|
215
|
+
semantics.
|
|
216
|
+
- **Cancel labels during active maneuver** (Rev343). The orange buttons
|
|
217
|
+
show `CANCELAR VIRADA` or `CANCELAR TRASLUCHADA` instead of their
|
|
218
|
+
normal text so the sailor knows what tapping them will do.
|
|
219
|
+
|
|
220
|
+
### Fixed
|
|
221
|
+
|
|
222
|
+
- **Diamond target stuck on external tacks** (Rev347). The
|
|
223
|
+
`_countdownPlannedTargetRad` variable now only masks `state.target`
|
|
224
|
+
when the countdown overlay is actually visible; stale values from
|
|
225
|
+
previously aborted visor tacks are cleared belt-and-suspenders.
|
|
226
|
+
- **Severity dropdown reverted to default on every poll** (Rev375,
|
|
227
|
+
`alarms.ts` `describe()`). Was returning `rule.severity` (the factory
|
|
228
|
+
default) instead of `s.severity` (the runtime value with override
|
|
229
|
+
applied). Fixed to return `s.severity`.
|
|
230
|
+
- **Visor countdown mask over authoritative state** (Rev347 lesson,
|
|
231
|
+
documented pattern). Any JS variable that fronts an authoritative
|
|
232
|
+
bus value must be gated by a visible UI signal, not by a cleanup
|
|
233
|
+
that may not fire on every abort path.
|
|
234
|
+
|
|
235
|
+
### Known limitations
|
|
236
|
+
|
|
237
|
+
- Aproado / empopado true-wind flow (`apSetMode("wind")` with
|
|
238
|
+
`await state.mode = "wind"` before `apSetTargetRad`) is implemented
|
|
239
|
+
but awaits sea-trial QA.
|
|
240
|
+
- Physical-remote tack → HUD mirror hook (bug #7 from the 2026-09-28
|
|
241
|
+
trial) is implemented via `observeTackTransition` + `external` flag
|
|
242
|
+
but awaits sea-trial validation.
|
|
243
|
+
- The pypilot-core direction rewrite for short-arc wind tacks is
|
|
244
|
+
upstream (not our plugin) and remains open; a GitHub issue is drafted
|
|
245
|
+
but not yet posted to Sean D'Epagnier.
|
|
246
|
+
|
|
247
|
+
---
|
|
248
|
+
|
|
3
249
|
## 2.10.0 — 2026-09-27 — Sea-trial wind-mode fixes + maneuver forensics
|
|
4
250
|
|
|
5
251
|
Rolls up Rev309 through Rev323. Between 2.9.0 (Rev280) and 2.10.0 the
|
package/README.md
CHANGED
|
@@ -316,6 +316,7 @@ that isolated TinyPilot.
|
|
|
316
316
|
| `POST` | `/plugins/signalk-pypilot-newui/alarms/ack/:id` | Acknowledge one active alarm (silences the sound, banner stays visible). |
|
|
317
317
|
| `POST` | `/plugins/signalk-pypilot-newui/alarms/mute/:id` | Mute the RULE for N minutes (query `?min=15`). |
|
|
318
318
|
| `POST` | `/plugins/signalk-pypilot-newui/alarms/enable/:id` | Enable / disable a rule (query `?on=1\|0`). |
|
|
319
|
+
| `POST` | `/plugins/signalk-pypilot-newui/alarms/severity/:id` | Override the severity of one rule. Body: `{ "severity": "info\|warn\|alarm" }`. Persists via `props.alarmSeverityOverrides` so it survives restart. |
|
|
319
320
|
| `GET` | `/plugins/signalk-pypilot-newui/prechecks` | Pre-departure autopilot check verdict: `ready` / `ready-with-caveats` / `do-not-engage` + per-item detail. |
|
|
320
321
|
| `POST` | `/plugins/signalk-pypilot-newui/doctor/start` | Start a diagnostic session (query `?duration=180`). Requires AP engaged. |
|
|
321
322
|
| `POST` | `/plugins/signalk-pypilot-newui/doctor/cancel` | Cancel the current session. |
|