signalk-chiplog 2.2.0 → 2.3.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
@@ -6,6 +6,23 @@ All notable changes to Chiplog are documented here. The format follows
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [2.3.0] - 2026-09-18
10
+
11
+ ### Added
12
+
13
+ - **InfluxDB query timeout** setting (`influxQueryTimeoutSeconds`, 30 s by default): how long a retrospective replay
14
+ waits for the InfluxDB server to answer before giving up on it as unreachable or overloaded, now configurable instead
15
+ of a fixed 30 seconds — useful against a Raspberry Pi that is simply slow to answer a six-hour chunk.
16
+
17
+ ### Fixed
18
+
19
+ - **Retrospective replay backfilling a gap before passages already logged live** no longer dated every reconstructed
20
+ passage to the most recent existing passage's end time. Detection's guard against an out-of-order departure looked at
21
+ the latest `end_time` in the whole logbook rather than only at passages that actually preceded the new one, so filling
22
+ in an earlier gap — installing Chiplog after the fact, or after a stop — pinned every reconstructed departure to that
23
+ unrelated, later date, and the replay summary reported no passage found for the requested period even though entries
24
+ had been created.
25
+
9
26
  ## [2.2.0] - 2026-09-18
10
27
 
11
28
  ### Added
@@ -249,7 +266,8 @@ First release.
249
266
  - REST API under `/plugins/signalk-chiplog/api`, documented in [docs/API.md](docs/API.md).
250
267
  - Single SQLite database through Node's built-in `node:sqlite`: no native module to build.
251
268
 
252
- [Unreleased]: https://github.com/ricard33/signalk-chiplog/compare/v2.2.0...HEAD
269
+ [Unreleased]: https://github.com/ricard33/signalk-chiplog/compare/v2.3.0...HEAD
270
+ [2.3.0]: https://github.com/ricard33/signalk-chiplog/compare/v2.2.0...v2.3.0
253
271
  [2.2.0]: https://github.com/ricard33/signalk-chiplog/compare/v2.1.0...v2.2.0
254
272
  [2.1.0]: https://github.com/ricard33/signalk-chiplog/compare/v2.0.0...v2.1.0
255
273
  [2.0.0]: https://github.com/ricard33/signalk-chiplog/compare/v1.2.0...v2.0.0
package/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  # Chiplog
2
2
 
