signalk-wakelogger 0.2.0-beta.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 +32 -0
- package/LICENSE +201 -0
- package/README.md +49 -0
- package/SECURITY.md +7 -0
- package/assets/screenshots/plugin-config.png +0 -0
- package/assets/screenshots/plugin-status.png +0 -0
- package/assets/wakelogger.svg +6 -0
- package/dist/config/defaults.d.ts +18 -0
- package/dist/config/defaults.js +30 -0
- package/dist/config/defaults.js.map +1 -0
- package/dist/config/schema.d.ts +43 -0
- package/dist/config/schema.js +47 -0
- package/dist/config/schema.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +338 -0
- package/dist/index.js.map +1 -0
- package/dist/outbox/database-outbox.d.ts +25 -0
- package/dist/outbox/database-outbox.js +186 -0
- package/dist/outbox/database-outbox.js.map +1 -0
- package/dist/outbox/database-types.d.ts +19 -0
- package/dist/outbox/database-types.js +3 -0
- package/dist/outbox/database-types.js.map +1 -0
- package/dist/outbox/factory.d.ts +12 -0
- package/dist/outbox/factory.js +98 -0
- package/dist/outbox/factory.js.map +1 -0
- package/dist/outbox/file-outbox.d.ts +27 -0
- package/dist/outbox/file-outbox.js +280 -0
- package/dist/outbox/file-outbox.js.map +1 -0
- package/dist/outbox/interface.d.ts +33 -0
- package/dist/outbox/interface.js +3 -0
- package/dist/outbox/interface.js.map +1 -0
- package/dist/pairing/association-client.d.ts +3 -0
- package/dist/pairing/association-client.js +31 -0
- package/dist/pairing/association-client.js.map +1 -0
- package/dist/pairing/credentials.d.ts +46 -0
- package/dist/pairing/credentials.js +168 -0
- package/dist/pairing/credentials.js.map +1 -0
- package/dist/pairing/pairing-client.d.ts +19 -0
- package/dist/pairing/pairing-client.js +102 -0
- package/dist/pairing/pairing-client.js.map +1 -0
- package/dist/signalk/normaliser.d.ts +11 -0
- package/dist/signalk/normaliser.js +119 -0
- package/dist/signalk/normaliser.js.map +1 -0
- package/dist/signalk/paths.d.ts +2 -0
- package/dist/signalk/paths.js +14 -0
- package/dist/signalk/paths.js.map +1 -0
- package/dist/signalk/subscriber.d.ts +2 -0
- package/dist/signalk/subscriber.js +20 -0
- package/dist/signalk/subscriber.js.map +1 -0
- package/dist/telemetry/profile-store.d.ts +7 -0
- package/dist/telemetry/profile-store.js +39 -0
- package/dist/telemetry/profile-store.js.map +1 -0
- package/dist/telemetry/profile.d.ts +32 -0
- package/dist/telemetry/profile.js +94 -0
- package/dist/telemetry/profile.js.map +1 -0
- package/dist/telemetry/sampler.d.ts +14 -0
- package/dist/telemetry/sampler.js +44 -0
- package/dist/telemetry/sampler.js.map +1 -0
- package/dist/telemetry/types.d.ts +73 -0
- package/dist/telemetry/types.js +3 -0
- package/dist/telemetry/types.js.map +1 -0
- package/dist/transport/adaptive-mode.d.ts +23 -0
- package/dist/transport/adaptive-mode.js +63 -0
- package/dist/transport/adaptive-mode.js.map +1 -0
- package/dist/transport/mqtt-client.d.ts +69 -0
- package/dist/transport/mqtt-client.js +365 -0
- package/dist/transport/mqtt-client.js.map +1 -0
- package/dist/transport/topics.d.ts +10 -0
- package/dist/transport/topics.js +13 -0
- package/dist/transport/topics.js.map +1 -0
- package/dist/trips/state-machine.d.ts +38 -0
- package/dist/trips/state-machine.js +118 -0
- package/dist/trips/state-machine.js.map +1 -0
- package/docs/architecture.md +17 -0
- package/docs/development.md +49 -0
- package/docs/implementation-plan.md +1943 -0
- package/docs/original-plan-gap-audit.md +47 -0
- package/docs/pairing.md +17 -0
- package/docs/release.md +52 -0
- package/docs/telemetry-protocol.md +50 -0
- package/docs/trip-detection.md +7 -0
- package/docs/validation.md +35 -0
- package/package.json +80 -0
|
@@ -0,0 +1,1943 @@
|
|
|
1
|
+
# Wake Logger Signal K Plugin — Implementation Plan
|
|
2
|
+
|
|
3
|
+
## 2026-08-31 refined decisions and implementation status
|
|
4
|
+
|
|
5
|
+
This is the complete original implementation plan recovered from CachyOS, with the following agreed decisions as authoritative amendments. Where an example or undecided option later in this document conflicts with this section, this section wins.
|
|
6
|
+
|
|
7
|
+
### Scope and ownership
|
|
8
|
+
|
|
9
|
+
- The eventual delivery is end-to-end: this plugin, Wake Logger pairing and device management, Mosquitto, ingestion, current state, provisional trips and private/public UI.
|
|
10
|
+
- This repository owns only live acquisition and resilient transport. Wake Logger owns authorization, entitlements, vessel mapping, derived wind, final trip boundaries and edits. Post-trip archival upload remains a separate system.
|
|
11
|
+
- Trip events from the plugin are advisory evidence. The cloud is authoritative. The first live milestone emits evidence and stores live telemetry; automatic cloud trip refinement is calibrated using real data.
|
|
12
|
+
- The feature uses the existing Race Analytics entitlement. All vessel crew may view private live telemetry read-only. Device management is restricted by Wake Logger's vessel-management policy, and only owners/site administrators control public sharing.
|
|
13
|
+
- Public tracking is owner opt-in, revocable and independently supports unlisted links and directory listing. Production rollout follows isolated validation and explicit approval.
|
|
14
|
+
|
|
15
|
+
### Representative evidence and protocol v1
|
|
16
|
+
|
|
17
|
+
Representative NMEA/DAT fixtures confirm that protocol v1 can reliably carry:
|
|
18
|
+
|
|
19
|
+
```text
|
|
20
|
+
lat, lon, capturedAt, receivedAt
|
|
21
|
+
sog_kn, cog_deg
|
|
22
|
+
heading_deg, heading_reference
|
|
23
|
+
depth_m
|
|
24
|
+
aws_kn, awa_deg
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Signal K provides speed in m/s and angles in radians; the plugin converts speeds to knots and angles to degrees in `[0,360)`. Depth remains metres. True heading is preferred and magnetic fallback is labelled. Wake Logger continues deriving `tws_kn`, `twd_deg`, VMG, tack, supported speed and calculation quality rather than trusting incoming true-wind frames.
|
|
28
|
+
|
|
29
|
+
Regression fixtures cover invalid historical time anchors, out-of-range depth sentinels, non-finite values and timed-out sensors. Rate of turn, attitude, GNSS diagnostics, water temperature, speed through water, engine, electrical and tanks are outside the current telemetry profile.
|
|
30
|
+
|
|
31
|
+
Each sample receives a persistent monotonic sequence before its durable append. Identity and deduplication use `device_id + sequence`, never `vessel_id + sequence`. The authenticated device maps to its vessel server-side and a payload vessel ID is not trusted. A batch may declare `droppedThrough` to explicitly close a device-side retention/recovery gap.
|
|
32
|
+
|
|
33
|
+
### Pairing and MQTT contract
|
|
34
|
+
|
|
35
|
+
- Public pairing uses the Wake Logger HTTPS endpoint configured by the plugin.
|
|
36
|
+
- Non-production overrides remain local and are never committed.
|
|
37
|
+
- Request: `{ "code": "...", "name": "Signal K ..." }`.
|
|
38
|
+
- Response: `{ "device": { "id": "..." }, "credentials": { "broker_host": "...", "broker_port": 8883, "tls": true, "client_id": "...", "username": "...", "password": "...", "telemetry_profile": {}, "association_status_url": "https://...", "association_token": "..." } }`.
|
|
39
|
+
- Topics: `wakelogger/v1/devices/<device-id>/{telemetry,state,status,events,ack,profile,profile-ack}`.
|
|
40
|
+
- Cloud acknowledgement: `{ "v": 1, "deviceId": "...", "ackSequence": 123, "acknowledgedAt": 1788143912200 }`.
|
|
41
|
+
|
|
42
|
+
Use MQTT 5 and QoS 1. The state and status topics are retained; telemetry and events are not. Current state publishes before ordered backlog. Broker acknowledgement alone never removes a record: the application acknowledgement follows Wake Logger's durable commit. Live and backlog duplicates are harmless under the device/sequence uniqueness constraint.
|
|
43
|
+
|
|
44
|
+
The broker uses one credential per device, required client-ID binding, default-deny ACLs and access only to that device namespace. Endpoint and certificate topology are cloud-owned and returned during pairing rather than documented here. Require TLS 1.2+, hostname validation and no insecure bypass.
|
|
45
|
+
|
|
46
|
+
### Selected implementation defaults
|
|
47
|
+
|
|
48
|
+
- Keep `OutboxStore` as the boundary. Prefer Signal K's emerging plugin-scoped Database API as a bounded delivery buffer when available, with the native-free segmented file outbox under `app.getDataDirPath()` as the portable fallback. SQLite is not shipped.
|
|
49
|
+
- Persist the backend selection per device. Never silently fall back from database to files because that could reuse a sequence; retain legacy files and select the database only after their pending queue is empty.
|
|
50
|
+
- Keep an independent outbox/sequence space per device ID. Pairing a replacement preserves the retired device's queue locally but never republishes those records under the new authenticated identity.
|
|
51
|
+
- Retry temporary pairing failures at most six times with bounded exponential delays; reject invalid/expired codes immediately and retain the current credential if replacement provisioning fails.
|
|
52
|
+
- Confirm broker revocation through a device-scoped outbound HTTPS status credential and expose `Device revoked — enter a new pairing code`. A local admin-only forget action removes credentials but preserves the consumed-code tombstone, retired outboxes and sequence records.
|
|
53
|
+
- Records are length-prefixed, SHA-256 checksummed and append-only, with synced appends and atomic metadata. Corrupt/incomplete tails are truncated during recovery.
|
|
54
|
+
- Defaults are 4 MiB segments, seven-day/250 MB retention, one-second live samples, batches up to 60 samples and a 64 KiB payload ceiling.
|
|
55
|
+
- Preserve newest data at a limit, report count/range of dropped samples and never crash Signal K. Restore retained current state from the outbox after restart.
|
|
56
|
+
- Start and stop remain safe/idempotent with empty configuration, no credentials, no DNS and no internet. Reconnect uses capped exponential backoff with jitter; authentication failures retain their distinct status and retry every five minutes with jitter so entitlement restoration recovers automatically.
|
|
57
|
+
- The plugin emits start/stop evidence using stable berth-cluster movement, not a moving origin, so slow marina departures are detected. MQTT disconnects never end a tracking session.
|
|
58
|
+
|
|
59
|
+
### Milestones
|
|
60
|
+
|
|
61
|
+
Version 0.2 beta implements the plugin foundation, supported-field normalization, database-preferred durable outbox, pairing contract, MQTT transport, application acknowledgements, private trip evidence, remote telemetry profiles, adaptive transport, expanded status, tests, CI and documentation. Wake Logger cloud/broker/API/UI delivery is implemented in the private Wake Logger repository. Automated CI, packaging and registry preparation gate npm beta publication. Target-hardware multi-day/ARM, real-vessel and measured resource evidence remain separate first-vessel and stable-production gates; the published beta is used to collect them. Remaining evidence is recorded in `original-plan-gap-audit.md`.
|
|
62
|
+
|
|
63
|
+
## 1. Purpose
|
|
64
|
+
|
|
65
|
+
Build a production-quality Signal K plugin that allows a vessel running Signal K to stream live telemetry securely and efficiently to Wake Logger.
|
|
66
|
+
|
|
67
|
+
The plugin will be distributed through the normal Signal K plugin ecosystem and should ultimately be installable from the Signal K AppStore.
|
|
68
|
+
|
|
69
|
+
The plugin is responsible only for **live vessel tracking and resilient live telemetry transport**.
|
|
70
|
+
|
|
71
|
+
It is **not responsible for post-trip or post-race data uploads**. Any separate full-resolution archival upload process is outside this repository and must remain architecturally separate.
|
|
72
|
+
|
|
73
|
+
The plugin must support worldwide vessel tracking and should not contain assumptions tied to a single country, jurisdiction, qualification system, race organisation or regulator.
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
# 2. Primary design goals
|
|
78
|
+
|
|
79
|
+
The plugin must:
|
|
80
|
+
|
|
81
|
+
1. Read selected live data from the local Signal K server.
|
|
82
|
+
2. Convert that data into the Wake Logger live telemetry schema.
|
|
83
|
+
3. Efficiently batch telemetry to minimise bandwidth.
|
|
84
|
+
4. Maintain a durable local outbound queue.
|
|
85
|
+
5. Continue operating while internet connectivity is unavailable.
|
|
86
|
+
6. Automatically reconnect when connectivity returns.
|
|
87
|
+
7. Prioritise current live state after reconnecting.
|
|
88
|
+
8. Drain queued historical live telemetry without overwhelming the available connection.
|
|
89
|
+
9. Publish telemetry over MQTT using TLS.
|
|
90
|
+
10. Use MQTT QoS 1.
|
|
91
|
+
11. prevent duplicate telemetry in Wake Logger through sequence numbers.
|
|
92
|
+
12. Support tracking sessions lasting minutes, hours, days or longer.
|
|
93
|
+
13. Detect probable trip start and trip end events.
|
|
94
|
+
14. Allow the Wake Logger cloud service to provision vessel credentials through a pairing process.
|
|
95
|
+
15. Require no inbound internet connection to the vessel.
|
|
96
|
+
16. Start safely even when Wake Logger credentials or internet connectivity are unavailable.
|
|
97
|
+
17. Be compatible with supported Signal K platforms, particularly Raspberry Pi/ARM installations.
|
|
98
|
+
18. Meet Signal K plugin registry and CI expectations.
|
|
99
|
+
19. Be fully testable without access to a real vessel.
|
|
100
|
+
20. Avoid unnecessary dependencies, particularly architecture-specific native dependencies.
|
|
101
|
+
|
|
102
|
+
---
|
|
103
|
+
|
|
104
|
+
# 3. High-level architecture
|
|
105
|
+
|
|
106
|
+
```text
|
|
107
|
+
NMEA 2000 / NMEA 0183 / other vessel sources
|
|
108
|
+
│
|
|
109
|
+
▼
|
|
110
|
+
Signal K Server
|
|
111
|
+
│
|
|
112
|
+
▼
|
|
113
|
+
signalk-wakelogger
|
|
114
|
+
│
|
|
115
|
+
┌─────────┴─────────┐
|
|
116
|
+
│ │
|
|
117
|
+
▼ ▼
|
|
118
|
+
Signal K subscriber Trip state machine
|
|
119
|
+
│
|
|
120
|
+
▼
|
|
121
|
+
Telemetry normaliser
|
|
122
|
+
│
|
|
123
|
+
▼
|
|
124
|
+
Batcher
|
|
125
|
+
│
|
|
126
|
+
▼
|
|
127
|
+
Durable local outbox
|
|
128
|
+
│
|
|
129
|
+
▼
|
|
130
|
+
MQTT transport
|
|
131
|
+
│
|
|
132
|
+
TLS / QoS 1
|
|
133
|
+
│
|
|
134
|
+
▼
|
|
135
|
+
Internet
|
|
136
|
+
│
|
|
137
|
+
▼
|
|
138
|
+
Wake Logger MQTT broker
|
|
139
|
+
│
|
|
140
|
+
▼
|
|
141
|
+
Telemetry ingestion service
|
|
142
|
+
│
|
|
143
|
+
┌────┴──────────────┐
|
|
144
|
+
▼ ▼
|
|
145
|
+
Current vessel state Historical live telemetry
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
---
|
|
149
|
+
|
|
150
|
+
# 4. Architectural boundaries
|
|
151
|
+
|
|
152
|
+
## Plugin responsibilities
|
|
153
|
+
|
|
154
|
+
The plugin owns:
|
|
155
|
+
|
|
156
|
+
- Signal K subscriptions
|
|
157
|
+
- telemetry sampling
|
|
158
|
+
- telemetry normalisation
|
|
159
|
+
- telemetry batching
|
|
160
|
+
- local sequence numbering
|
|
161
|
+
- local persistent buffering
|
|
162
|
+
- MQTT connectivity
|
|
163
|
+
- TLS transport
|
|
164
|
+
- pairing
|
|
165
|
+
- credential storage
|
|
166
|
+
- connection health
|
|
167
|
+
- trip-state detection
|
|
168
|
+
- transmission retry behaviour
|
|
169
|
+
- live telemetry backlog recovery
|
|
170
|
+
- diagnostic status reporting
|
|
171
|
+
|
|
172
|
+
## Wake Logger cloud responsibilities
|
|
173
|
+
|
|
174
|
+
The cloud owns:
|
|
175
|
+
|
|
176
|
+
- user accounts
|
|
177
|
+
- vessel ownership
|
|
178
|
+
- vessel identities
|
|
179
|
+
- pairing-code generation
|
|
180
|
+
- MQTT credential provisioning
|
|
181
|
+
- MQTT ACLs
|
|
182
|
+
- telemetry validation
|
|
183
|
+
- telemetry deduplication
|
|
184
|
+
- live vessel state
|
|
185
|
+
- historical live telemetry
|
|
186
|
+
- final trip construction
|
|
187
|
+
- trip editing/merging/splitting
|
|
188
|
+
- qualification calculations
|
|
189
|
+
- reporting and analytics
|
|
190
|
+
|
|
191
|
+
The plugin must never attempt to replicate Wake Logger business logic.
|
|
192
|
+
|
|
193
|
+
---
|
|
194
|
+
|
|
195
|
+
# 5. Technology choices
|
|
196
|
+
|
|
197
|
+
## Language
|
|
198
|
+
|
|
199
|
+
Use:
|
|
200
|
+
|
|
201
|
+
```text
|
|
202
|
+
TypeScript
|
|
203
|
+
Node.js
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
Signal K supports Node.js/TypeScript plugins through its Server API.
|
|
207
|
+
|
|
208
|
+
Use:
|
|
209
|
+
|
|
210
|
+
```text
|
|
211
|
+
@signalk/server-api
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
for Signal K types where practical.
|
|
215
|
+
|
|
216
|
+
Signal K currently documents Node.js 20 or later for plugin development.
|
|
217
|
+
|
|
218
|
+
## MQTT client
|
|
219
|
+
|
|
220
|
+
Preferred library:
|
|
221
|
+
|
|
222
|
+
```text
|
|
223
|
+
mqtt
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
MQTT.js supports Node.js, MQTT 5 features and QoS 1.
|
|
227
|
+
|
|
228
|
+
Configure explicitly for MQTT 5 rather than relying on library defaults.
|
|
229
|
+
|
|
230
|
+
## Durable queue
|
|
231
|
+
|
|
232
|
+
Create a storage abstraction:
|
|
233
|
+
|
|
234
|
+
```text
|
|
235
|
+
OutboxStore
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
Do not tightly couple the application architecture to SQLite.
|
|
239
|
+
|
|
240
|
+
Initial implementation should prioritise portability across:
|
|
241
|
+
|
|
242
|
+
- Linux x64
|
|
243
|
+
- Linux ARM64
|
|
244
|
+
- ARMv7
|
|
245
|
+
- Raspberry Pi
|
|
246
|
+
- Signal K Docker deployments
|
|
247
|
+
- Cerbo GX where practical
|
|
248
|
+
|
|
249
|
+
Signal K plugin testing installs packages with lifecycle scripts disabled, and native Node modules can create cross-platform packaging issues.
|
|
250
|
+
|
|
251
|
+
The implementation uses two replaceable approaches:
|
|
252
|
+
|
|
253
|
+
### Option A — Signal K Database API
|
|
254
|
+
|
|
255
|
+
Preferred when the server exposes the emerging plugin-scoped API. Use it only as a bounded write-ahead delivery queue, not as a competing history or Track API.
|
|
256
|
+
|
|
257
|
+
### Option B — file-backed append-only queue
|
|
258
|
+
|
|
259
|
+
Portable fallback.
|
|
260
|
+
|
|
261
|
+
Use:
|
|
262
|
+
|
|
263
|
+
```text
|
|
264
|
+
segmented append-only files
|
|
265
|
+
+
|
|
266
|
+
persistent acknowledgement cursor
|
|
267
|
+
+
|
|
268
|
+
atomic metadata files
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
Advantages:
|
|
272
|
+
|
|
273
|
+
- no native dependencies
|
|
274
|
+
- portable
|
|
275
|
+
- easy to inspect
|
|
276
|
+
- robust on Raspberry Pi
|
|
277
|
+
- simple recovery
|
|
278
|
+
- predictable disk usage
|
|
279
|
+
|
|
280
|
+
Do not ship a native SQLite dependency. The rest of the application interacts only through `OutboxStore`, keeping storage replaceable as Signal K's API evolves.
|
|
281
|
+
|
|
282
|
+
---
|
|
283
|
+
|
|
284
|
+
# 6. Proposed repository structure
|
|
285
|
+
|
|
286
|
+
```text
|
|
287
|
+
signalk-wakelogger/
|
|
288
|
+
│
|
|
289
|
+
├── src/
|
|
290
|
+
│ ├── index.ts
|
|
291
|
+
│ │
|
|
292
|
+
│ ├── config/
|
|
293
|
+
│ │ ├── schema.ts
|
|
294
|
+
│ │ └── defaults.ts
|
|
295
|
+
│ │
|
|
296
|
+
│ ├── signalk/
|
|
297
|
+
│ │ ├── subscriber.ts
|
|
298
|
+
│ │ ├── paths.ts
|
|
299
|
+
│ │ └── normaliser.ts
|
|
300
|
+
│ │
|
|
301
|
+
│ ├── telemetry/
|
|
302
|
+
│ │ ├── types.ts
|
|
303
|
+
│ │ ├── batcher.ts
|
|
304
|
+
│ │ ├── sampler.ts
|
|
305
|
+
│ │ └── encoder.ts
|
|
306
|
+
│ │
|
|
307
|
+
│ ├── transport/
|
|
308
|
+
│ │ ├── mqtt-client.ts
|
|
309
|
+
│ │ ├── reconnect.ts
|
|
310
|
+
│ │ └── connection-state.ts
|
|
311
|
+
│ │
|
|
312
|
+
│ ├── outbox/
|
|
313
|
+
│ │ ├── interface.ts
|
|
314
|
+
│ │ ├── file-outbox.ts
|
|
315
|
+
│ │ └── recovery.ts
|
|
316
|
+
│ │
|
|
317
|
+
│ ├── pairing/
|
|
318
|
+
│ │ ├── pairing-client.ts
|
|
319
|
+
│ │ ├── credentials.ts
|
|
320
|
+
│ │ └── identity.ts
|
|
321
|
+
│ │
|
|
322
|
+
│ ├── trips/
|
|
323
|
+
│ │ ├── state-machine.ts
|
|
324
|
+
│ │ ├── movement.ts
|
|
325
|
+
│ │ └── types.ts
|
|
326
|
+
│ │
|
|
327
|
+
│ ├── status/
|
|
328
|
+
│ │ └── status.ts
|
|
329
|
+
│ │
|
|
330
|
+
│ └── util/
|
|
331
|
+
│ ├── clock.ts
|
|
332
|
+
│ ├── backoff.ts
|
|
333
|
+
│ └── logger.ts
|
|
334
|
+
│
|
|
335
|
+
├── test/
|
|
336
|
+
│ ├── unit/
|
|
337
|
+
│ ├── integration/
|
|
338
|
+
│ ├── fixtures/
|
|
339
|
+
│ └── simulated-vessel/
|
|
340
|
+
│
|
|
341
|
+
├── assets/
|
|
342
|
+
│
|
|
343
|
+
├── docs/
|
|
344
|
+
│ ├── architecture.md
|
|
345
|
+
│ ├── telemetry-protocol.md
|
|
346
|
+
│ ├── trip-detection.md
|
|
347
|
+
│ ├── pairing.md
|
|
348
|
+
│ └── development.md
|
|
349
|
+
│
|
|
350
|
+
├── .github/
|
|
351
|
+
│ └── workflows/
|
|
352
|
+
│ ├── ci.yml
|
|
353
|
+
│ ├── signalk-ci.yml
|
|
354
|
+
│ └── publish.yml
|
|
355
|
+
│
|
|
356
|
+
├── package.json
|
|
357
|
+
├── tsconfig.json
|
|
358
|
+
├── README.md
|
|
359
|
+
├── CHANGELOG.md
|
|
360
|
+
├── CONTRIBUTING.md
|
|
361
|
+
├── SECURITY.md
|
|
362
|
+
└── LICENSE
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
---
|
|
366
|
+
|
|
367
|
+
# 7. Signal K plugin lifecycle
|
|
368
|
+
|
|
369
|
+
The plugin must implement the standard Signal K plugin lifecycle:
|
|
370
|
+
|
|
371
|
+
```text
|
|
372
|
+
id
|
|
373
|
+
name
|
|
374
|
+
schema
|
|
375
|
+
start()
|
|
376
|
+
stop()
|
|
377
|
+
```
|
|
378
|
+
|
|
379
|
+
`start()` must never require a successful internet connection.
|
|
380
|
+
|
|
381
|
+
This is a critical requirement.
|
|
382
|
+
|
|
383
|
+
Valid startup states include:
|
|
384
|
+
|
|
385
|
+
```text
|
|
386
|
+
Not configured
|
|
387
|
+
Configured but not paired
|
|
388
|
+
Paired but offline
|
|
389
|
+
Paired and connecting
|
|
390
|
+
Connected
|
|
391
|
+
```
|
|
392
|
+
|
|
393
|
+
For example:
|
|
394
|
+
|
|
395
|
+
```text
|
|
396
|
+
Signal K starts
|
|
397
|
+
↓
|
|
398
|
+
Wake Logger plugin starts
|
|
399
|
+
↓
|
|
400
|
+
No Wake Logger credentials
|
|
401
|
+
↓
|
|
402
|
+
Plugin status:
|
|
403
|
+
"Not paired"
|
|
404
|
+
```
|
|
405
|
+
|
|
406
|
+
That is a successful plugin startup.
|
|
407
|
+
|
|
408
|
+
Do not throw an exception because:
|
|
409
|
+
|
|
410
|
+
- DNS fails
|
|
411
|
+
- Wake Logger is unavailable
|
|
412
|
+
- MQTT is unavailable
|
|
413
|
+
- credentials are absent
|
|
414
|
+
- vessel has no internet connection
|
|
415
|
+
|
|
416
|
+
Network connectivity is a runtime state, not a plugin lifecycle requirement.
|
|
417
|
+
|
|
418
|
+
---
|
|
419
|
+
|
|
420
|
+
# 8. Initial Signal K subscriptions
|
|
421
|
+
|
|
422
|
+
Create a central path definition file rather than scattering Signal K strings throughout the codebase.
|
|
423
|
+
|
|
424
|
+
Initial candidate paths:
|
|
425
|
+
|
|
426
|
+
```text
|
|
427
|
+
navigation.position
|
|
428
|
+
navigation.speedOverGround
|
|
429
|
+
navigation.courseOverGroundTrue
|
|
430
|
+
navigation.headingTrue
|
|
431
|
+
navigation.headingMagnetic
|
|
432
|
+
|
|
433
|
+
environment.depth.belowTransducer
|
|
434
|
+
|
|
435
|
+
environment.wind.speedApparent
|
|
436
|
+
environment.wind.angleApparent
|
|
437
|
+
```
|
|
438
|
+
|
|
439
|
+
Not every vessel will provide every path.
|
|
440
|
+
|
|
441
|
+
Missing data must be normal behaviour.
|
|
442
|
+
|
|
443
|
+
Do not require depth or wind information for basic tracking. Engine, battery, fuel and tank data are outside the product scope.
|
|
444
|
+
|
|
445
|
+
Minimum useful tracking dataset:
|
|
446
|
+
|
|
447
|
+
```text
|
|
448
|
+
position
|
|
449
|
+
timestamp
|
|
450
|
+
```
|
|
451
|
+
|
|
452
|
+
Preferred:
|
|
453
|
+
|
|
454
|
+
```text
|
|
455
|
+
position
|
|
456
|
+
SOG
|
|
457
|
+
COG
|
|
458
|
+
heading
|
|
459
|
+
```
|
|
460
|
+
|
|
461
|
+
---
|
|
462
|
+
|
|
463
|
+
# 9. Sampling strategy
|
|
464
|
+
|
|
465
|
+
Do not blindly forward every Signal K delta.
|
|
466
|
+
|
|
467
|
+
Implement path-specific sampling.
|
|
468
|
+
|
|
469
|
+
Suggested starting defaults:
|
|
470
|
+
|
|
471
|
+
```text
|
|
472
|
+
Position 1 Hz
|
|
473
|
+
SOG 1 Hz
|
|
474
|
+
COG 1 Hz
|
|
475
|
+
Heading 1 Hz
|
|
476
|
+
Depth 1 Hz
|
|
477
|
+
Wind 1 Hz
|
|
478
|
+
```
|
|
479
|
+
|
|
480
|
+
Sampling rates are remotely configurable through an approved, versioned Wake Logger telemetry profile.
|
|
481
|
+
|
|
482
|
+
Changes should still be captured where appropriate even when the normal sampling period has not elapsed.
|
|
483
|
+
|
|
484
|
+
---
|
|
485
|
+
|
|
486
|
+
# 10. Telemetry batching
|
|
487
|
+
|
|
488
|
+
Do not send one MQTT publication for every Signal K value.
|
|
489
|
+
|
|
490
|
+
Aggregate data into short batches.
|
|
491
|
+
|
|
492
|
+
Initial target:
|
|
493
|
+
|
|
494
|
+
```text
|
|
495
|
+
1 batch per second
|
|
496
|
+
```
|
|
497
|
+
|
|
498
|
+
A batch may contain:
|
|
499
|
+
|
|
500
|
+
```text
|
|
501
|
+
timestamp
|
|
502
|
+
sequence
|
|
503
|
+
position
|
|
504
|
+
SOG
|
|
505
|
+
COG
|
|
506
|
+
heading
|
|
507
|
+
RPM
|
|
508
|
+
depth
|
|
509
|
+
wind
|
|
510
|
+
other changed values
|
|
511
|
+
```
|
|
512
|
+
|
|
513
|
+
Target average bandwidth should be comfortably below:
|
|
514
|
+
|
|
515
|
+
```text
|
|
516
|
+
1 kB/sec per vessel
|
|
517
|
+
```
|
|
518
|
+
|
|
519
|
+
before TLS/TCP overhead.
|
|
520
|
+
|
|
521
|
+
Measure actual bandwidth during testing rather than relying on estimates.
|
|
522
|
+
|
|
523
|
+
---
|
|
524
|
+
|
|
525
|
+
# 11. Telemetry protocol
|
|
526
|
+
|
|
527
|
+
Create a versioned Wake Logger protocol.
|
|
528
|
+
|
|
529
|
+
Example conceptual JSON:
|
|
530
|
+
|
|
531
|
+
```json
|
|
532
|
+
{
|
|
533
|
+
"v": 1,
|
|
534
|
+
"vesselId": "vsl_xxx",
|
|
535
|
+
"sequence": 184291,
|
|
536
|
+
"capturedAt": 1788143912000,
|
|
537
|
+
"trackingSessionId": "trk_xxx",
|
|
538
|
+
"values": {
|
|
539
|
+
"lat": -27.41238,
|
|
540
|
+
"lon": 153.18291,
|
|
541
|
+
"sog": 6.42,
|
|
542
|
+
"cog": 241.3,
|
|
543
|
+
"heading": 238.8
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
```
|
|
547
|
+
|
|
548
|
+
During early development use JSON.
|
|
549
|
+
|
|
550
|
+
This allows:
|
|
551
|
+
|
|
552
|
+
- packet inspection
|
|
553
|
+
- logging
|
|
554
|
+
- test fixture creation
|
|
555
|
+
- rapid protocol changes
|
|
556
|
+
|
|
557
|
+
Do not optimise prematurely.
|
|
558
|
+
|
|
559
|
+
Create an encoder abstraction so CBOR or another compact binary encoding can be introduced later without rewriting transport logic.
|
|
560
|
+
|
|
561
|
+
---
|
|
562
|
+
|
|
563
|
+
# 12. Sequence numbers
|
|
564
|
+
|
|
565
|
+
Each vessel installation must maintain a monotonically increasing telemetry sequence.
|
|
566
|
+
|
|
567
|
+
Sequence numbers survive:
|
|
568
|
+
|
|
569
|
+
```text
|
|
570
|
+
plugin restart
|
|
571
|
+
Signal K restart
|
|
572
|
+
Pi reboot
|
|
573
|
+
MQTT reconnect
|
|
574
|
+
internet outage
|
|
575
|
+
```
|
|
576
|
+
|
|
577
|
+
Example:
|
|
578
|
+
|
|
579
|
+
```text
|
|
580
|
+
392001
|
|
581
|
+
392002
|
|
582
|
+
392003
|
|
583
|
+
...
|
|
584
|
+
```
|
|
585
|
+
|
|
586
|
+
Wake Logger backend should enforce conceptual uniqueness on:
|
|
587
|
+
|
|
588
|
+
```text
|
|
589
|
+
vessel_id + sequence
|
|
590
|
+
```
|
|
591
|
+
|
|
592
|
+
This makes MQTT QoS 1 duplicate delivery harmless.
|
|
593
|
+
|
|
594
|
+
The sequence must be assigned before the telemetry item enters the durable outbox.
|
|
595
|
+
|
|
596
|
+
---
|
|
597
|
+
|
|
598
|
+
# 13. Persistent outbox
|
|
599
|
+
|
|
600
|
+
Data flow:
|
|
601
|
+
|
|
602
|
+
```text
|
|
603
|
+
Telemetry created
|
|
604
|
+
↓
|
|
605
|
+
Sequence assigned
|
|
606
|
+
↓
|
|
607
|
+
Written durably to OutboxStore
|
|
608
|
+
↓
|
|
609
|
+
MQTT publish QoS 1
|
|
610
|
+
↓
|
|
611
|
+
Publish acknowledged
|
|
612
|
+
↓
|
|
613
|
+
Outbox item marked delivered
|
|
614
|
+
↓
|
|
615
|
+
Storage reclaimed later
|
|
616
|
+
```
|
|
617
|
+
|
|
618
|
+
Never use:
|
|
619
|
+
|
|
620
|
+
```text
|
|
621
|
+
create telemetry
|
|
622
|
+
→ publish
|
|
623
|
+
→ save only if publish fails
|
|
624
|
+
```
|
|
625
|
+
|
|
626
|
+
because a crash between creation and publishing could lose data.
|
|
627
|
+
|
|
628
|
+
Persist first.
|
|
629
|
+
|
|
630
|
+
Transmit second.
|
|
631
|
+
|
|
632
|
+
---
|
|
633
|
+
|
|
634
|
+
# 14. Outbox retention
|
|
635
|
+
|
|
636
|
+
The queue must have configurable limits.
|
|
637
|
+
|
|
638
|
+
Suggested initial limits:
|
|
639
|
+
|
|
640
|
+
```text
|
|
641
|
+
Maximum age: 7 days
|
|
642
|
+
Maximum disk use: configurable
|
|
643
|
+
Default disk use: 250 MB
|
|
644
|
+
```
|
|
645
|
+
|
|
646
|
+
Actual limits should be tuned after measuring real data volumes.
|
|
647
|
+
|
|
648
|
+
When limits are reached:
|
|
649
|
+
|
|
650
|
+
1. Never crash Signal K.
|
|
651
|
+
2. Preserve the newest data.
|
|
652
|
+
3. Emit a visible warning.
|
|
653
|
+
4. Record dropped-data metrics.
|
|
654
|
+
5. Remove oldest backlog according to policy.
|
|
655
|
+
|
|
656
|
+
---
|
|
657
|
+
|
|
658
|
+
# 15. MQTT transport
|
|
659
|
+
|
|
660
|
+
Use:
|
|
661
|
+
|
|
662
|
+
```text
|
|
663
|
+
MQTT 5
|
|
664
|
+
TLS
|
|
665
|
+
QoS 1
|
|
666
|
+
```
|
|
667
|
+
|
|
668
|
+
Initial endpoint concept:
|
|
669
|
+
|
|
670
|
+
```text
|
|
671
|
+
mqtt.wakelogger.com:8883
|
|
672
|
+
```
|
|
673
|
+
|
|
674
|
+
Topic structure:
|
|
675
|
+
|
|
676
|
+
```text
|
|
677
|
+
wakelogger/v1/vessels/<vessel-id>/telemetry
|
|
678
|
+
wakelogger/v1/vessels/<vessel-id>/status
|
|
679
|
+
```
|
|
680
|
+
|
|
681
|
+
Potential future topic:
|
|
682
|
+
|
|
683
|
+
```text
|
|
684
|
+
wakelogger/v1/vessels/<vessel-id>/control
|
|
685
|
+
```
|
|
686
|
+
|
|
687
|
+
Do not create a separate MQTT topic for every Signal K path.
|
|
688
|
+
|
|
689
|
+
---
|
|
690
|
+
|
|
691
|
+
# 16. MQTT connection behaviour
|
|
692
|
+
|
|
693
|
+
Implement:
|
|
694
|
+
|
|
695
|
+
```text
|
|
696
|
+
exponential reconnect backoff
|
|
697
|
+
+
|
|
698
|
+
jitter
|
|
699
|
+
+
|
|
700
|
+
upper reconnect limit
|
|
701
|
+
```
|
|
702
|
+
|
|
703
|
+
Example conceptual sequence:
|
|
704
|
+
|
|
705
|
+
```text
|
|
706
|
+
1 sec
|
|
707
|
+
2 sec
|
|
708
|
+
4 sec
|
|
709
|
+
8 sec
|
|
710
|
+
15 sec
|
|
711
|
+
30 sec
|
|
712
|
+
60 sec
|
|
713
|
+
```
|
|
714
|
+
|
|
715
|
+
Avoid synchronised fleet reconnect storms after a server outage.
|
|
716
|
+
|
|
717
|
+
MQTT connectivity must expose states such as:
|
|
718
|
+
|
|
719
|
+
```text
|
|
720
|
+
disabled
|
|
721
|
+
unpaired
|
|
722
|
+
offline
|
|
723
|
+
connecting
|
|
724
|
+
online
|
|
725
|
+
degraded
|
|
726
|
+
```
|
|
727
|
+
|
|
728
|
+
---
|
|
729
|
+
|
|
730
|
+
# 17. Reconnection priorities
|
|
731
|
+
|
|
732
|
+
When connectivity returns after a substantial outage:
|
|
733
|
+
|
|
734
|
+
## Priority 1
|
|
735
|
+
|
|
736
|
+
Publish current vessel state immediately.
|
|
737
|
+
|
|
738
|
+
## Priority 2
|
|
739
|
+
|
|
740
|
+
Continue publishing new live telemetry.
|
|
741
|
+
|
|
742
|
+
## Priority 3
|
|
743
|
+
|
|
744
|
+
Drain historical live backlog.
|
|
745
|
+
|
|
746
|
+
Do not make users wait for hours of queued telemetry before Wake Logger receives the vessel's current location.
|
|
747
|
+
|
|
748
|
+
Backlog draining must be rate limited.
|
|
749
|
+
|
|
750
|
+
Example:
|
|
751
|
+
|
|
752
|
+
```text
|
|
753
|
+
live traffic always has priority
|
|
754
|
+
|
|
755
|
+
unused capacity
|
|
756
|
+
↓
|
|
757
|
+
backlog replay
|
|
758
|
+
```
|
|
759
|
+
|
|
760
|
+
---
|
|
761
|
+
|
|
762
|
+
# 18. Poor connectivity behaviour
|
|
763
|
+
|
|
764
|
+
The plugin should recognise degraded transport.
|
|
765
|
+
|
|
766
|
+
Potential signals:
|
|
767
|
+
|
|
768
|
+
```text
|
|
769
|
+
connection resets
|
|
770
|
+
slow publish acknowledgements
|
|
771
|
+
frequent reconnects
|
|
772
|
+
growing outbox depth
|
|
773
|
+
```
|
|
774
|
+
|
|
775
|
+
Introduce transport states:
|
|
776
|
+
|
|
777
|
+
```text
|
|
778
|
+
NORMAL
|
|
779
|
+
CONSTRAINED
|
|
780
|
+
OFFLINE
|
|
781
|
+
```
|
|
782
|
+
|
|
783
|
+
Under constrained connectivity, reduce lower-priority telemetry rates before reducing essential navigation tracking.
|
|
784
|
+
|
|
785
|
+
Priority order:
|
|
786
|
+
|
|
787
|
+
```text
|
|
788
|
+
1. Position
|
|
789
|
+
2. SOG
|
|
790
|
+
3. COG
|
|
791
|
+
4. Heading
|
|
792
|
+
5. Depth
|
|
793
|
+
6. Apparent wind
|
|
794
|
+
```
|
|
795
|
+
|
|
796
|
+
Do not implement complicated adaptation until basic reliable transport is working.
|
|
797
|
+
|
|
798
|
+
---
|
|
799
|
+
|
|
800
|
+
# 19. Pairing architecture
|
|
801
|
+
|
|
802
|
+
A user should not manually configure MQTT credentials.
|
|
803
|
+
|
|
804
|
+
Desired workflow:
|
|
805
|
+
|
|
806
|
+
```text
|
|
807
|
+
Install Wake Logger plugin
|
|
808
|
+
↓
|
|
809
|
+
Open Signal K Plugin Config
|
|
810
|
+
↓
|
|
811
|
+
Enter Wake Logger pairing code
|
|
812
|
+
↓
|
|
813
|
+
Plugin calls Wake Logger pairing API
|
|
814
|
+
↓
|
|
815
|
+
Wake Logger validates code
|
|
816
|
+
↓
|
|
817
|
+
Plugin receives vessel identity
|
|
818
|
+
and scoped credentials
|
|
819
|
+
↓
|
|
820
|
+
Plugin stores credentials locally
|
|
821
|
+
↓
|
|
822
|
+
MQTT connection begins
|
|
823
|
+
```
|
|
824
|
+
|
|
825
|
+
Pairing codes should:
|
|
826
|
+
|
|
827
|
+
```text
|
|
828
|
+
be short lived
|
|
829
|
+
be single use
|
|
830
|
+
be bound to an authorised Wake Logger account
|
|
831
|
+
```
|
|
832
|
+
|
|
833
|
+
The provisioning API may return:
|
|
834
|
+
|
|
835
|
+
```text
|
|
836
|
+
vesselId
|
|
837
|
+
clientId
|
|
838
|
+
MQTT host
|
|
839
|
+
MQTT port
|
|
840
|
+
credential/certificate
|
|
841
|
+
allowed protocol version
|
|
842
|
+
telemetry profile
|
|
843
|
+
association status URL and scoped token
|
|
844
|
+
```
|
|
845
|
+
|
|
846
|
+
Temporary network, rate-limit and server failures are retried a bounded number of times while the code remains valid. Invalid or expired codes stop immediately. Replacement must be transactional: the old device remains active until new broker provisioning succeeds.
|
|
847
|
+
|
|
848
|
+
Wake Logger Owners/First Mates and site administrators can revoke an association without deleting telemetry history. The plugin confirms revocation through its device-scoped status endpoint and reports a specific status. A Signal K administrator can forget the local credential without deleting retired outboxes or sequence evidence, then enter a new pairing code.
|
|
849
|
+
|
|
850
|
+
Never place production credentials in source code.
|
|
851
|
+
|
|
852
|
+
---
|
|
853
|
+
|
|
854
|
+
# 20. MQTT authorisation
|
|
855
|
+
|
|
856
|
+
Each vessel must have unique credentials.
|
|
857
|
+
|
|
858
|
+
Broker permissions should restrict a vessel to its own namespace.
|
|
859
|
+
|
|
860
|
+
For vessel:
|
|
861
|
+
|
|
862
|
+
```text
|
|
863
|
+
vsl_123
|
|
864
|
+
```
|
|
865
|
+
|
|
866
|
+
allow:
|
|
867
|
+
|
|
868
|
+
```text
|
|
869
|
+
wakelogger/v1/vessels/vsl_123/*
|
|
870
|
+
```
|
|
871
|
+
|
|
872
|
+
deny publishing into another vessel namespace.
|
|
873
|
+
|
|
874
|
+
Credential revocation must be possible from Wake Logger.
|
|
875
|
+
|
|
876
|
+
---
|
|
877
|
+
|
|
878
|
+
# 21. Tracking sessions
|
|
879
|
+
|
|
880
|
+
Tracking sessions must be completely independent of MQTT connections.
|
|
881
|
+
|
|
882
|
+
A tracking session may last:
|
|
883
|
+
|
|
884
|
+
```text
|
|
885
|
+
minutes
|
|
886
|
+
hours
|
|
887
|
+
days
|
|
888
|
+
weeks
|
|
889
|
+
```
|
|
890
|
+
|
|
891
|
+
A vessel may reconnect to MQTT many times during one tracking session.
|
|
892
|
+
|
|
893
|
+
Example:
|
|
894
|
+
|
|
895
|
+
```text
|
|
896
|
+
Tracking session
|
|
897
|
+
──────────────────────────────────────────
|
|
898
|
+
|
|
899
|
+
MQTT #1 ───────X
|
|
900
|
+
|
|
901
|
+
MQTT #2 ───X
|
|
902
|
+
|
|
903
|
+
MQTT #3 ─────────
|
|
904
|
+
|
|
905
|
+
Same tracking session throughout.
|
|
906
|
+
```
|
|
907
|
+
|
|
908
|
+
Never end a tracking session because:
|
|
909
|
+
|
|
910
|
+
```text
|
|
911
|
+
MQTT disconnects
|
|
912
|
+
internet disappears
|
|
913
|
+
Signal K temporarily loses a sensor
|
|
914
|
+
```
|
|
915
|
+
|
|
916
|
+
---
|
|
917
|
+
|
|
918
|
+
# 22. Trip detection
|
|
919
|
+
|
|
920
|
+
Implement a local state machine:
|
|
921
|
+
|
|
922
|
+
```text
|
|
923
|
+
STOPPED
|
|
924
|
+
↓
|
|
925
|
+
START_CANDIDATE
|
|
926
|
+
↓
|
|
927
|
+
MOVING
|
|
928
|
+
↓
|
|
929
|
+
STOP_CANDIDATE
|
|
930
|
+
↓
|
|
931
|
+
STOPPED
|
|
932
|
+
```
|
|
933
|
+
|
|
934
|
+
Initial proposed thresholds:
|
|
935
|
+
|
|
936
|
+
## Start candidate
|
|
937
|
+
|
|
938
|
+
Either:
|
|
939
|
+
|
|
940
|
+
```text
|
|
941
|
+
SOG > 1.5 knots
|
|
942
|
+
```
|
|
943
|
+
|
|
944
|
+
or:
|
|
945
|
+
|
|
946
|
+
```text
|
|
947
|
+
movement > 200 metres from stationary cluster
|
|
948
|
+
```
|
|
949
|
+
|
|
950
|
+
maintained for approximately:
|
|
951
|
+
|
|
952
|
+
```text
|
|
953
|
+
2 minutes
|
|
954
|
+
```
|
|
955
|
+
|
|
956
|
+
When confirmed, backdate the trip start to the first credible movement.
|
|
957
|
+
|
|
958
|
+
## Stop candidate
|
|
959
|
+
|
|
960
|
+
Require:
|
|
961
|
+
|
|
962
|
+
```text
|
|
963
|
+
SOG < 0.5 knots
|
|
964
|
+
```
|
|
965
|
+
|
|
966
|
+
and:
|
|
967
|
+
|
|
968
|
+
```text
|
|
969
|
+
positions remain within approximately 75 metres
|
|
970
|
+
```
|
|
971
|
+
|
|
972
|
+
for:
|
|
973
|
+
|
|
974
|
+
```text
|
|
975
|
+
15 minutes
|
|
976
|
+
```
|
|
977
|
+
|
|
978
|
+
When confirmed, backdate the end to the beginning of the genuine stationary period.
|
|
979
|
+
|
|
980
|
+
These values are starting hypotheses only.
|
|
981
|
+
|
|
982
|
+
They must be tuned using real vessel data.
|
|
983
|
+
|
|
984
|
+
---
|
|
985
|
+
|
|
986
|
+
# 23. Trip evidence
|
|
987
|
+
|
|
988
|
+
Trip events should record why the state machine changed.
|
|
989
|
+
|
|
990
|
+
Example:
|
|
991
|
+
|
|
992
|
+
```json
|
|
993
|
+
{
|
|
994
|
+
"event": "trip_started",
|
|
995
|
+
"effectiveAt": 1788143912000,
|
|
996
|
+
"reason": {
|
|
997
|
+
"distanceMovedMetres": 236,
|
|
998
|
+
"movementDurationSeconds": 132,
|
|
999
|
+
"sogThresholdExceeded": true
|
|
1000
|
+
}
|
|
1001
|
+
}
|
|
1002
|
+
```
|
|
1003
|
+
|
|
1004
|
+
This allows Wake Logger to:
|
|
1005
|
+
|
|
1006
|
+
- audit automatic detection
|
|
1007
|
+
- improve algorithms
|
|
1008
|
+
- explain boundaries
|
|
1009
|
+
- correct incorrect trips
|
|
1010
|
+
- tune thresholds
|
|
1011
|
+
|
|
1012
|
+
---
|
|
1013
|
+
|
|
1014
|
+
# 24. Engine information
|
|
1015
|
+
|
|
1016
|
+
Engine state is not subscribed or transmitted. GPS movement is the universal source, which also keeps engine-off sailing valid.
|
|
1017
|
+
|
|
1018
|
+
---
|
|
1019
|
+
|
|
1020
|
+
# 25. Time handling
|
|
1021
|
+
|
|
1022
|
+
Internally use:
|
|
1023
|
+
|
|
1024
|
+
```text
|
|
1025
|
+
UTC
|
|
1026
|
+
```
|
|
1027
|
+
|
|
1028
|
+
for all timestamps.
|
|
1029
|
+
|
|
1030
|
+
Never use local wall-clock time as the canonical trip timeline.
|
|
1031
|
+
|
|
1032
|
+
The UI may present local vessel/user time later.
|
|
1033
|
+
|
|
1034
|
+
Store source timestamps when supplied by Signal K.
|
|
1035
|
+
|
|
1036
|
+
Also retain local receipt time where useful for diagnosing delays.
|
|
1037
|
+
|
|
1038
|
+
---
|
|
1039
|
+
|
|
1040
|
+
# 26. Plugin status
|
|
1041
|
+
|
|
1042
|
+
The Signal K Admin UI should expose meaningful status.
|
|
1043
|
+
|
|
1044
|
+
Examples:
|
|
1045
|
+
|
|
1046
|
+
```text
|
|
1047
|
+
Wake Logger: Not paired
|
|
1048
|
+
Wake Logger: Connecting
|
|
1049
|
+
Wake Logger: Connected
|
|
1050
|
+
Wake Logger: Offline — 327 queued messages
|
|
1051
|
+
Wake Logger: Connected — replaying backlog
|
|
1052
|
+
Wake Logger: Authentication failed
|
|
1053
|
+
```
|
|
1054
|
+
|
|
1055
|
+
Useful metrics:
|
|
1056
|
+
|
|
1057
|
+
```text
|
|
1058
|
+
connection state
|
|
1059
|
+
last successful publish
|
|
1060
|
+
queue message count
|
|
1061
|
+
queue disk size
|
|
1062
|
+
oldest queued message age
|
|
1063
|
+
current sequence
|
|
1064
|
+
tracking state
|
|
1065
|
+
last position timestamp
|
|
1066
|
+
```
|
|
1067
|
+
|
|
1068
|
+
Never expose secrets in logs or status text.
|
|
1069
|
+
|
|
1070
|
+
---
|
|
1071
|
+
|
|
1072
|
+
# 27. Testing strategy
|
|
1073
|
+
|
|
1074
|
+
Testing is a first-class requirement.
|
|
1075
|
+
|
|
1076
|
+
## Unit tests
|
|
1077
|
+
|
|
1078
|
+
Cover:
|
|
1079
|
+
|
|
1080
|
+
```text
|
|
1081
|
+
telemetry sampling
|
|
1082
|
+
telemetry batching
|
|
1083
|
+
sequence generation
|
|
1084
|
+
outbox persistence
|
|
1085
|
+
outbox recovery
|
|
1086
|
+
MQTT retry logic
|
|
1087
|
+
trip state transitions
|
|
1088
|
+
movement calculations
|
|
1089
|
+
configuration validation
|
|
1090
|
+
protocol encoding
|
|
1091
|
+
credential handling
|
|
1092
|
+
```
|
|
1093
|
+
|
|
1094
|
+
## Crash tests
|
|
1095
|
+
|
|
1096
|
+
Simulate:
|
|
1097
|
+
|
|
1098
|
+
```text
|
|
1099
|
+
process dies after queue write
|
|
1100
|
+
process dies during transmission
|
|
1101
|
+
Signal K restart
|
|
1102
|
+
machine reboot
|
|
1103
|
+
partially written queue segment
|
|
1104
|
+
```
|
|
1105
|
+
|
|
1106
|
+
Data must recover safely.
|
|
1107
|
+
|
|
1108
|
+
## Network tests
|
|
1109
|
+
|
|
1110
|
+
Simulate:
|
|
1111
|
+
|
|
1112
|
+
```text
|
|
1113
|
+
DNS failure
|
|
1114
|
+
broker unavailable
|
|
1115
|
+
TLS failure
|
|
1116
|
+
connection reset
|
|
1117
|
+
30-second outage
|
|
1118
|
+
30-minute outage
|
|
1119
|
+
24-hour outage
|
|
1120
|
+
very slow connection
|
|
1121
|
+
duplicate MQTT delivery
|
|
1122
|
+
out-of-order backlog arrival
|
|
1123
|
+
```
|
|
1124
|
+
|
|
1125
|
+
## Vessel simulation
|
|
1126
|
+
|
|
1127
|
+
Create reusable fixtures covering:
|
|
1128
|
+
|
|
1129
|
+
```text
|
|
1130
|
+
stationary at berth
|
|
1131
|
+
GPS drift at berth
|
|
1132
|
+
slow marina departure
|
|
1133
|
+
normal motor trip
|
|
1134
|
+
sailing trip with engine off
|
|
1135
|
+
brief stop
|
|
1136
|
+
anchoring
|
|
1137
|
+
return to berth
|
|
1138
|
+
poor GPS
|
|
1139
|
+
long tracking session
|
|
1140
|
+
```
|
|
1141
|
+
|
|
1142
|
+
---
|
|
1143
|
+
|
|
1144
|
+
# 28. Signal K development testing
|
|
1145
|
+
|
|
1146
|
+
Agents should maintain a local Signal K development environment.
|
|
1147
|
+
|
|
1148
|
+
Signal K provides sample NMEA 2000 data for plugin development.
|
|
1149
|
+
|
|
1150
|
+
The plugin should also be linkable into a development server using `npm link`.
|
|
1151
|
+
|
|
1152
|
+
No agent should require access to the real vessel for routine development.
|
|
1153
|
+
|
|
1154
|
+
Hardware testing happens only after simulation passes.
|
|
1155
|
+
|
|
1156
|
+
---
|
|
1157
|
+
|
|
1158
|
+
# 29. Continuous integration
|
|
1159
|
+
|
|
1160
|
+
Create normal project CI:
|
|
1161
|
+
|
|
1162
|
+
```text
|
|
1163
|
+
lint
|
|
1164
|
+
typecheck
|
|
1165
|
+
unit tests
|
|
1166
|
+
build
|
|
1167
|
+
npm audit
|
|
1168
|
+
```
|
|
1169
|
+
|
|
1170
|
+
Also use Signal K's reusable plugin CI workflow.
|
|
1171
|
+
|
|
1172
|
+
The Signal K workflow validates plugin behaviour across supported environments including multiple architectures.
|
|
1173
|
+
|
|
1174
|
+
The repository should not merge changes to `main` if:
|
|
1175
|
+
|
|
1176
|
+
```text
|
|
1177
|
+
build fails
|
|
1178
|
+
tests fail
|
|
1179
|
+
Signal K plugin CI fails
|
|
1180
|
+
```
|
|
1181
|
+
|
|
1182
|
+
---
|
|
1183
|
+
|
|
1184
|
+
# 30. Signal K registry compatibility
|
|
1185
|
+
|
|
1186
|
+
The plugin should target a full Signal K registry quality score.
|
|
1187
|
+
|
|
1188
|
+
Registry tests currently evaluate areas including:
|
|
1189
|
+
|
|
1190
|
+
```text
|
|
1191
|
+
installation
|
|
1192
|
+
plugin loading
|
|
1193
|
+
activation
|
|
1194
|
+
configuration schema
|
|
1195
|
+
automated tests
|
|
1196
|
+
npm security audit
|
|
1197
|
+
changelog
|
|
1198
|
+
screenshots
|
|
1199
|
+
core dependency freshness
|
|
1200
|
+
```
|
|
1201
|
+
|
|
1202
|
+
Important:
|
|
1203
|
+
|
|
1204
|
+
The registry executes plugin code in a restricted environment with no network access.
|
|
1205
|
+
|
|
1206
|
+
Therefore:
|
|
1207
|
+
|
|
1208
|
+
```text
|
|
1209
|
+
start()
|
|
1210
|
+
```
|
|
1211
|
+
|
|
1212
|
+
must operate successfully when the Wake Logger cloud service cannot be reached.
|
|
1213
|
+
|
|
1214
|
+
---
|
|
1215
|
+
|
|
1216
|
+
# 31. Dependency policy
|
|
1217
|
+
|
|
1218
|
+
Keep runtime dependencies minimal.
|
|
1219
|
+
|
|
1220
|
+
Before adding a dependency, agents should check:
|
|
1221
|
+
|
|
1222
|
+
```text
|
|
1223
|
+
Is it maintained?
|
|
1224
|
+
Does it work on ARM?
|
|
1225
|
+
Does it require postinstall scripts?
|
|
1226
|
+
Does it compile native code?
|
|
1227
|
+
Does it materially improve the product?
|
|
1228
|
+
Can Node.js already do this?
|
|
1229
|
+
```
|
|
1230
|
+
|
|
1231
|
+
Avoid native modules unless there is a strong reason.
|
|
1232
|
+
|
|
1233
|
+
Do not tightly pin Signal K core dependencies in ways that unnecessarily block current same-major releases.
|
|
1234
|
+
|
|
1235
|
+
---
|
|
1236
|
+
|
|
1237
|
+
# 32. Security requirements
|
|
1238
|
+
|
|
1239
|
+
Never log:
|
|
1240
|
+
|
|
1241
|
+
```text
|
|
1242
|
+
passwords
|
|
1243
|
+
private keys
|
|
1244
|
+
access tokens
|
|
1245
|
+
pairing secrets
|
|
1246
|
+
full credentials
|
|
1247
|
+
```
|
|
1248
|
+
|
|
1249
|
+
Use TLS certificate validation.
|
|
1250
|
+
|
|
1251
|
+
Do not allow:
|
|
1252
|
+
|
|
1253
|
+
```text
|
|
1254
|
+
rejectUnauthorized: false
|
|
1255
|
+
```
|
|
1256
|
+
|
|
1257
|
+
in production.
|
|
1258
|
+
|
|
1259
|
+
Validate data received from pairing APIs.
|
|
1260
|
+
|
|
1261
|
+
Validate plugin configuration.
|
|
1262
|
+
|
|
1263
|
+
Use bounded inputs.
|
|
1264
|
+
|
|
1265
|
+
Ensure telemetry payload size is bounded.
|
|
1266
|
+
|
|
1267
|
+
Include:
|
|
1268
|
+
|
|
1269
|
+
```text
|
|
1270
|
+
SECURITY.md
|
|
1271
|
+
```
|
|
1272
|
+
|
|
1273
|
+
with a vulnerability reporting process before public release.
|
|
1274
|
+
|
|
1275
|
+
---
|
|
1276
|
+
|
|
1277
|
+
# 33. Logging
|
|
1278
|
+
|
|
1279
|
+
Use Signal K's plugin logging facilities.
|
|
1280
|
+
|
|
1281
|
+
Log levels should conceptually include:
|
|
1282
|
+
|
|
1283
|
+
```text
|
|
1284
|
+
status
|
|
1285
|
+
debug
|
|
1286
|
+
warning
|
|
1287
|
+
error
|
|
1288
|
+
```
|
|
1289
|
+
|
|
1290
|
+
Normal operation must not produce excessive logs.
|
|
1291
|
+
|
|
1292
|
+
Avoid per-second telemetry logging except in explicit debug mode.
|
|
1293
|
+
|
|
1294
|
+
---
|
|
1295
|
+
|
|
1296
|
+
# 34. Documentation
|
|
1297
|
+
|
|
1298
|
+
Before first public beta the repository must contain:
|
|
1299
|
+
|
|
1300
|
+
## README
|
|
1301
|
+
|
|
1302
|
+
Cover:
|
|
1303
|
+
|
|
1304
|
+
```text
|
|
1305
|
+
What Wake Logger is
|
|
1306
|
+
What the plugin does
|
|
1307
|
+
Requirements
|
|
1308
|
+
Installation
|
|
1309
|
+
Pairing
|
|
1310
|
+
How live telemetry works
|
|
1311
|
+
Offline behaviour
|
|
1312
|
+
Privacy/data transmitted
|
|
1313
|
+
Troubleshooting
|
|
1314
|
+
Development
|
|
1315
|
+
```
|
|
1316
|
+
|
|
1317
|
+
## architecture.md
|
|
1318
|
+
|
|
1319
|
+
Explain component boundaries.
|
|
1320
|
+
|
|
1321
|
+
## telemetry-protocol.md
|
|
1322
|
+
|
|
1323
|
+
Document every protocol version and field.
|
|
1324
|
+
|
|
1325
|
+
## trip-detection.md
|
|
1326
|
+
|
|
1327
|
+
Document state machine and thresholds.
|
|
1328
|
+
|
|
1329
|
+
## development.md
|
|
1330
|
+
|
|
1331
|
+
Explain:
|
|
1332
|
+
|
|
1333
|
+
```text
|
|
1334
|
+
npm install
|
|
1335
|
+
build
|
|
1336
|
+
test
|
|
1337
|
+
npm link
|
|
1338
|
+
Signal K development setup
|
|
1339
|
+
sample data
|
|
1340
|
+
```
|
|
1341
|
+
|
|
1342
|
+
---
|
|
1343
|
+
|
|
1344
|
+
# 35. Versioning
|
|
1345
|
+
|
|
1346
|
+
Use semantic versioning.
|
|
1347
|
+
|
|
1348
|
+
Suggested milestones:
|
|
1349
|
+
|
|
1350
|
+
```text
|
|
1351
|
+
0.1.0 Signal K subscription prototype
|
|
1352
|
+
0.2.0 MQTT transmission
|
|
1353
|
+
0.3.0 durable offline queue
|
|
1354
|
+
0.4.0 Wake Logger pairing
|
|
1355
|
+
0.5.0 trip detection
|
|
1356
|
+
0.6.0 first vessel beta
|
|
1357
|
+
0.9.0 public release candidate
|
|
1358
|
+
1.0.0 production release
|
|
1359
|
+
```
|
|
1360
|
+
|
|
1361
|
+
Do not treat these as mandatory release numbers if implementation order changes.
|
|
1362
|
+
|
|
1363
|
+
---
|
|
1364
|
+
|
|
1365
|
+
# 36. Publishing
|
|
1366
|
+
|
|
1367
|
+
Eventually publish as an npm package containing:
|
|
1368
|
+
|
|
1369
|
+
```text
|
|
1370
|
+
signalk-node-server-plugin
|
|
1371
|
+
```
|
|
1372
|
+
|
|
1373
|
+
in its package keywords.
|
|
1374
|
+
|
|
1375
|
+
Add appropriate Signal K AppStore metadata including:
|
|
1376
|
+
|
|
1377
|
+
```text
|
|
1378
|
+
display name
|
|
1379
|
+
icon
|
|
1380
|
+
screenshots
|
|
1381
|
+
description
|
|
1382
|
+
```
|
|
1383
|
+
|
|
1384
|
+
Use GitHub Actions to publish releases.
|
|
1385
|
+
|
|
1386
|
+
Prefer npm trusted publishing/OIDC over long-lived npm publishing tokens.
|
|
1387
|
+
|
|
1388
|
+
Do not manually publish production releases from developer machines.
|
|
1389
|
+
|
|
1390
|
+
---
|
|
1391
|
+
|
|
1392
|
+
# 37. Agent workstreams
|
|
1393
|
+
|
|
1394
|
+
The following workstreams can proceed in parallel after the initial contracts are agreed.
|
|
1395
|
+
|
|
1396
|
+
---
|
|
1397
|
+
|
|
1398
|
+
## EPIC 1 — Repository foundation
|
|
1399
|
+
|
|
1400
|
+
### Agent tasks
|
|
1401
|
+
|
|
1402
|
+
- initialise TypeScript configuration
|
|
1403
|
+
- define linting
|
|
1404
|
+
- define test runner
|
|
1405
|
+
- establish directory structure
|
|
1406
|
+
- add Signal K plugin entry point
|
|
1407
|
+
- add package metadata
|
|
1408
|
+
- implement empty configuration schema
|
|
1409
|
+
- add standard CI
|
|
1410
|
+
- add Signal K CI
|
|
1411
|
+
- add README skeleton
|
|
1412
|
+
- add CHANGELOG
|
|
1413
|
+
- add licence
|
|
1414
|
+
- add SECURITY.md
|
|
1415
|
+
|
|
1416
|
+
### Acceptance criteria
|
|
1417
|
+
|
|
1418
|
+
```text
|
|
1419
|
+
npm ci
|
|
1420
|
+
npm run build
|
|
1421
|
+
npm test
|
|
1422
|
+
```
|
|
1423
|
+
|
|
1424
|
+
all succeed.
|
|
1425
|
+
|
|
1426
|
+
Plugin loads in Signal K.
|
|
1427
|
+
|
|
1428
|
+
Plugin starts without configuration.
|
|
1429
|
+
|
|
1430
|
+
Signal K CI passes.
|
|
1431
|
+
|
|
1432
|
+
---
|
|
1433
|
+
|
|
1434
|
+
## EPIC 2 — Signal K data acquisition
|
|
1435
|
+
|
|
1436
|
+
### Agent tasks
|
|
1437
|
+
|
|
1438
|
+
- implement subscription manager wrapper
|
|
1439
|
+
- centralise Signal K paths
|
|
1440
|
+
- capture timestamps
|
|
1441
|
+
- normalise vessel navigation values
|
|
1442
|
+
- implement path-specific sampling
|
|
1443
|
+
- handle missing paths cleanly
|
|
1444
|
+
- build sample-data tests
|
|
1445
|
+
|
|
1446
|
+
### Acceptance criteria
|
|
1447
|
+
|
|
1448
|
+
Given simulated Signal K deltas, the plugin produces deterministic normalised telemetry.
|
|
1449
|
+
|
|
1450
|
+
No network connectivity is required.
|
|
1451
|
+
|
|
1452
|
+
---
|
|
1453
|
+
|
|
1454
|
+
## EPIC 3 — Telemetry protocol
|
|
1455
|
+
|
|
1456
|
+
### Agent tasks
|
|
1457
|
+
|
|
1458
|
+
- define protocol v1
|
|
1459
|
+
- define telemetry types
|
|
1460
|
+
- define sequence behaviour
|
|
1461
|
+
- implement JSON encoder
|
|
1462
|
+
- document protocol
|
|
1463
|
+
- write compatibility tests
|
|
1464
|
+
|
|
1465
|
+
### Acceptance criteria
|
|
1466
|
+
|
|
1467
|
+
The same input always generates schema-valid protocol output.
|
|
1468
|
+
|
|
1469
|
+
Protocol versioning is explicit.
|
|
1470
|
+
|
|
1471
|
+
---
|
|
1472
|
+
|
|
1473
|
+
## EPIC 4 — Persistent outbox
|
|
1474
|
+
|
|
1475
|
+
### Agent tasks
|
|
1476
|
+
|
|
1477
|
+
- define `OutboxStore`
|
|
1478
|
+
- implement file-backed queue
|
|
1479
|
+
- add atomic writes
|
|
1480
|
+
- implement acknowledgement cursor
|
|
1481
|
+
- implement queue recovery
|
|
1482
|
+
- implement disk limits
|
|
1483
|
+
- expose queue statistics
|
|
1484
|
+
- implement crash/restart tests
|
|
1485
|
+
|
|
1486
|
+
### Acceptance criteria
|
|
1487
|
+
|
|
1488
|
+
A simulated process restart loses no acknowledged or unacknowledged state beyond clearly documented guarantees.
|
|
1489
|
+
|
|
1490
|
+
Queue survives reboot/restart.
|
|
1491
|
+
|
|
1492
|
+
---
|
|
1493
|
+
|
|
1494
|
+
## EPIC 5 — MQTT transport
|
|
1495
|
+
|
|
1496
|
+
### Agent tasks
|
|
1497
|
+
|
|
1498
|
+
- implement MQTT 5 client
|
|
1499
|
+
- implement TLS
|
|
1500
|
+
- QoS 1 publishing
|
|
1501
|
+
- connection state
|
|
1502
|
+
- reconnect backoff
|
|
1503
|
+
- jitter
|
|
1504
|
+
- publish acknowledgement handling
|
|
1505
|
+
- Last Will/status
|
|
1506
|
+
- graceful shutdown
|
|
1507
|
+
- integration tests using a local broker
|
|
1508
|
+
|
|
1509
|
+
### Acceptance criteria
|
|
1510
|
+
|
|
1511
|
+
Telemetry is removed from the outbox only after successful publication acknowledgement.
|
|
1512
|
+
|
|
1513
|
+
Broker outages do not crash the plugin.
|
|
1514
|
+
|
|
1515
|
+
---
|
|
1516
|
+
|
|
1517
|
+
## EPIC 6 — Reconnect and backlog recovery
|
|
1518
|
+
|
|
1519
|
+
### Agent tasks
|
|
1520
|
+
|
|
1521
|
+
- current-state priority publishing
|
|
1522
|
+
- live-vs-backlog scheduler
|
|
1523
|
+
- backlog throttling
|
|
1524
|
+
- duplicate safety
|
|
1525
|
+
- connection health metrics
|
|
1526
|
+
- degraded-network tests
|
|
1527
|
+
|
|
1528
|
+
### Acceptance criteria
|
|
1529
|
+
|
|
1530
|
+
After a simulated one-hour outage:
|
|
1531
|
+
|
|
1532
|
+
1. current vessel position appears first
|
|
1533
|
+
2. new live data continues
|
|
1534
|
+
3. historical backlog drains afterwards
|
|
1535
|
+
4. no telemetry sequence is lost
|
|
1536
|
+
5. duplicate delivery is safe
|
|
1537
|
+
|
|
1538
|
+
---
|
|
1539
|
+
|
|
1540
|
+
## EPIC 7 — Pairing
|
|
1541
|
+
|
|
1542
|
+
### Agent tasks
|
|
1543
|
+
|
|
1544
|
+
- pairing API contract
|
|
1545
|
+
- pairing-code configuration
|
|
1546
|
+
- credential persistence
|
|
1547
|
+
- credential replacement
|
|
1548
|
+
- credential revocation handling
|
|
1549
|
+
- bounded retry and invalid-code handling
|
|
1550
|
+
- local credential-forget action with retained device state
|
|
1551
|
+
- authentication error states
|
|
1552
|
+
- status reporting
|
|
1553
|
+
|
|
1554
|
+
### Acceptance criteria
|
|
1555
|
+
|
|
1556
|
+
A newly installed plugin can move through:
|
|
1557
|
+
|
|
1558
|
+
```text
|
|
1559
|
+
unpaired
|
|
1560
|
+
→ pairing
|
|
1561
|
+
→ provisioned
|
|
1562
|
+
→ connected
|
|
1563
|
+
```
|
|
1564
|
+
|
|
1565
|
+
without manual MQTT configuration. Temporary service failures show a bounded retry state; confirmed revocation shows `Device revoked — enter a new pairing code`; forgetting local credentials preserves retired outboxes and requires a fresh code.
|
|
1566
|
+
|
|
1567
|
+
---
|
|
1568
|
+
|
|
1569
|
+
## EPIC 8 — Trip detection
|
|
1570
|
+
|
|
1571
|
+
### Agent tasks
|
|
1572
|
+
|
|
1573
|
+
- movement-distance calculations
|
|
1574
|
+
- stationary cluster logic
|
|
1575
|
+
- trip state machine
|
|
1576
|
+
- start dwell timer
|
|
1577
|
+
- stop dwell timer
|
|
1578
|
+
- trip event generation
|
|
1579
|
+
- state persistence
|
|
1580
|
+
- simulated voyage tests
|
|
1581
|
+
|
|
1582
|
+
### Acceptance criteria
|
|
1583
|
+
|
|
1584
|
+
The simulation suite correctly distinguishes:
|
|
1585
|
+
|
|
1586
|
+
```text
|
|
1587
|
+
GPS drift
|
|
1588
|
+
real departure
|
|
1589
|
+
temporary stop
|
|
1590
|
+
anchoring
|
|
1591
|
+
arrival
|
|
1592
|
+
engine-off sailing
|
|
1593
|
+
```
|
|
1594
|
+
|
|
1595
|
+
according to documented rules.
|
|
1596
|
+
|
|
1597
|
+
---
|
|
1598
|
+
|
|
1599
|
+
## EPIC 9 — Plugin UI/status
|
|
1600
|
+
|
|
1601
|
+
### Agent tasks
|
|
1602
|
+
|
|
1603
|
+
- configuration schema
|
|
1604
|
+
- pairing input
|
|
1605
|
+
- status messages
|
|
1606
|
+
- queue metrics
|
|
1607
|
+
- connection information
|
|
1608
|
+
- basic troubleshooting feedback
|
|
1609
|
+
|
|
1610
|
+
### Acceptance criteria
|
|
1611
|
+
|
|
1612
|
+
A vessel operator can determine whether the plugin is:
|
|
1613
|
+
|
|
1614
|
+
```text
|
|
1615
|
+
paired
|
|
1616
|
+
connected
|
|
1617
|
+
offline
|
|
1618
|
+
buffering
|
|
1619
|
+
replaying
|
|
1620
|
+
faulted
|
|
1621
|
+
```
|
|
1622
|
+
|
|
1623
|
+
without reading server logs.
|
|
1624
|
+
|
|
1625
|
+
---
|
|
1626
|
+
|
|
1627
|
+
## EPIC 10 — Production hardening
|
|
1628
|
+
|
|
1629
|
+
### Agent tasks
|
|
1630
|
+
|
|
1631
|
+
- dependency audit
|
|
1632
|
+
- memory testing
|
|
1633
|
+
- CPU testing
|
|
1634
|
+
- long-duration testing
|
|
1635
|
+
- storage-limit testing
|
|
1636
|
+
- fuzz malformed input
|
|
1637
|
+
- log review
|
|
1638
|
+
- secret review
|
|
1639
|
+
- platform testing
|
|
1640
|
+
- documentation completion
|
|
1641
|
+
|
|
1642
|
+
### Acceptance criteria
|
|
1643
|
+
|
|
1644
|
+
Run simulated tracking continuously for at least several days while introducing repeated outages and restarts.
|
|
1645
|
+
|
|
1646
|
+
No uncontrolled queue growth.
|
|
1647
|
+
|
|
1648
|
+
No memory growth.
|
|
1649
|
+
|
|
1650
|
+
No crashes.
|
|
1651
|
+
|
|
1652
|
+
No credentials in logs.
|
|
1653
|
+
|
|
1654
|
+
---
|
|
1655
|
+
|
|
1656
|
+
# 38. Agent development rules
|
|
1657
|
+
|
|
1658
|
+
All agents working in this repository should follow these rules.
|
|
1659
|
+
|
|
1660
|
+
## Rule 1
|
|
1661
|
+
|
|
1662
|
+
Do not alter protocol contracts silently.
|
|
1663
|
+
|
|
1664
|
+
Changes to telemetry protocol must update:
|
|
1665
|
+
|
|
1666
|
+
```text
|
|
1667
|
+
telemetry-protocol.md
|
|
1668
|
+
tests
|
|
1669
|
+
protocol version where required
|
|
1670
|
+
```
|
|
1671
|
+
|
|
1672
|
+
## Rule 2
|
|
1673
|
+
|
|
1674
|
+
Do not introduce Wake Logger cloud business logic into this repository.
|
|
1675
|
+
|
|
1676
|
+
## Rule 3
|
|
1677
|
+
|
|
1678
|
+
Do not combine post-trip archival uploads with live telemetry.
|
|
1679
|
+
|
|
1680
|
+
## Rule 4
|
|
1681
|
+
|
|
1682
|
+
Internet outages are normal operating conditions, not exceptional failures.
|
|
1683
|
+
|
|
1684
|
+
## Rule 5
|
|
1685
|
+
|
|
1686
|
+
Signal K sensors and paths may disappear at any time.
|
|
1687
|
+
|
|
1688
|
+
## Rule 6
|
|
1689
|
+
|
|
1690
|
+
Never assume engine information exists.
|
|
1691
|
+
|
|
1692
|
+
## Rule 7
|
|
1693
|
+
|
|
1694
|
+
Never assume one vessel timezone.
|
|
1695
|
+
|
|
1696
|
+
## Rule 8
|
|
1697
|
+
|
|
1698
|
+
Never assume one jurisdiction.
|
|
1699
|
+
|
|
1700
|
+
## Rule 9
|
|
1701
|
+
|
|
1702
|
+
Never require inbound connectivity to the vessel.
|
|
1703
|
+
|
|
1704
|
+
## Rule 10
|
|
1705
|
+
|
|
1706
|
+
Do not introduce a native runtime dependency without demonstrating Signal K CI compatibility.
|
|
1707
|
+
|
|
1708
|
+
## Rule 11
|
|
1709
|
+
|
|
1710
|
+
Tests accompany functional changes.
|
|
1711
|
+
|
|
1712
|
+
## Rule 12
|
|
1713
|
+
|
|
1714
|
+
`start()` and `stop()` must remain safe and idempotent.
|
|
1715
|
+
|
|
1716
|
+
## Rule 13
|
|
1717
|
+
|
|
1718
|
+
Do not expose secrets.
|
|
1719
|
+
|
|
1720
|
+
## Rule 14
|
|
1721
|
+
|
|
1722
|
+
Keep bandwidth measurable and intentional.
|
|
1723
|
+
|
|
1724
|
+
## Rule 15
|
|
1725
|
+
|
|
1726
|
+
Prioritise reliability and recoverability over clever optimisation.
|
|
1727
|
+
|
|
1728
|
+
---
|
|
1729
|
+
|
|
1730
|
+
# 39. Recommended initial development sequence
|
|
1731
|
+
|
|
1732
|
+
Agents should not try to build everything simultaneously.
|
|
1733
|
+
|
|
1734
|
+
### Phase 1
|
|
1735
|
+
|
|
1736
|
+
```text
|
|
1737
|
+
Repo foundation
|
|
1738
|
+
Signal K plugin skeleton
|
|
1739
|
+
Signal K subscriptions
|
|
1740
|
+
Simulation fixtures
|
|
1741
|
+
```
|
|
1742
|
+
|
|
1743
|
+
### Phase 2
|
|
1744
|
+
|
|
1745
|
+
```text
|
|
1746
|
+
Telemetry protocol
|
|
1747
|
+
Sampling
|
|
1748
|
+
Batching
|
|
1749
|
+
Sequence numbers
|
|
1750
|
+
```
|
|
1751
|
+
|
|
1752
|
+
### Phase 3
|
|
1753
|
+
|
|
1754
|
+
```text
|
|
1755
|
+
Persistent outbox
|
|
1756
|
+
Crash recovery
|
|
1757
|
+
```
|
|
1758
|
+
|
|
1759
|
+
### Phase 4
|
|
1760
|
+
|
|
1761
|
+
```text
|
|
1762
|
+
MQTT
|
|
1763
|
+
TLS
|
|
1764
|
+
QoS 1
|
|
1765
|
+
Reconnect behaviour
|
|
1766
|
+
```
|
|
1767
|
+
|
|
1768
|
+
### Phase 5
|
|
1769
|
+
|
|
1770
|
+
```text
|
|
1771
|
+
Wake Logger ingestion integration
|
|
1772
|
+
Pairing
|
|
1773
|
+
```
|
|
1774
|
+
|
|
1775
|
+
### Phase 6
|
|
1776
|
+
|
|
1777
|
+
```text
|
|
1778
|
+
Long outage handling
|
|
1779
|
+
Backlog scheduling
|
|
1780
|
+
```
|
|
1781
|
+
|
|
1782
|
+
### Phase 7
|
|
1783
|
+
|
|
1784
|
+
```text
|
|
1785
|
+
Trip detection
|
|
1786
|
+
```
|
|
1787
|
+
|
|
1788
|
+
### Phase 8
|
|
1789
|
+
|
|
1790
|
+
```text
|
|
1791
|
+
Real Raspberry Pi / Signal K vessel test
|
|
1792
|
+
```
|
|
1793
|
+
|
|
1794
|
+
### Phase 9
|
|
1795
|
+
|
|
1796
|
+
```text
|
|
1797
|
+
Public beta
|
|
1798
|
+
Signal K registry
|
|
1799
|
+
npm/AppStore release
|
|
1800
|
+
```
|
|
1801
|
+
|
|
1802
|
+
---
|
|
1803
|
+
|
|
1804
|
+
# 40. First implementation milestone
|
|
1805
|
+
|
|
1806
|
+
The first genuinely useful milestone should be:
|
|
1807
|
+
|
|
1808
|
+
```text
|
|
1809
|
+
Signal K sample NMEA 2000 data
|
|
1810
|
+
↓
|
|
1811
|
+
signalk-wakelogger
|
|
1812
|
+
↓
|
|
1813
|
+
position + SOG + COG
|
|
1814
|
+
↓
|
|
1815
|
+
1-second batches
|
|
1816
|
+
↓
|
|
1817
|
+
persistent outbox
|
|
1818
|
+
↓
|
|
1819
|
+
MQTT QoS 1
|
|
1820
|
+
↓
|
|
1821
|
+
local test broker
|
|
1822
|
+
↓
|
|
1823
|
+
test Wake Logger ingestion endpoint
|
|
1824
|
+
```
|
|
1825
|
+
|
|
1826
|
+
Do not begin with:
|
|
1827
|
+
|
|
1828
|
+
```text
|
|
1829
|
+
pairing UI
|
|
1830
|
+
adaptive bandwidth
|
|
1831
|
+
binary encoding
|
|
1832
|
+
complex trip detection
|
|
1833
|
+
full vessel telemetry
|
|
1834
|
+
```
|
|
1835
|
+
|
|
1836
|
+
until this core pipeline works reliably.
|
|
1837
|
+
|
|
1838
|
+
---
|
|
1839
|
+
|
|
1840
|
+
# 41. Definition of first-vessel-ready
|
|
1841
|
+
|
|
1842
|
+
The plugin is ready for installation on the first real vessel when all of the following are true:
|
|
1843
|
+
|
|
1844
|
+
- Signal K CI passes.
|
|
1845
|
+
- Plugin starts without internet.
|
|
1846
|
+
- Plugin starts without Wake Logger credentials.
|
|
1847
|
+
- Position/SOG/COG are captured correctly.
|
|
1848
|
+
- Telemetry survives Signal K restart.
|
|
1849
|
+
- Telemetry survives Pi restart.
|
|
1850
|
+
- MQTT disconnect/reconnect works.
|
|
1851
|
+
- A 30-minute outage produces no unintended telemetry loss.
|
|
1852
|
+
- Current position is prioritised when connectivity returns.
|
|
1853
|
+
- Backlog drains without blocking live telemetry.
|
|
1854
|
+
- QoS duplicates are handled.
|
|
1855
|
+
- Queue disk limits operate.
|
|
1856
|
+
- No secrets appear in logs.
|
|
1857
|
+
- CPU usage is acceptable on Raspberry Pi.
|
|
1858
|
+
- Memory usage remains stable.
|
|
1859
|
+
- Bandwidth usage has been measured.
|
|
1860
|
+
- Plugin status clearly reflects connection and queue state.
|
|
1861
|
+
|
|
1862
|
+
---
|
|
1863
|
+
|
|
1864
|
+
# 42. Definition of public-release-ready
|
|
1865
|
+
|
|
1866
|
+
Before `1.0.0`:
|
|
1867
|
+
|
|
1868
|
+
- Complete README.
|
|
1869
|
+
- Complete architecture documentation.
|
|
1870
|
+
- Complete telemetry protocol documentation.
|
|
1871
|
+
- Complete trip detection documentation.
|
|
1872
|
+
- Screenshots available.
|
|
1873
|
+
- Changelog current.
|
|
1874
|
+
- Security policy available.
|
|
1875
|
+
- npm audit acceptable.
|
|
1876
|
+
- Signal K registry score reviewed.
|
|
1877
|
+
- Signal K CI green.
|
|
1878
|
+
- ARM testing completed.
|
|
1879
|
+
- Real vessel testing completed.
|
|
1880
|
+
- Multi-day session testing completed.
|
|
1881
|
+
- Poor-connectivity testing completed.
|
|
1882
|
+
- Wake Logger pairing operational.
|
|
1883
|
+
- Credential revocation tested.
|
|
1884
|
+
- MQTT ACL isolation tested.
|
|
1885
|
+
- Upgrade from previous plugin version tested.
|
|
1886
|
+
- Plugin uninstall/reinstall behaviour understood.
|
|
1887
|
+
- Privacy/data-transmission documentation complete.
|
|
1888
|
+
|
|
1889
|
+
---
|
|
1890
|
+
|
|
1891
|
+
# 43. Non-goals for version 1
|
|
1892
|
+
|
|
1893
|
+
Do not allow scope creep into:
|
|
1894
|
+
|
|
1895
|
+
- full NMEA 2000 archival
|
|
1896
|
+
- CAN-frame uploads
|
|
1897
|
+
- historical file uploads
|
|
1898
|
+
- chart plotting
|
|
1899
|
+
- navigation planning
|
|
1900
|
+
- autopilot control
|
|
1901
|
+
- vessel control commands
|
|
1902
|
+
- remote Signal K administration
|
|
1903
|
+
- generic MQTT bridging
|
|
1904
|
+
- Signal K replacement
|
|
1905
|
+
- qualification calculations inside the plugin
|
|
1906
|
+
- country-specific regulatory logic
|
|
1907
|
+
|
|
1908
|
+
Those belong elsewhere.
|
|
1909
|
+
|
|
1910
|
+
---
|
|
1911
|
+
|
|
1912
|
+
# 44. Product principle
|
|
1913
|
+
|
|
1914
|
+
The plugin should eventually feel almost invisible.
|
|
1915
|
+
|
|
1916
|
+
Ideal vessel-owner experience:
|
|
1917
|
+
|
|
1918
|
+
```text
|
|
1919
|
+
Install Wake Logger
|
|
1920
|
+
↓
|
|
1921
|
+
Enter pairing code
|
|
1922
|
+
↓
|
|
1923
|
+
Connected
|
|
1924
|
+
```
|
|
1925
|
+
|
|
1926
|
+
Everything else:
|
|
1927
|
+
|
|
1928
|
+
```text
|
|
1929
|
+
MQTT
|
|
1930
|
+
TLS
|
|
1931
|
+
queue management
|
|
1932
|
+
retries
|
|
1933
|
+
sampling
|
|
1934
|
+
protocol versions
|
|
1935
|
+
outages
|
|
1936
|
+
backlog recovery
|
|
1937
|
+
```
|
|
1938
|
+
|
|
1939
|
+
should happen automatically.
|
|
1940
|
+
|
|
1941
|
+
The success criterion is not merely that telemetry works on perfect Wi-Fi.
|
|
1942
|
+
|
|
1943
|
+
The success criterion is that the vessel can move between good cellular coverage, poor coverage and no coverage for extended periods, and Wake Logger still reconstructs an accurate, ordered tracking timeline once communication becomes available again.
|