signalk-chiplog 2.6.0 → 2.8.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 +54 -1
- package/README.md +78 -56
- package/index.js +110 -27
- package/lib/api.js +2 -2
- package/lib/database.js +54 -1
- package/lib/detection.js +4 -16
- package/lib/event-watcher.js +142 -2
- package/lib/events.js +86 -21
- package/lib/history-api.js +401 -0
- package/lib/history-series.js +138 -0
- package/lib/influx-history.js +27 -102
- package/lib/replay-job.js +48 -26
- package/package.json +4 -1
- package/public/app.css +20 -0
- package/public/entry/entry.css +94 -1
- package/public/entry/js/components/Dialogs.mjs +82 -16
- package/public/entry/js/components/Icons.mjs +33 -0
- package/public/entry/js/components/NotePanel.mjs +21 -3
- package/public/entry/js/components/RecentList.mjs +2 -3
- package/public/entry/js/journal.mjs +24 -7
- package/public/entry/js/main.mjs +27 -18
- package/public/js/animation/boat-model.mjs +534 -171
- package/public/js/animation/camera3d.mjs +5 -2
- package/public/js/components/PassageView.mjs +4 -3
- package/public/js/components/Timeline.mjs +40 -14
- package/public/js/format.mjs +34 -0
- package/public/js/i18n.mjs +22 -6
- package/public/js/log-lines.mjs +10 -0
- package/public/vendor/three.min.mjs +172 -172
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,57 @@ All notable changes to Chiplog are documented here. The format follows
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [2.8.0] - 2026-10-01
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- **A manual entry's time can be typed in or corrected.** A note can be written up after the fact with the time it
|
|
14
|
+
happened, and any manoeuvre, note or sketch the crew logged can be redated later from the logbook's timeline or from
|
|
15
|
+
the tablet — an entry still waiting for the connection included. Since such an entry was not made where it happened,
|
|
16
|
+
its position is read back from the track at that time and left empty when the track has nothing within 2 minutes of
|
|
17
|
+
it, along with the instrument readings taken when the button was pressed. A time outside the passage or in the future
|
|
18
|
+
is refused, and the departure manoeuvre that opened a passage is still moved through that passage's departure time.
|
|
19
|
+
|
|
20
|
+
### Changed
|
|
21
|
+
|
|
22
|
+
- **The tablet's confirmation banner no longer reads as a question.** Logging an entry put up two buttons the size of
|
|
23
|
+
the app's primary actions, "Add a comment" and "Undo", which looked like a dialog waiting for an answer — it was not
|
|
24
|
+
clear the entry was already in, nor that "Undo" deleted it rather than dismissing the banner. The banner now confirms
|
|
25
|
+
first (a check mark, or a clock for an entry held on the tablet), carries a close button and a bar draining over the
|
|
26
|
+
ten seconds it stays, and puts the two follow-ups below the message at a smaller size, the undo in red and labelled
|
|
27
|
+
with what it undoes.
|
|
28
|
+
|
|
29
|
+
## [2.7.0] - 2026-09-22
|
|
30
|
+
|
|
31
|
+
### Added
|
|
32
|
+
|
|
33
|
+
- **Heading changes are logged automatically.** A turn of 30° or more (configurable), held steady for a minute above 2
|
|
34
|
+
knots, is added to the timeline as the average heading it settled on. Can be turned off in settings.
|
|
35
|
+
|
|
36
|
+
- **The retrospective analysis can read the Signal K History API.** Instead of connecting to an InfluxDB 1.x database
|
|
37
|
+
itself, Chiplog can now read whichever history provider the server has registered — signalk-to-influxdb2, QuestDB,
|
|
38
|
+
TimescaleDB — with no database credentials to set. Pick it with **History source** in the settings; InfluxDB 1.x stays
|
|
39
|
+
the default, so an existing installation is untouched.
|
|
40
|
+
- **Engine and sail segments are reconstructed from an InfluxDB 1.x history too.** The retrospective analysis read the
|
|
41
|
+
engine RPMs but never listed the boat's engines, so a reconstructed passage carried no propulsion segment and no
|
|
42
|
+
engine hours.
|
|
43
|
+
|
|
44
|
+
### Changed
|
|
45
|
+
|
|
46
|
+
- **The 3D animation starts on the medium boat size.** The 3D view opened with the smallest of the three; it now opens
|
|
47
|
+
on the middle one, where the boat is large enough to be read. **Boat size** still offers all three.
|
|
48
|
+
|
|
49
|
+
- **The 3D animation's boat is drawn as a cartoon.** The generated sailboat has been rebuilt: a fuller hull with a
|
|
50
|
+
proper sheer and overhangs, a planked deck with a covering board, a coachroof with portholes, a cockpit with a crew on
|
|
51
|
+
the weather rail, a roached mainsail with a stripe and a burgee at the masthead — all in flat colours with an inked
|
|
52
|
+
silhouette, so it still reads when the boat is only a hundred pixels long. Nothing changes for a crew who load their
|
|
53
|
+
own `.glb`.
|
|
54
|
+
|
|
55
|
+
- **`navigation.state` is followed whatever its source.** Chiplog no longer prefers signalk-autostate's value over
|
|
56
|
+
another source of the same path: it uses the one Signal K resolves the path to. On a boat where the AIS transponder
|
|
57
|
+
and signalk-autostate both publish it, which one wins is settled in the server's source priorities — that is also
|
|
58
|
+
where a transponder left at "under way using engine" while moored is corrected.
|
|
59
|
+
|
|
9
60
|
## [2.6.0] - 2026-09-20
|
|
10
61
|
|
|
11
62
|
### Changed
|
|
@@ -352,7 +403,9 @@ First release.
|
|
|
352
403
|
- REST API under `/plugins/signalk-chiplog/api`, documented in [docs/API.md](docs/API.md).
|
|
353
404
|
- Single SQLite database through Node's built-in `node:sqlite`: no native module to build.
|
|
354
405
|
|
|
355
|
-
[Unreleased]: https://github.com/ricard33/signalk-chiplog/compare/v2.
|
|
406
|
+
[Unreleased]: https://github.com/ricard33/signalk-chiplog/compare/v2.8.0...HEAD
|
|
407
|
+
[2.8.0]: https://github.com/ricard33/signalk-chiplog/compare/v2.7.0...v2.8.0
|
|
408
|
+
[2.7.0]: https://github.com/ricard33/signalk-chiplog/compare/v2.6.0...v2.7.0
|
|
356
409
|
[2.6.0]: https://github.com/ricard33/signalk-chiplog/compare/v2.5.1...v2.6.0
|
|
357
410
|
[2.5.1]: https://github.com/ricard33/signalk-chiplog/compare/v2.5.0...v2.5.1
|
|
358
411
|
[2.5.0]: https://github.com/ricard33/signalk-chiplog/compare/v2.4.0...v2.5.0
|
package/README.md
CHANGED
|
@@ -8,7 +8,7 @@ sensors cannot know from a tablet at the helm: manoeuvres, notes and handwriting
|
|
|
8
8
|
such as a lock or a lunch anchorage.
|
|
9
9
|
- **GPS track**, distance, time under engine and under sail.
|
|
10
10
|
- **Hourly instrument readings**, as on a paper log, plus readings at departure, arrival and each manoeuvre.
|
|
11
|
-
- **Automatic events**: alarms, autopilot changes, strong wind, falling barometer.
|
|
11
|
+
- **Automatic events**: alarms, autopilot changes, strong wind, falling barometer, held heading changes.
|
|
12
12
|
- **Departure and arrival names**, looked up online and corrected once for good.
|
|
13
13
|
- **Consultation webapp**: logbook by day, map, timeline, corrections, export.
|
|
14
14
|
- **Replay a range of passages** on the map — an hour of sailing per second — and save it as an MP4 for a phone, a
|
|
@@ -87,9 +87,9 @@ A **passage** is one logbook entry: from leaving a berth or anchorage to arrivin
|
|
|
87
87
|
which carries on once the boat moves.
|
|
88
88
|
- **Power cuts and restarts.** If the server comes back after the boat has been still for longer than the tolerance, the
|
|
89
89
|
passage is closed at its last movement. A short restart carries on with the same passage.
|
|
90
|
-
- **Under way or stopped** comes from `navigation.state` when
|
|
91
|
-
speed over ground over 3 minutes: under way above 1 knot, stopped below half a knot. This
|
|
92
|
-
anchor from starting passages.
|
|
90
|
+
- **Under way or stopped** comes from `navigation.state` when something publishes it — signalk-autostate, typically.
|
|
91
|
+
Otherwise Chiplog averages speed over ground over 3 minutes: under way above 1 knot, stopped below half a knot. This
|
|
92
|
+
keeps a boat swinging at anchor from starting passages.
|
|
93
93
|
|
|
94
94
|
A passage that was split in two — a stop just longer than the tolerance, for instance — can be merged back from the
|
|
95
95
|
logbook webapp. The stop the merge folds away is kept on the timeline as its own line, naming the place, since it would
|
|
@@ -131,6 +131,8 @@ Added to the timeline without anyone touching anything:
|
|
|
131
131
|
- **Wind** — true wind, averaged over 2 minutes, rising above 20 and 30 knots and falling back below them
|
|
132
132
|
(configurable).
|
|
133
133
|
- **Barometer** — a fall of 4 hPa or more over 3 hours (configurable).
|
|
134
|
+
- **Heading changes** — a turn of 30° or more, held steady for a minute, above 2 knots (configurable, and can be turned
|
|
135
|
+
off).
|
|
134
136
|
|
|
135
137
|
An alarm at anchor between two passages goes to the passage that ended there, as long as the boat is within 1 nautical
|
|
136
138
|
mile of that arrival.
|
|
@@ -212,8 +214,12 @@ Open **Chiplog** from the Signal K webapps, or `/signalk-chiplog/`. Reading need
|
|
|
212
214
|
counter at departure and arrival and the hours run, and the tank levels and battery charge, voltage and current noted
|
|
213
215
|
at departure), and the log: every reading and event in order, including handwritten notes. A passage in progress
|
|
214
216
|
refreshes every minute. Each line's comment can be edited (read/write access); a manoeuvre or note the crew logged
|
|
215
|
-
themselves can also be deleted — automatic lines (alarms, autopilot, weather, corrections) can only be
|
|
216
|
-
|
|
217
|
+
themselves can also be **redated** and deleted — automatic lines (alarms, autopilot, weather, corrections) can only be
|
|
218
|
+
annotated. Correcting a time reads the position back from the track at that time, and leaves it empty when the track
|
|
219
|
+
has nothing within 2 minutes of it, since the entry was not made where it happened. A time outside the passage, or in
|
|
220
|
+
the future, is refused, and the departure manoeuvre that opened a passage is moved by changing that passage's
|
|
221
|
+
departure time in **Corrections** below. Under each position, in grey, its bearing and distance from the nearest
|
|
222
|
+
landmark.
|
|
217
223
|
- **Corrections** (read/write access):
|
|
218
224
|
- rename the departure, or the arrival once the passage is closed — a passage in progress has none yet to rename;
|
|
219
225
|
- switch an engine period to sail or back;
|
|
@@ -236,9 +242,9 @@ Open **Chiplog** from the Signal K webapps, or `/signalk-chiplog/`. Reading need
|
|
|
236
242
|
saves it as a video in one of five shapes (Mobile 9:16, Portrait 3:4, Square 1:1, Landscape 4:3, Widescreen 16:9).
|
|
237
243
|
Everything happens in the browser: nothing is rendered or encoded on the Signal K server, and the map tiles are the
|
|
238
244
|
only thing downloaded. **View → 3D** shows the same film, at the map's own scale and with north still at the top, as a
|
|
239
|
-
camera tilted down onto a
|
|
240
|
-
laid flat under it; frame it closer or wider than the map and pick the boat's size if you like, and load your own
|
|
241
|
-
as a `.glb` file — sails included — if you would rather see it (see
|
|
245
|
+
camera tilted down onto a cartoon sailboat that heels and trims its sails to the wind and rides the waves, with the
|
|
246
|
+
map laid flat under it; frame it closer or wider than the map and pick the boat's size if you like, and load your own
|
|
247
|
+
boat as a `.glb` file — sails included — if you would rather see it (see
|
|
242
248
|
[Your own boat](#your-own-boat-in-the-3d-animation-)). The MP4 export then films the 3D view.
|
|
243
249
|
- **Export** — download the whole logbook or a date range as a PDF logbook to print, JSON, CSV or GPX, and write the
|
|
244
250
|
abandon-ship copy to the USB drive now (admin). The PDF is written in the webapp's language and the device's time
|
|
@@ -254,7 +260,7 @@ shortcuts beside it; where any date is allowed, the calendar has an _Any date_ b
|
|
|
254
260
|
|
|
255
261
|
### Your own boat in the 3D animation ⛵
|
|
256
262
|
|
|
257
|
-
The 3D view draws a
|
|
263
|
+
The 3D view draws a cartoon sailboat. To see yours instead, use **Boat → Use my own boat…** under the animation and pick
|
|
258
264
|
a `.glb` file. The model is kept in **that browser only** (it is never sent to the logbook or the Signal K server), so
|
|
259
265
|
it has to be loaded again on another device; **Use the default boat** puts the generic one back.
|
|
260
266
|
|
|
@@ -353,9 +359,11 @@ change. One tap logs it with the time, the position and an instrument reading.
|
|
|
353
359
|
|
|
354
360
|
- **Sail change** asks which sail went up: mainsail, genoa, jib, staysail, spinnaker, gennaker, code 0, storm jib, or
|
|
355
361
|
any name you type.
|
|
356
|
-
- A banner then confirms it
|
|
357
|
-
|
|
358
|
-
|
|
362
|
+
- A banner then confirms it: a check mark, what was logged and at what time, and a bar along the bottom draining over
|
|
363
|
+
the 10 seconds it stays. Nothing is waiting on you — it goes on its own, or at once with the **×**. Under the message
|
|
364
|
+
sit two optional follow-ups:
|
|
365
|
+
- **Add a comment**, e.g. "25 kn, second reef";
|
|
366
|
+
- **Undo this entry**, in red, for a mistaken tap — it deletes the entry just logged.
|
|
359
367
|
|
|
360
368
|
### Departures open the passage
|
|
361
369
|
|
|
@@ -370,7 +378,8 @@ note once moored belongs to the passage that brought you there. Anywhere else, t
|
|
|
370
378
|
|
|
371
379
|
### Notes and handwriting
|
|
372
380
|
|
|
373
|
-
- **Note** — type and tap **Log it**.
|
|
381
|
+
- **Note** — type and tap **Log it**. Leave **Time** empty for now, or fill it in to write up something that happened
|
|
382
|
+
earlier; a note dated by hand takes its position from the track rather than from where you are standing.
|
|
374
383
|
- **Handwriting** — takes over the whole screen, with a toolbar above the pad: fine pen, thick pen, highlighter, eraser,
|
|
375
384
|
undo, and a choice of colour (kept to the theme's colour in night mode, to spare night vision). Pen pressure also sets
|
|
376
385
|
the line width. The eraser removes only what it actually touches, splitting a stroke rather than deleting all of it;
|
|
@@ -383,7 +392,8 @@ export, not just on the tablet.
|
|
|
383
392
|
### Latest entries
|
|
384
393
|
|
|
385
394
|
Below, the latest entries of the current passage (or of the last one) are listed with their time. Each can take a
|
|
386
|
-
comment, and your own entries can be deleted; a note's text can be edited.
|
|
395
|
+
comment, and your own entries can be redated and deleted; a note's text can be edited. An entry still waiting for the
|
|
396
|
+
connection can be corrected too — the change travels with it.
|
|
387
397
|
|
|
388
398
|
### Night mode
|
|
389
399
|
|
|
@@ -418,36 +428,43 @@ a regular Signal K user account.
|
|
|
418
428
|
|
|
419
429
|
In the Signal K admin, **Apps & Plugins → Configuration → Chiplog**.
|
|
420
430
|
|
|
421
|
-
| Setting | Default | What it does
|
|
422
|
-
| ---------------------------------------------------------------- | --------------------------------------------- |
|
|
423
|
-
| Stop duration within which a new departure continues the passage | 30 min | A passage closes when the boat stops; leaving again sooner reopens it, the stop kept as a stopover.
|
|
424
|
-
| Under-way speed without navigation.state | 1 kn | Used only without signalk-autostate: under way above it, stopped below half of it.
|
|
425
|
-
| Propulsion assumed without engine data | sail | When nothing says whether the engine is running. Set to engine on a motorboat.
|
|
426
|
-
| Instrument snapshot interval | 60 min | Readings on this clock boundary during a passage.
|
|
427
|
-
| Track point interval | 15 s | A track point at least this often while moving.
|
|
428
|
-
| Place matching radius | 200 m | A departure or arrival this close to a known place takes its name.
|
|
429
|
-
| Name departures and arrivals with online geocoding | on | Turn off to never send positions online; places are then named after their coordinates until corrected.
|
|
430
|
-
| Geocoding service | `https://nominatim.openstreetmap.org` | Any Nominatim-compatible service, e.g. a self-hosted one.
|
|
431
|
-
| Read each journal line against the nearest landmark | on | Fetches the landmarks of the areas sailed through from OpenStreetMap, so each position is also given as a bearing and distance from one. Turn off to keep the coordinates alone.
|
|
432
|
-
| Landmark service (Overpass API) | `https://overpass-api.de/api/interpreter` | Any Overpass-compatible service, e.g. a self-hosted one.
|
|
433
|
-
| Fetch the tide forecast at departure | on | Turn off to never send the departure position online; the passage page then shows no tide.
|
|
434
|
-
| Marine service | `https://marine-api.open-meteo.com/v1/marine` | Any Open-Meteo Marine-compatible service, e.g. a self-hosted one. Serves the tide, and the sea state and current of the weather forecast.
|
|
435
|
-
| Fetch the marine weather forecast at departure | on | Turn off to never send the departure position to the weather services; the passage page and the PDF then show no forecast.
|
|
436
|
-
| Weather service | `https://api.open-meteo.com/v1/forecast` | Any Open-Meteo-compatible forecast service, e.g. a self-hosted one.
|
|
437
|
-
| USB export directory | — | Where the abandon-ship copy is written, e.g. `/media/usb`. Empty turns the USB copy off.
|
|
438
|
-
| Automatic USB copy interval | 15 min | How often the USB copy is brought up to date. 0 turns the periodic copy off.
|
|
439
|
-
| Copy to the USB drive at each arrival | on | Brings the USB copy up to date as soon as a passage ends.
|
|
440
|
-
| Logbook language (PDF) | en | Language of the PDF logbooks on the USB drive (English or French).
|
|
441
|
-
| Ship's time zone (PDF) | the server's | Time zone of the PDF logbooks on the USB drive, e.g. `Europe/Paris`.
|
|
442
|
-
| Wind speed thresholds | 20, 30 kn | Logged when the 2-minute average true wind crosses them.
|
|
443
|
-
| Barometric drop warning | 4 hPa / 3 h | 0 turns it off.
|
|
444
|
-
|
|
|
445
|
-
|
|
|
446
|
-
|
|
|
447
|
-
|
|
|
448
|
-
|
|
|
449
|
-
|
|
|
450
|
-
|
|
|
431
|
+
| Setting | Default | What it does |
|
|
432
|
+
| ---------------------------------------------------------------- | --------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
433
|
+
| Stop duration within which a new departure continues the passage | 30 min | A passage closes when the boat stops; leaving again sooner reopens it, the stop kept as a stopover. |
|
|
434
|
+
| Under-way speed without navigation.state | 1 kn | Used only without signalk-autostate: under way above it, stopped below half of it. |
|
|
435
|
+
| Propulsion assumed without engine data | sail | When nothing says whether the engine is running. Set to engine on a motorboat. |
|
|
436
|
+
| Instrument snapshot interval | 60 min | Readings on this clock boundary during a passage. |
|
|
437
|
+
| Track point interval | 15 s | A track point at least this often while moving. |
|
|
438
|
+
| Place matching radius | 200 m | A departure or arrival this close to a known place takes its name. |
|
|
439
|
+
| Name departures and arrivals with online geocoding | on | Turn off to never send positions online; places are then named after their coordinates until corrected. |
|
|
440
|
+
| Geocoding service | `https://nominatim.openstreetmap.org` | Any Nominatim-compatible service, e.g. a self-hosted one. |
|
|
441
|
+
| Read each journal line against the nearest landmark | on | Fetches the landmarks of the areas sailed through from OpenStreetMap, so each position is also given as a bearing and distance from one. Turn off to keep the coordinates alone. |
|
|
442
|
+
| Landmark service (Overpass API) | `https://overpass-api.de/api/interpreter` | Any Overpass-compatible service, e.g. a self-hosted one. |
|
|
443
|
+
| Fetch the tide forecast at departure | on | Turn off to never send the departure position online; the passage page then shows no tide. |
|
|
444
|
+
| Marine service | `https://marine-api.open-meteo.com/v1/marine` | Any Open-Meteo Marine-compatible service, e.g. a self-hosted one. Serves the tide, and the sea state and current of the weather forecast. |
|
|
445
|
+
| Fetch the marine weather forecast at departure | on | Turn off to never send the departure position to the weather services; the passage page and the PDF then show no forecast. |
|
|
446
|
+
| Weather service | `https://api.open-meteo.com/v1/forecast` | Any Open-Meteo-compatible forecast service, e.g. a self-hosted one. |
|
|
447
|
+
| USB export directory | — | Where the abandon-ship copy is written, e.g. `/media/usb`. Empty turns the USB copy off. |
|
|
448
|
+
| Automatic USB copy interval | 15 min | How often the USB copy is brought up to date. 0 turns the periodic copy off. |
|
|
449
|
+
| Copy to the USB drive at each arrival | on | Brings the USB copy up to date as soon as a passage ends. |
|
|
450
|
+
| Logbook language (PDF) | en | Language of the PDF logbooks on the USB drive (English or French). |
|
|
451
|
+
| Ship's time zone (PDF) | the server's | Time zone of the PDF logbooks on the USB drive, e.g. `Europe/Paris`. |
|
|
452
|
+
| Wind speed thresholds | 20, 30 kn | Logged when the 2-minute average true wind crosses them. |
|
|
453
|
+
| Barometric drop warning | 4 hPa / 3 h | 0 turns it off. |
|
|
454
|
+
| Log heading changes | on | Turn off to leave heading changes out of the log. |
|
|
455
|
+
| Heading change threshold | 30° | A change must be at least this large to be logged. |
|
|
456
|
+
| Heading change tolerance | 10° | How much the new heading may wander while holding and still count as steady. |
|
|
457
|
+
| Heading change hold time | 60 s | How long the new heading must hold before it is logged. |
|
|
458
|
+
| Heading change minimum speed | 2 kn | Below this speed over ground, the course is too noisy to log a change. |
|
|
459
|
+
| Heading change cooldown | 5 min | A new change is logged only once the last one is at least this old. |
|
|
460
|
+
| History source (retrospective analysis) | InfluxDB 1.x | Select Signal K History API to read the server's own history provider, such as signalk-to-influxdb2 — no database connection needed. InfluxDB 1.x stays the default so existing installations are untouched. |
|
|
461
|
+
| InfluxDB host (retrospective analysis) | — | Shown only for the InfluxDB 1.x legacy source. Local or remote host of the database signalk-to-influxdb writes to. Empty turns the retrospective analysis page off. |
|
|
462
|
+
| InfluxDB port | 8086 | |
|
|
463
|
+
| InfluxDB database | — | |
|
|
464
|
+
| InfluxDB username / password | — | Leave empty if the database needs none. |
|
|
465
|
+
| InfluxDB protocol | http | `http` or `https`. |
|
|
466
|
+
| Retrospective query timeout | 30 s | Each retrospective query gives up and reports an error past this, instead of hanging against an unreachable or overloaded history. Applies to either source. |
|
|
467
|
+
| Vessel context (retrospective analysis) | this server's own | Only needed running the replay from a different Signal K server than the one that wrote the history, e.g. development pointed at a production database. Applies to either source. |
|
|
451
468
|
|
|
452
469
|
## Signal K data used 🔌
|
|
453
470
|
|
|
@@ -459,7 +476,7 @@ None of these is required except position and speed over ground; each feature us
|
|
|
459
476
|
| Engine or sail | `propulsion.*.revolutions`, `propulsion.*.state`, `navigation.state` |
|
|
460
477
|
| Readings | `navigation.headingTrue` (or `headingMagnetic` + `magneticVariation`), `navigation.speedThroughWater`, `environment.wind.*`, `environment.depth.belowSurface` (or `belowTransducer`), `environment.outside.pressure`, `environment.outside.temperature`, `environment.water.temperature`, `navigation.log`, `propulsion.*.runTime` |
|
|
461
478
|
| Boat status | `tanks.*.*.currentLevel`, `.currentVolume`, `.capacity`, `.name`, `electrical.batteries.*.voltage`, `.current`, `.capacity.stateOfCharge`, `.temperature`, `.name` |
|
|
462
|
-
| Events | `notifications.*`, `steering.autopilot.state`, `.mode`, `.engaged`, `.target`, `environment.wind.speedTrue`, `environment.outside.pressure`
|
|
479
|
+
| Events | `notifications.*`, `steering.autopilot.state`, `.mode`, `.engaged`, `.target`, `environment.wind.speedTrue`, `environment.outside.pressure`, `navigation.headingTrue` (or `headingMagnetic` + `magneticVariation`) |
|
|
463
480
|
|
|
464
481
|
## Backups and abandon ship 🛟
|
|
465
482
|
|
|
@@ -485,9 +502,13 @@ stopped? The **Retrospective** page (admin access) reconstructs those passages f
|
|
|
485
502
|
Chiplog runs live — the same thresholds, so a reconstructed passage is one Chiplog would have logged had it been running
|
|
486
503
|
at the time.
|
|
487
504
|
|
|
488
|
-
-
|
|
489
|
-
|
|
490
|
-
|
|
505
|
+
- Choose a history source in **Apps & Plugins → Configuration**:
|
|
506
|
+
- **Signal K History API** (recommended) reads the server's active history provider, such as
|
|
507
|
+
[signalk-to-influxdb2](https://github.com/tkurki/signalk-to-influxdb2), without database credentials or storage
|
|
508
|
+
schema assumptions.
|
|
509
|
+
- **InfluxDB 1.x (legacy)** requires [signalk-to-influxdb](https://github.com/tkurki/signalk-to-influxdb) to have
|
|
510
|
+
written the boat's data into an InfluxDB 1.x database — local or on another machine — set with host, port, database,
|
|
511
|
+
and a username/password if it needs one.
|
|
491
512
|
- Pick a **from** and **to** date on the Retrospective page and start it. It runs in the background — the page shows its
|
|
492
513
|
progress — and can be cancelled at any point; a first quick pass finds when the boat moved, and only those stretches
|
|
493
514
|
are then fetched and reconstructed, so weeks in port take next to no time. Once done, the page sums up what it added:
|
|
@@ -567,9 +588,10 @@ Chiplog works, but departures and arrivals are decided from speed only. The mess
|
|
|
567
588
|
- **"has not been updated since…"** — the source named stopped publishing. signalk-autostate republishes every 10
|
|
568
589
|
minutes while it receives position and speed: check that the GPS data reaches the server, and that the plugin is
|
|
569
590
|
enabled.
|
|
570
|
-
- **"is “default” (from nmea0183.AI)"** —
|
|
571
|
-
|
|
572
|
-
is enabled
|
|
591
|
+
- **"is “default” (from nmea0183.AI)"** — the source Signal K resolved `navigation.state` to publishes a navigational
|
|
592
|
+
status Chiplog does not use, typically the boat's own AIS transponder. Chiplog follows whichever source the server
|
|
593
|
+
picks, so the fix is on the server: check that signalk-autostate is enabled, and give it priority over the transponder
|
|
594
|
+
in Signal K's source priorities.
|
|
573
595
|
|
|
574
596
|
### Passages are not opening
|
|
575
597
|
|
|
@@ -624,10 +646,10 @@ context** in the plugin configuration.
|
|
|
624
646
|
### A retrospective analysis takes minutes then fails with no clear reason
|
|
625
647
|
|
|
626
648
|
The InfluxDB server did not answer — unreachable, overloaded, a firewall or a VPN not connected. Each query now gives up
|
|
627
|
-
after **
|
|
628
|
-
until some far longer, less informative failure; check that the server named in the plugin configuration is
|
|
629
|
-
from wherever Signal K runs, and that it is not overloaded — or raise the timeout if it is simply slow to
|
|
630
|
-
six-hour chunk.
|
|
649
|
+
after **Retrospective query timeout** (30 seconds by default) with the connection problem it ran into, rather than
|
|
650
|
+
hanging until some far longer, less informative failure; check that the server named in the plugin configuration is
|
|
651
|
+
reachable from wherever Signal K runs, and that it is not overloaded — or raise the timeout if it is simply slow to
|
|
652
|
+
answer a six-hour chunk.
|
|
631
653
|
|
|
632
654
|
### A retrospective analysis over several days makes the InfluxDB server unresponsive
|
|
633
655
|
|
package/index.js
CHANGED
|
@@ -225,50 +225,121 @@ module.exports = function (app) {
|
|
|
225
225
|
default: EVENT_DEFAULTS.pressureDropThreshold,
|
|
226
226
|
minimum: 0
|
|
227
227
|
},
|
|
228
|
-
|
|
229
|
-
type: '
|
|
230
|
-
title: '
|
|
228
|
+
headingChangeEnabled: {
|
|
229
|
+
type: 'boolean',
|
|
230
|
+
title: 'Log heading changes',
|
|
231
231
|
description:
|
|
232
|
-
'
|
|
232
|
+
'Records a course change once it is held; turn off to leave heading changes out of the log',
|
|
233
|
+
default: EVENT_DEFAULTS.headingChangeEnabled
|
|
233
234
|
},
|
|
234
|
-
|
|
235
|
+
headingChangeThreshold: {
|
|
235
236
|
type: 'number',
|
|
236
|
-
title: '
|
|
237
|
-
|
|
237
|
+
title: 'Heading change threshold (degrees)',
|
|
238
|
+
description: 'A change must be at least this large to be logged',
|
|
239
|
+
default: EVENT_DEFAULTS.headingChangeThreshold,
|
|
240
|
+
minimum: 1,
|
|
241
|
+
maximum: 180
|
|
238
242
|
},
|
|
239
|
-
|
|
240
|
-
type: '
|
|
241
|
-
title: '
|
|
243
|
+
headingChangeTolerance: {
|
|
244
|
+
type: 'number',
|
|
245
|
+
title: 'Heading change tolerance (degrees)',
|
|
246
|
+
description: 'How much the new heading may wander while holding and still count as steady',
|
|
247
|
+
default: EVENT_DEFAULTS.headingChangeTolerance,
|
|
248
|
+
minimum: 0
|
|
242
249
|
},
|
|
243
|
-
|
|
244
|
-
type: '
|
|
245
|
-
title: '
|
|
246
|
-
description: '
|
|
250
|
+
headingChangeHoldSeconds: {
|
|
251
|
+
type: 'number',
|
|
252
|
+
title: 'Heading change hold time (seconds)',
|
|
253
|
+
description: 'How long the new heading must hold before it is logged',
|
|
254
|
+
default: EVENT_DEFAULTS.headingChangeHoldSeconds,
|
|
255
|
+
minimum: 1
|
|
247
256
|
},
|
|
248
|
-
|
|
249
|
-
type: '
|
|
250
|
-
title: '
|
|
251
|
-
|
|
257
|
+
headingChangeMinSpeed: {
|
|
258
|
+
type: 'number',
|
|
259
|
+
title: 'Heading change minimum speed (knots)',
|
|
260
|
+
description: 'Below this speed over ground, the course is too noisy to log a change',
|
|
261
|
+
default: EVENT_DEFAULTS.headingChangeMinSpeed,
|
|
262
|
+
minimum: 0
|
|
263
|
+
},
|
|
264
|
+
headingChangeCooldownMinutes: {
|
|
265
|
+
type: 'number',
|
|
266
|
+
title: 'Heading change cooldown (minutes)',
|
|
267
|
+
description: 'A new change is logged only once the last one is at least this old',
|
|
268
|
+
default: EVENT_DEFAULTS.headingChangeCooldownMinutes,
|
|
269
|
+
minimum: 0
|
|
252
270
|
},
|
|
253
|
-
|
|
271
|
+
retrospectiveHistorySource: {
|
|
254
272
|
type: 'string',
|
|
255
|
-
title: '
|
|
256
|
-
|
|
257
|
-
|
|
273
|
+
title: 'History source for retrospective analysis',
|
|
274
|
+
description:
|
|
275
|
+
'Signal K reads the server’s own History API provider (signalk-to-influxdb2, for example), needing no database connection of its own — the better choice on a new installation. InfluxDB 1.x keeps the legacy direct database reader, and stays the default so installations already set up that way go on working untouched.',
|
|
276
|
+
enum: ['influxdb1', 'signalk'],
|
|
277
|
+
enumNames: ['InfluxDB 1.x (legacy)', 'Signal K History API'],
|
|
278
|
+
default: 'influxdb1'
|
|
258
279
|
},
|
|
259
280
|
influxQueryTimeoutSeconds: {
|
|
260
281
|
type: 'number',
|
|
261
|
-
title: '
|
|
282
|
+
title: 'Retrospective query timeout (seconds)',
|
|
262
283
|
description:
|
|
263
|
-
'Each retrospective query is given up on and reported as an error past this, rather than hanging indefinitely against an unreachable or overloaded
|
|
284
|
+
'Each retrospective query is given up on and reported as an error past this, rather than hanging indefinitely against an unreachable or overloaded history. Applies to either history source',
|
|
264
285
|
default: INFLUX_DEFAULTS.influxQueryTimeoutSeconds,
|
|
265
286
|
minimum: 1
|
|
266
287
|
},
|
|
267
288
|
influxSelfContext: {
|
|
268
289
|
type: 'string',
|
|
269
|
-
title: '
|
|
290
|
+
title: 'Vessel context (retrospective analysis)',
|
|
270
291
|
description:
|
|
271
|
-
'Only needed running the replay from a different Signal K server than the one that wrote the history — e.g. a development instance pointed at a boat’s production database. The vessel context the data was tagged with, such as "vessels.urn:mrn:imo:mmsi:123456789"; a failed replay names the contexts actually found. Leave empty to use this server’s own (Signal K → Server → Vessel Identity)'
|
|
292
|
+
'Only needed running the replay from a different Signal K server than the one that wrote the history — e.g. a development instance pointed at a boat’s production database. The vessel context the data was tagged with, such as "vessels.urn:mrn:imo:mmsi:123456789"; a failed replay names the contexts actually found. Leave empty to use this server’s own (Signal K → Server → Vessel Identity). Applies to either history source'
|
|
293
|
+
}
|
|
294
|
+
},
|
|
295
|
+
// RJSF evaluates dependencies each time the selector changes. Keeping the
|
|
296
|
+
// InfluxDB fields out of the top-level properties hides them in History
|
|
297
|
+
// API mode and inserts them immediately after the source selector.
|
|
298
|
+
dependencies: {
|
|
299
|
+
retrospectiveHistorySource: {
|
|
300
|
+
oneOf: [
|
|
301
|
+
{
|
|
302
|
+
properties: {
|
|
303
|
+
retrospectiveHistorySource: { const: 'influxdb1' },
|
|
304
|
+
influxHost: {
|
|
305
|
+
type: 'string',
|
|
306
|
+
title: 'InfluxDB host (retrospective analysis)',
|
|
307
|
+
description:
|
|
308
|
+
'For reconstructing past passages from a signalk-to-influxdb history (InfluxDB 1.x), local or remote. Leave empty to turn that feature off'
|
|
309
|
+
},
|
|
310
|
+
influxPort: {
|
|
311
|
+
type: 'number',
|
|
312
|
+
title: 'InfluxDB port',
|
|
313
|
+
default: INFLUX_DEFAULTS.influxPort
|
|
314
|
+
},
|
|
315
|
+
influxDatabase: {
|
|
316
|
+
type: 'string',
|
|
317
|
+
title: 'InfluxDB database'
|
|
318
|
+
},
|
|
319
|
+
influxUsername: {
|
|
320
|
+
type: 'string',
|
|
321
|
+
title: 'InfluxDB username',
|
|
322
|
+
description: 'Leave empty if the database needs none'
|
|
323
|
+
},
|
|
324
|
+
influxPassword: {
|
|
325
|
+
type: 'string',
|
|
326
|
+
title: 'InfluxDB password',
|
|
327
|
+
format: 'password'
|
|
328
|
+
},
|
|
329
|
+
influxProtocol: {
|
|
330
|
+
type: 'string',
|
|
331
|
+
title: 'InfluxDB protocol',
|
|
332
|
+
enum: ['http', 'https'],
|
|
333
|
+
default: INFLUX_DEFAULTS.influxProtocol
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
},
|
|
337
|
+
{
|
|
338
|
+
properties: {
|
|
339
|
+
retrospectiveHistorySource: { const: 'signalk' }
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
]
|
|
272
343
|
}
|
|
273
344
|
}
|
|
274
345
|
};
|
|
@@ -400,6 +471,16 @@ module.exports = function (app) {
|
|
|
400
471
|
logbookTimeZone: config.logbookTimeZone || null,
|
|
401
472
|
windSpeedThresholds: config.windSpeedThresholds ?? EVENT_DEFAULTS.windSpeedThresholds,
|
|
402
473
|
pressureDropThreshold: config.pressureDropThreshold ?? EVENT_DEFAULTS.pressureDropThreshold,
|
|
474
|
+
headingChangeEnabled: config.headingChangeEnabled ?? EVENT_DEFAULTS.headingChangeEnabled,
|
|
475
|
+
headingChangeThreshold:
|
|
476
|
+
config.headingChangeThreshold ?? EVENT_DEFAULTS.headingChangeThreshold,
|
|
477
|
+
headingChangeTolerance:
|
|
478
|
+
config.headingChangeTolerance ?? EVENT_DEFAULTS.headingChangeTolerance,
|
|
479
|
+
headingChangeHoldSeconds:
|
|
480
|
+
config.headingChangeHoldSeconds ?? EVENT_DEFAULTS.headingChangeHoldSeconds,
|
|
481
|
+
headingChangeMinSpeed: config.headingChangeMinSpeed ?? EVENT_DEFAULTS.headingChangeMinSpeed,
|
|
482
|
+
headingChangeCooldownMinutes:
|
|
483
|
+
config.headingChangeCooldownMinutes ?? EVENT_DEFAULTS.headingChangeCooldownMinutes,
|
|
403
484
|
influxHost: config.influxHost || null,
|
|
404
485
|
influxPort: config.influxPort ?? INFLUX_DEFAULTS.influxPort,
|
|
405
486
|
influxDatabase: config.influxDatabase || null,
|
|
@@ -408,7 +489,9 @@ module.exports = function (app) {
|
|
|
408
489
|
influxProtocol: config.influxProtocol || INFLUX_DEFAULTS.influxProtocol,
|
|
409
490
|
influxQueryTimeoutSeconds:
|
|
410
491
|
config.influxQueryTimeoutSeconds ?? INFLUX_DEFAULTS.influxQueryTimeoutSeconds,
|
|
411
|
-
influxSelfContext: config.influxSelfContext || null
|
|
492
|
+
influxSelfContext: config.influxSelfContext || null,
|
|
493
|
+
retrospectiveHistorySource:
|
|
494
|
+
config.retrospectiveHistorySource === 'signalk' ? 'signalk' : 'influxdb1'
|
|
412
495
|
};
|
|
413
496
|
|
|
414
497
|
if (settings.logbookTimeZone && !isTimeZone(settings.logbookTimeZone)) {
|
package/lib/api.js
CHANGED
|
@@ -499,7 +499,7 @@ function registerRoutes(router, { getContext, logError }) {
|
|
|
499
499
|
|
|
500
500
|
readwrite.patch(
|
|
501
501
|
'/api/events/:id',
|
|
502
|
-
handle(({ db }, req) => {
|
|
502
|
+
handle(({ db, now }, req) => {
|
|
503
503
|
const id = v.parseId(req.params.id);
|
|
504
504
|
const body = v.requireBody(req.body, ['time', 'comment', 'subtype', 'payload']);
|
|
505
505
|
const patch = withoutUndefined({
|
|
@@ -508,7 +508,7 @@ function registerRoutes(router, { getContext, logError }) {
|
|
|
508
508
|
subtype: optional(body, 'subtype', nullableString(200)),
|
|
509
509
|
payload: optional(body, 'payload', parsePayload)
|
|
510
510
|
});
|
|
511
|
-
return events.updateEvent(db, id, patch);
|
|
511
|
+
return events.updateEvent(db, id, patch, { now: now() });
|
|
512
512
|
})
|
|
513
513
|
);
|
|
514
514
|
|
package/lib/database.js
CHANGED
|
@@ -371,7 +371,10 @@ const MIGRATIONS = [
|
|
|
371
371
|
ALTER TABLE places ADD COLUMN country_code TEXT;
|
|
372
372
|
ALTER TABLE places ADD COLUMN country_checked INTEGER NOT NULL DEFAULT 0
|
|
373
373
|
CHECK (country_checked IN (0, 1));
|
|
374
|
-
|
|
374
|
+
`,
|
|
375
|
+
// Another CHECK-widening rebuild, same reason and same shape as
|
|
376
|
+
// addPropulsionChangeEventType.
|
|
377
|
+
addHeadingChangeEventType
|
|
375
378
|
];
|
|
376
379
|
|
|
377
380
|
function addPropulsionChangeEventType(db, version) {
|
|
@@ -472,6 +475,56 @@ function addStopoverEventType(db, version) {
|
|
|
472
475
|
db.exec('PRAGMA foreign_keys = ON');
|
|
473
476
|
}
|
|
474
477
|
|
|
478
|
+
function addHeadingChangeEventType(db, version) {
|
|
479
|
+
db.exec('PRAGMA foreign_keys = OFF');
|
|
480
|
+
withTransaction(db, () => {
|
|
481
|
+
db.exec(`
|
|
482
|
+
-- The event-watcher logs a held course change (SPEC §4.6) the same way
|
|
483
|
+
-- as the other automatic events.
|
|
484
|
+
CREATE TABLE events_new (
|
|
485
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
486
|
+
entry_id INTEGER NOT NULL REFERENCES log_entries (id) ON DELETE CASCADE,
|
|
487
|
+
time TEXT NOT NULL,
|
|
488
|
+
type TEXT NOT NULL CHECK (
|
|
489
|
+
type IN (
|
|
490
|
+
'manoeuvre',
|
|
491
|
+
'text_annotation',
|
|
492
|
+
'handwritten_annotation',
|
|
493
|
+
'sk_alarm',
|
|
494
|
+
'autopilot',
|
|
495
|
+
'weather_threshold',
|
|
496
|
+
'manual_correction',
|
|
497
|
+
'propulsion_change',
|
|
498
|
+
'stopover',
|
|
499
|
+
'heading_change'
|
|
500
|
+
)
|
|
501
|
+
),
|
|
502
|
+
subtype TEXT,
|
|
503
|
+
lat REAL,
|
|
504
|
+
lon REAL,
|
|
505
|
+
comment TEXT,
|
|
506
|
+
payload TEXT,
|
|
507
|
+
source TEXT NOT NULL DEFAULT 'manual' CHECK (source IN ('auto', 'manual')),
|
|
508
|
+
created_at TEXT NOT NULL,
|
|
509
|
+
client_ref TEXT
|
|
510
|
+
);
|
|
511
|
+
INSERT INTO events_new (
|
|
512
|
+
id, entry_id, time, type, subtype, lat, lon, comment, payload, source, created_at, client_ref
|
|
513
|
+
)
|
|
514
|
+
SELECT id, entry_id, time, type, subtype, lat, lon, comment, payload, source, created_at, client_ref
|
|
515
|
+
FROM events;
|
|
516
|
+
DROP TABLE events;
|
|
517
|
+
ALTER TABLE events_new RENAME TO events;
|
|
518
|
+
CREATE INDEX idx_events_entry_time ON events (entry_id, time);
|
|
519
|
+
CREATE INDEX idx_events_type ON events (type);
|
|
520
|
+
CREATE UNIQUE INDEX idx_events_client_ref ON events (client_ref)
|
|
521
|
+
WHERE client_ref IS NOT NULL;
|
|
522
|
+
`);
|
|
523
|
+
db.exec(`PRAGMA user_version = ${version + 1}`);
|
|
524
|
+
});
|
|
525
|
+
db.exec('PRAGMA foreign_keys = ON');
|
|
526
|
+
}
|
|
527
|
+
|
|
475
528
|
function seedBuiltinManoeuvreTypes(db) {
|
|
476
529
|
const insert = db.prepare(
|
|
477
530
|
`INSERT INTO manoeuvre_types (key, label, sort_order, builtin)
|