3
- An automated logbook for [Signal K](https://signalk.org). Chiplog writes the logbook from the data already on your
4
- boat's Signal K server — passages, track, engine and sail, instrument readings, alarms — and lets the crew add what
3
+ An automated nautical logbook for [Signal K](https://signalk.org). Chiplog writes the logbook from the data already on
4
+ your boat's Signal K server — passages, track, engine and sail, instrument readings, alarms — and lets the crew add what
5
5
  sensors cannot know from a tablet at the helm: manoeuvres, notes and handwriting.
6
6
 
7
7
  - **One entry per passage**, opened when the boat leaves and closed as soon as it arrives, carrying on after short stops
@@ -348,6 +348,7 @@ In the Signal K admin, **Apps & Plugins → Configuration → Chiplog**.
348
348
  | InfluxDB database | — | |
349
349
  | InfluxDB username / password | — | Leave empty if the database needs none. |
350
350
  | InfluxDB protocol | http | `http` or `https`. |
351
+ | InfluxDB query timeout | 30 s | Each retrospective query gives up and reports an error past this, instead of hanging against an unreachable or overloaded database. |
351
352
  | InfluxDB vessel context | 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. |
352
353
 
353
354
  ## Signal K data used 🔌
@@ -497,9 +498,10 @@ context** in the plugin configuration.
497
498
  ### A retrospective analysis takes minutes then fails with no clear reason
498
499
 
499
500
  The InfluxDB server did not answer — unreachable, overloaded, a firewall or a VPN not connected. Each query now gives up
500
- after 30 seconds with the connection problem it ran into, rather than hanging until some far longer, less informative
501
- failure; check that the server named in the plugin configuration is reachable from wherever Signal K runs, and that it
502
- is not overloaded.
501
+ after **InfluxDB query timeout** (30 seconds by default) with the connection problem it ran into, rather than hanging
502
+ until some far longer, less informative failure; check that the server named in the plugin configuration is reachable
503
+ from wherever Signal K runs, and that it is not overloaded — or raise the timeout if it is simply slow to answer a
504
+ six-hour chunk.
503
505
 
504
506
  ### A retrospective analysis over several days makes the InfluxDB server unresponsive
505
507
 
package/index.js CHANGED
@@ -256,6 +256,14 @@ module.exports = function (app) {
256
256
  enum: ['http', 'https'],
257
257
  default: INFLUX_DEFAULTS.influxProtocol
258
258
  },
259
+ influxQueryTimeoutSeconds: {
260
+ type: 'number',
261
+ title: 'InfluxDB query timeout (seconds)',
262
+ 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 database',
264
+ default: INFLUX_DEFAULTS.influxQueryTimeoutSeconds,
265
+ minimum: 1
266
+ },
259
267
  influxSelfContext: {
260
268
  type: 'string',
261
269
  title: 'InfluxDB vessel context',
@@ -384,6 +392,8 @@ module.exports = function (app) {
384
392
  influxUsername: config.influxUsername || null,
385
393
  influxPassword: config.influxPassword || null,
386
394
  influxProtocol: config.influxProtocol || INFLUX_DEFAULTS.influxProtocol,
395
+ influxQueryTimeoutSeconds:
396
+ config.influxQueryTimeoutSeconds ?? INFLUX_DEFAULTS.influxQueryTimeoutSeconds,
387
397
  influxSelfContext: config.influxSelfContext || null
388
398
  };
389
399
 
package/lib/detection.js CHANGED
@@ -314,11 +314,16 @@ function createPassageDetector({ db, readSelfPath, settings, clock = Date.now })
314
314
  }
315
315
 
316
316
  function openPassage(now, position, departure) {
317
+ const startIso = iso(departure.time);
318
+ // Only a passage that actually precedes this departure can push it later
319
+ // -- not just whichever entry happens to hold the latest end_time. A
320
+ // retrospective replay filling a gap before passages logged live (SPEC
321
+ // §4.10) would otherwise have every reconstructed departure clamped to
322
+ // the most recent (unrelated, later) passage's end.
317
323
  const previousEnd = db
318
- .prepare('SELECT MAX(end_time) AS endTime FROM log_entries')
319
- .get().endTime;
320
- const startTime =
321
- previousEnd && iso(departure.time) < previousEnd ? previousEnd : iso(departure.time);
324
+ .prepare('SELECT MAX(end_time) AS endTime FROM log_entries WHERE start_time < ?')
325
+ .get(startIso).endTime;
326
+ const startTime = previousEnd && startIso < previousEnd ? previousEnd : startIso;
322
327
  const start = departure.position ?? position;
323
328
  const place = initialPlaceName(db, start, settings.placeMatchRadius);
324
329
 
@@ -12,7 +12,9 @@ const { AUTOSTATE_SOURCE_PREFIX, MAX_AGE_MS, UNDERWAY_STATES } = require('./dete
12
12
  // packets, a VPN not connected) can otherwise hang far longer than this --
13
13
  // Node's fetch has no default timeout of its own -- for an error that is no
14
14
  // clearer once it finally arrives, so `query` bounds every request itself.
15
- const QUERY_TIMEOUT_MS = 30 * 1000;
15
+ // Configurable (`influxQueryTimeoutSeconds`): a Raspberry Pi under load can
16
+ // need longer than the default to answer a six-hour chunk.
17
+ const DEFAULT_QUERY_TIMEOUT_SECONDS = 30;
16
18
 
17
19
  // A resource-constrained host (a Raspberry Pi running both Signal K and
18
20
  // InfluxDB) can be brought down by one query spanning weeks across every
@@ -34,7 +36,8 @@ const INFLUX_DEFAULTS = {
34
36
  influxPort: 8086,
35
37
  influxDatabase: '',
36
38
  influxUsername: '',
37
- influxPassword: ''
39
+ influxPassword: '',
40
+ influxQueryTimeoutSeconds: DEFAULT_QUERY_TIMEOUT_SECONDS
38
41
  };
39
42
 
40
43
  // Everything detection, track recording and observations read live (SPEC
@@ -107,9 +110,11 @@ function createInfluxHistory({
107
110
  username,
108
111
  password,
109
112
  selfContext,
113
+ queryTimeoutSeconds = INFLUX_DEFAULTS.influxQueryTimeoutSeconds,
110
114
  fetch = globalThis.fetch,
111
115
  signal
112
116
  }) {
117
+ const queryTimeoutMs = queryTimeoutSeconds * 1000;
113
118
  // path -> [{ time, node }], ascending by time; `node` is what readSelfPath
114
119
  // answers, built once here rather than on every read.
115
120
  const series = new Map();
@@ -131,7 +136,7 @@ function createInfluxHistory({
131
136
  epoch: 'ms',
132
137
  q: statements.join(';')
133
138
  });
134
- const timeout = AbortSignal.timeout(QUERY_TIMEOUT_MS);
139
+ const timeout = AbortSignal.timeout(queryTimeoutMs);
135
140
  let response;
136
141
  try {
137
142
  response = await fetch(url, {
@@ -146,7 +151,7 @@ function createInfluxHistory({
146
151
  }
147
152
  if (err.name === 'TimeoutError') {
148
153
  throw new Error(
149
- `InfluxDB at ${protocol}://${host}:${port} did not answer within ${QUERY_TIMEOUT_MS / 1000}s`,
154
+ `InfluxDB at ${protocol}://${host}:${port} did not answer within ${queryTimeoutSeconds}s`,
150
155
  { cause: err }
151
156
  );
152
157
  }
package/lib/replay-job.js CHANGED
@@ -71,6 +71,7 @@ function createReplayJob({
71
71
  username: settings.influxUsername,
72
72
  password: settings.influxPassword,
73
73
  selfContext: settings.influxSelfContext || app.selfContext,
74
+ queryTimeoutSeconds: settings.influxQueryTimeoutSeconds,
74
75
  fetch,
75
76
  signal
76
77
  });
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "signalk-chiplog",
3
- "version": "2.2.0",
4
- "description": "Automated digital logbook plugin for Signal K, with keyboard/handwritten entry on tablet",
3
+ "version": "2.3.0",
4
+ "description": "Nautical logbook for Signal K: automatic entries, handwritten notes",
5
5
  "main": "index.js",
6
6
  "files": [
7
7
  "index.js",