@noforeignland/signalk-to-noforeignland 1.1.0-beta.2 → 1.1.0-beta.3
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 +6 -5
- package/PROJECT_STRUCTURE.md +357 -0
- package/README.md +6 -3
- package/doc/dev +0 -0
- package/lib/HealthMonitor.js +6 -6
- package/lib/TrackLogger.js +3 -3
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
1.1.0
|
|
2
2
|
* CHANGE: Refactored Project structure, see PROJECT_STRUCTURE.md
|
|
3
|
+
* CHANGE: Use phrase GNSS instead of GPS - Thanks Piotr
|
|
3
4
|
|
|
4
5
|
1.0.1
|
|
5
6
|
* CHANGE: Cleanup previous installs and migrate plugin config, removes depricated old plugins.
|
|
@@ -27,17 +28,17 @@ The "new" one has to be installed once manually, after that everything is back t
|
|
|
27
28
|
0.1.29-beta.1
|
|
28
29
|
* CHANGE: After talking to Treppo from Sugnal K core team we should use the data path "noforeignland.*", code and docs changed.
|
|
29
30
|
* CHANGE: README.md info added and format optimized
|
|
30
|
-
* CHANGE:
|
|
31
|
+
* CHANGE: GNSS source at the end for setPluginStatus - Cerbo has a long source name and truncates it.
|
|
31
32
|
* CHANGE: Use "npm install instead" of "npm ci" to push from Github to npmjs using OIDC authentication
|
|
32
33
|
* CHANGE: Moved navigation.position source from path noforeignland.status to noforeignland.source
|
|
33
34
|
|
|
34
35
|
0.1.28
|
|
35
|
-
* BUGFIX: No
|
|
36
|
+
* BUGFIX: No GNSS data found - introduced in 0.1.27 - Thanks Piotr
|
|
36
37
|
|
|
37
38
|
0.1.28-beta.2
|
|
38
39
|
* EXPERIMENTAL: Signal K data path to visualize the plugin behaviour or error in Node Red, KIP, etc. Using plugin.signalk-to-noforeignland.* for now. See README.md for details.
|
|
39
40
|
* CHANGE: Using app.getDataDirPath() to store transient data, thanks Jeremy, they are now in "plugin-config-data/signalk-to-noforeignland/nfl-track" and renamed to pending.json1 and sent.json1
|
|
40
|
-
* CHANGE: Optimize
|
|
41
|
+
* CHANGE: Optimize GNSS detection if multiple navigation.position from different sources exist.
|
|
41
42
|
* CHANGE: PluginStatus optimized for limited space available.
|
|
42
43
|
* CHANGE: doc/beta_install.md changed for new file structure.
|
|
43
44
|
|
|
@@ -49,13 +50,13 @@ The "new" one has to be installed once manually, after that everything is back t
|
|
|
49
50
|
|
|
50
51
|
0.1.27-beta.1
|
|
51
52
|
* NEW: NPMJS requires new method for publishing. The old tokens will expire Nov 19th, 2025, so moving to OIDC authentication.
|
|
52
|
-
* NEW: Check the
|
|
53
|
+
* NEW: Check the GNSS status in navigation.position, else retry and throw PluginError on Dashboard
|
|
53
54
|
* CHANGE: Keep track data on disk rewritten and migrate old files to new structure, so nfl-track-sent.jsonl becomes a continuous archive of all sent track data over time, when enabled. New Logic:
|
|
54
55
|
* New points accumulate in nfl-track-pending.jsonl
|
|
55
56
|
* Send succeeds → API confirms receipt
|
|
56
57
|
* If keepFiles=true: The content of pending file is appended to nfl-track-sent.jsonl (line 588)
|
|
57
58
|
* Pending file is deleted
|
|
58
|
-
* Next
|
|
59
|
+
* Next GNSS points → create a new pending file
|
|
59
60
|
* Next successful send → appends again to the same nfl-track-sent.jsonl
|
|
60
61
|
|
|
61
62
|
0.1.26
|
package/PROJECT_STRUCTURE.md
CHANGED
|
@@ -0,0 +1,357 @@
|
|
|
1
|
+
# Project Structure
|
|
2
|
+
|
|
3
|
+
This document describes the architecture and organization of the SignalK to Noforeignland plugin.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
This plugin follows a modular architecture where each responsibility is encapsulated in a dedicated module. The main orchestrator ([index.js](index.js)) coordinates all modules through a class-based approach.
|
|
8
|
+
|
|
9
|
+
## Directory Layout
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
nfl-signalk/
|
|
13
|
+
index.js # Main plugin entry point & orchestrator
|
|
14
|
+
cleanup-old-plugin.js # Postinstall script for removing old versions
|
|
15
|
+
package.json # NPM package configuration
|
|
16
|
+
lib/ # Core modules directory
|
|
17
|
+
ConfigManager.js # Configuration handling & migration
|
|
18
|
+
TrackLogger.js # Position subscription & logging
|
|
19
|
+
TrackSender.js # API communication & track sending
|
|
20
|
+
HealthMonitor.js # Position data health checks
|
|
21
|
+
PluginCleanup.js # Runtime cleanup of old plugins
|
|
22
|
+
TrackMigration.js # Track file migration utilities
|
|
23
|
+
DataPathEmitter.js # SignalK delta emission
|
|
24
|
+
DirectoryUtils.js # File system utilities
|
|
25
|
+
README.md # User documentation
|
|
26
|
+
CHANGELOG.md # Version history
|
|
27
|
+
PROJECT_STRUCTURE.md # This file
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Module Responsibilities
|
|
31
|
+
|
|
32
|
+
### Core Orchestrator
|
|
33
|
+
|
|
34
|
+
#### [index.js](index.js)
|
|
35
|
+
**Purpose**: Main plugin class that orchestrates all modules and implements SignalK plugin lifecycle.
|
|
36
|
+
|
|
37
|
+
**Key Responsibilities**:
|
|
38
|
+
- Exports SignalK plugin object with `start()` and `stop()` methods
|
|
39
|
+
- Initializes all module instances in correct order
|
|
40
|
+
- Manages plugin state (options, upSince, cron, lastSuccessfulTransfer)
|
|
41
|
+
- Coordinates between modules during startup sequence
|
|
42
|
+
- Handles plugin status and error reporting to SignalK UI
|
|
43
|
+
- Implements CRON-based interval for data sending
|
|
44
|
+
|
|
45
|
+
**Key Methods**:
|
|
46
|
+
- `start(options, restartPlugin)`: 13-step startup sequence
|
|
47
|
+
- `stop()`: Cleanup and shutdown
|
|
48
|
+
- `interval()`: CRON job handler for sending tracks
|
|
49
|
+
- `handleSavePoint(lastPosition)`: Callback when track point is saved
|
|
50
|
+
- `handleHealthy()`: Callback when health check passes
|
|
51
|
+
- `setPluginStatus(status)`: Update UI status
|
|
52
|
+
- `setPluginError(error)`: Report error to UI
|
|
53
|
+
|
|
54
|
+
### Configuration & Migration
|
|
55
|
+
|
|
56
|
+
#### [lib/ConfigManager.js](lib/ConfigManager.js)
|
|
57
|
+
**Purpose**: Handles plugin configuration, schema definition, and config migration.
|
|
58
|
+
|
|
59
|
+
**Key Responsibilities**:
|
|
60
|
+
- Defines plugin schema (mandatory/advanced/expert settings groups)
|
|
61
|
+
- Migrates old flat config structure to new nested structure
|
|
62
|
+
- Flattens nested config back to internal format with defaults
|
|
63
|
+
- Validates boat API key
|
|
64
|
+
- Resolves track directory paths (absolute vs relative)
|
|
65
|
+
- Randomizes CRON schedule to avoid server load spikes
|
|
66
|
+
|
|
67
|
+
**Config Structure**:
|
|
68
|
+
```javascript
|
|
69
|
+
{
|
|
70
|
+
mandatory: { boatApiKey: string },
|
|
71
|
+
advanced: { minMove, minSpeed, sendWhileMoving, ping_api_every_24h },
|
|
72
|
+
expert: { filterSource, trackDir, keepFiles, trackFrequency, apiCron,
|
|
73
|
+
internetTestTimeout, apiTimeout }
|
|
74
|
+
}
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### Position Tracking
|
|
78
|
+
|
|
79
|
+
#### [lib/TrackLogger.js](lib/TrackLogger.js)
|
|
80
|
+
**Purpose**: Subscribes to position updates and logs them to disk.
|
|
81
|
+
|
|
82
|
+
**Key Responsibilities**:
|
|
83
|
+
- Subscribes to `navigation.position` and optionally `navigation.speedOverGround`
|
|
84
|
+
- Implements GNSS source auto-selection (stick to one source unless stale)
|
|
85
|
+
- Supports manual source filtering via `filterSource` config
|
|
86
|
+
- Validates positions (rejects coordinates near 0,0)
|
|
87
|
+
- Applies movement filters (minSpeed, minMove, trackFrequency)
|
|
88
|
+
- Implements 24-hour keepalive ping
|
|
89
|
+
- Saves track points to JSONL file (`pending.jsonl`)
|
|
90
|
+
- Calculates distances using equirectangular approximation
|
|
91
|
+
|
|
92
|
+
**GNSS Source Logic**:
|
|
93
|
+
- If `filterSource` is set: only accept that specific source
|
|
94
|
+
- If not set: auto-select first source, switch only if stale (>5 min)
|
|
95
|
+
- Prevents position jumps when multiple GNSS devices are present
|
|
96
|
+
|
|
97
|
+
**Track Point Format**:
|
|
98
|
+
```json
|
|
99
|
+
{"lat": 37.8136, "lon": -122.4784, "t": "2025-01-15T10:30:00.000Z"}
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
#### [lib/TrackSender.js](lib/TrackSender.js)
|
|
103
|
+
**Purpose**: Sends accumulated track data to the Noforeignland API.
|
|
104
|
+
|
|
105
|
+
**Key Responsibilities**:
|
|
106
|
+
- Reads track points from `pending.jsonl`
|
|
107
|
+
- Tests internet connectivity via DNS lookups (8.8.8.8, 1.1.1.1)
|
|
108
|
+
- Checks if boat is moving (based on last position timestamp)
|
|
109
|
+
- Sends track data to NFL API with retry logic (3 attempts)
|
|
110
|
+
- Handles successful sends (archive to `sent.jsonl` or delete)
|
|
111
|
+
- Validates position coordinates before sending
|
|
112
|
+
|
|
113
|
+
**API Request Format**:
|
|
114
|
+
```javascript
|
|
115
|
+
POST https://www.noforeignland.com/home/api/v1/boat/tracking/track
|
|
116
|
+
Headers: { 'X-NFL-API-Key': pluginApiKey }
|
|
117
|
+
Body: {
|
|
118
|
+
timestamp: ms,
|
|
119
|
+
track: [[ms, lat, lon], [ms, lat, lon], ...],
|
|
120
|
+
boatApiKey: userBoatApiKey
|
|
121
|
+
}
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
**Retry Logic**:
|
|
125
|
+
- Attempt 1: base timeout (default 30s)
|
|
126
|
+
- Attempt 2: 2x timeout + 2s delay
|
|
127
|
+
- Attempt 3: 3x timeout + 4s delay
|
|
128
|
+
|
|
129
|
+
### Health & Monitoring
|
|
130
|
+
|
|
131
|
+
#### [lib/HealthMonitor.js](lib/HealthMonitor.js)
|
|
132
|
+
**Purpose**: Monitors GNSS position data freshness and reports issues.
|
|
133
|
+
|
|
134
|
+
**Key Responsibilities**:
|
|
135
|
+
- Initial check: 2 minutes after startup
|
|
136
|
+
- Periodic checks: every 5 minutes
|
|
137
|
+
- Detects stale position data (>5 minutes old)
|
|
138
|
+
- Detects missing position data
|
|
139
|
+
- Provides context-aware error messages (filtered vs auto-selected source)
|
|
140
|
+
- Calls error/healthy callbacks to update plugin status
|
|
141
|
+
|
|
142
|
+
**Health States**:
|
|
143
|
+
- Healthy: Position received within last 5 minutes
|
|
144
|
+
- Warning: No position for >5 minutes
|
|
145
|
+
- Error: No position ever received (or 2+ min after startup)
|
|
146
|
+
|
|
147
|
+
### Cleanup & Migration
|
|
148
|
+
|
|
149
|
+
#### [lib/PluginCleanup.js](lib/PluginCleanup.js)
|
|
150
|
+
**Purpose**: Runtime cleanup of old plugin versions.
|
|
151
|
+
|
|
152
|
+
**Key Responsibilities**:
|
|
153
|
+
- Detects Victron Cerbo vs standard SignalK paths
|
|
154
|
+
- Migrates config from old `signalk-to-noforeignland` to new scoped name
|
|
155
|
+
- Removes old plugin directories (`signalk-to-noforeignland`, `signalk-to-nfl`)
|
|
156
|
+
- Multiple retry attempts (immediate, 5s, 15s, 30s delays)
|
|
157
|
+
- Falls back to manual instructions if removal fails
|
|
158
|
+
- Returns promise resolving to 'all_removed' or 'partial_removal'
|
|
159
|
+
|
|
160
|
+
**Old Plugins Removed**:
|
|
161
|
+
- `signalk-to-noforeignland` (unscoped predecessor)
|
|
162
|
+
- `signalk-to-nfl` (deprecated alias)
|
|
163
|
+
|
|
164
|
+
#### [cleanup-old-plugin.js](cleanup-old-plugin.js)
|
|
165
|
+
**Purpose**: Postinstall script for immediate cleanup during npm install.
|
|
166
|
+
|
|
167
|
+
**Key Responsibilities**:
|
|
168
|
+
- Runs via `npm postinstall` hook
|
|
169
|
+
- Uses direct `fs.rmSync()` instead of npm uninstall (safer during install)
|
|
170
|
+
- 2-second delay to allow npm to complete current operation
|
|
171
|
+
- Detects Victron Cerbo vs standard SignalK paths
|
|
172
|
+
- Migrates config files
|
|
173
|
+
- Provides fallback manual instructions
|
|
174
|
+
|
|
175
|
+
**Why Two Cleanup Mechanisms?**
|
|
176
|
+
1. **Postinstall**: Runs during installation, removes old plugins immediately
|
|
177
|
+
2. **Runtime**: Handles cases where postinstall failed (permissions, timing)
|
|
178
|
+
|
|
179
|
+
#### [lib/TrackMigration.js](lib/TrackMigration.js)
|
|
180
|
+
**Purpose**: Migrates track files from old naming/location schemes.
|
|
181
|
+
|
|
182
|
+
**Key Responsibilities**:
|
|
183
|
+
- Migrates old file names to new naming scheme:
|
|
184
|
+
- `nfl-track.jsonl` -> `pending.jsonl`
|
|
185
|
+
- `nfl-track-pending.jsonl` -> `pending.jsonl`
|
|
186
|
+
- `nfl-track-sent.jsonl` -> `sent.jsonl`
|
|
187
|
+
- Migrates track files from old plugin directory to new data directory
|
|
188
|
+
- Removes old track directory if empty
|
|
189
|
+
- Non-destructive: only migrates if target doesn't exist
|
|
190
|
+
|
|
191
|
+
### SignalK Integration
|
|
192
|
+
|
|
193
|
+
#### [lib/DataPathEmitter.js](lib/DataPathEmitter.js)
|
|
194
|
+
**Purpose**: Creates and updates SignalK data paths for external integrations.
|
|
195
|
+
|
|
196
|
+
**Key Responsibilities**:
|
|
197
|
+
- Emits SignalK deltas to create data paths
|
|
198
|
+
- Updates status paths on state changes
|
|
199
|
+
- Manages error state independently
|
|
200
|
+
- Provides both ISO8601 and locale-formatted timestamps
|
|
201
|
+
|
|
202
|
+
**Data Paths Created**:
|
|
203
|
+
```
|
|
204
|
+
noforeignland.savepoint # ISO8601 timestamp of last save
|
|
205
|
+
noforeignland.savepoint_local # Locale string of last save
|
|
206
|
+
noforeignland.sent_to_api # ISO8601 timestamp of last API transfer
|
|
207
|
+
noforeignland.sent_to_api_local # Locale string of last API transfer
|
|
208
|
+
noforeignland.status # Status string (save/transfer/source info)
|
|
209
|
+
noforeignland.status_boolean # 0 = OK, 1 = error
|
|
210
|
+
noforeignland.source # Active GNSS source name
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
**Usage**: These paths can be consumed by Node-RED, KIP dashboards, or other SignalK consumers.
|
|
214
|
+
|
|
215
|
+
#### [lib/DirectoryUtils.js](lib/DirectoryUtils.js)
|
|
216
|
+
**Purpose**: File system utilities with proper error handling.
|
|
217
|
+
|
|
218
|
+
**Key Responsibilities**:
|
|
219
|
+
- Creates directories recursively
|
|
220
|
+
- Checks read/write permissions
|
|
221
|
+
- Provides context-specific error messages
|
|
222
|
+
- Handles common error codes (EACCES, EPERM, ETIMEDOUT)
|
|
223
|
+
|
|
224
|
+
## Data Flow
|
|
225
|
+
|
|
226
|
+
### Startup Sequence
|
|
227
|
+
```
|
|
228
|
+
1. ConfigManager: Migrate old config -> flatten -> validate
|
|
229
|
+
2. DirectoryUtils: Create track directory
|
|
230
|
+
3. PluginCleanup: Remove old plugins (async, non-blocking)
|
|
231
|
+
4. TrackMigration: Migrate old track files
|
|
232
|
+
5. Initialize: TrackLogger, TrackSender, HealthMonitor
|
|
233
|
+
6. ConfigManager: Randomize CRON schedule
|
|
234
|
+
7. TrackLogger: Start position subscription
|
|
235
|
+
8. CRON: Start interval job
|
|
236
|
+
9. HealthMonitor: Start health checks
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
### Position Logging Flow
|
|
240
|
+
```
|
|
241
|
+
navigation.position delta
|
|
242
|
+
-> TrackLogger.doOnValue()
|
|
243
|
+
-> handleSourceSelection() [filter/auto-select]
|
|
244
|
+
-> isValidPosition() [validate lat/lon]
|
|
245
|
+
-> shouldLogPosition() [check distance/frequency]
|
|
246
|
+
-> savePoint() [append to pending.jsonl]
|
|
247
|
+
-> callback to index.handleSavePoint()
|
|
248
|
+
-> DataPathEmitter.emitSavepoint()
|
|
249
|
+
-> setPluginStatus()
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
### Track Sending Flow (CRON Interval)
|
|
253
|
+
```
|
|
254
|
+
CRON trigger
|
|
255
|
+
-> index.interval()
|
|
256
|
+
-> TrackSender.isBoatMoving() [check last position age]
|
|
257
|
+
-> TrackSender.hasTrackData() [check pending.jsonl exists]
|
|
258
|
+
-> TrackSender.testInternet() [DNS lookup test]
|
|
259
|
+
-> TrackSender.sendTrack()
|
|
260
|
+
-> createTrackFromFile() [read pending.jsonl]
|
|
261
|
+
-> sendWithRetry() [POST to API, 3 attempts]
|
|
262
|
+
-> handleSuccessfulSend() [archive or delete]
|
|
263
|
+
-> DataPathEmitter.emitApiTransfer()
|
|
264
|
+
-> setPluginStatus()
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
### Health Monitoring Flow
|
|
268
|
+
```
|
|
269
|
+
HealthMonitor timer (every 5 min)
|
|
270
|
+
-> performHealthCheck()
|
|
271
|
+
-> check lastPositionReceived timestamp
|
|
272
|
+
-> if stale/missing: call onError callback
|
|
273
|
+
-> index.setPluginError()
|
|
274
|
+
-> DataPathEmitter.setError()
|
|
275
|
+
-> app.setPluginError()
|
|
276
|
+
-> if healthy: call onHealthy callback
|
|
277
|
+
-> index.handleHealthy()
|
|
278
|
+
-> setPluginStatus() [clear error if needed]
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
## File Locations
|
|
282
|
+
|
|
283
|
+
### Victron Cerbo GX
|
|
284
|
+
- SignalK directory: `/data/conf/signalk`
|
|
285
|
+
- Plugin installed at: `/data/conf/signalk/node_modules/@noforeignland/signalk-to-noforeignland`
|
|
286
|
+
- Config: `/data/conf/signalk/plugin-config-data/@noforeignland-signalk-to-noforeignland.json`
|
|
287
|
+
- Track files: `/data/conf/signalk/plugin-config-data/@noforeignland-signalk-to-noforeignland/nfl-track/`
|
|
288
|
+
|
|
289
|
+
### Standard SignalK
|
|
290
|
+
- SignalK directory: `~/.signalk`
|
|
291
|
+
- Plugin installed at: `~/.signalk/node_modules/@noforeignland/signalk-to-noforeignland`
|
|
292
|
+
- Config: `~/.signalk/plugin-config-data/@noforeignland-signalk-to-noforeignland.json`
|
|
293
|
+
- Track files: `~/.signalk/plugin-config-data/@noforeignland-signalk-to-noforeignland/nfl-track/`
|
|
294
|
+
|
|
295
|
+
## Development Notes
|
|
296
|
+
|
|
297
|
+
### Adding New Features
|
|
298
|
+
1. Create module in `lib/` if it's a distinct responsibility
|
|
299
|
+
2. Instantiate in [index.js](index.js) constructor
|
|
300
|
+
3. Initialize in `start()` method at appropriate step
|
|
301
|
+
4. Clean up in `stop()` method
|
|
302
|
+
5. Update this document
|
|
303
|
+
|
|
304
|
+
### Configuration Changes
|
|
305
|
+
1. Update schema in [ConfigManager.js](lib/ConfigManager.js) `getSchema()`
|
|
306
|
+
2. Add migration logic in `migrateOldConfig()` if breaking change
|
|
307
|
+
3. Update `flattenConfig()` to include new fields with defaults
|
|
308
|
+
4. Test both old and new config formats
|
|
309
|
+
|
|
310
|
+
### Track File Format Changes
|
|
311
|
+
1. Update `TrackLogger.savePoint()` for writing
|
|
312
|
+
2. Update `TrackSender.createTrackFromFile()` for reading
|
|
313
|
+
3. Add migration logic in [TrackMigration.js](lib/TrackMigration.js) if needed
|
|
314
|
+
|
|
315
|
+
### Testing Checklist
|
|
316
|
+
- [ ] Test on Victron Cerbo GX (path detection, limited storage)
|
|
317
|
+
- [ ] Test on standard SignalK installation
|
|
318
|
+
- [ ] Test config migration from old versions
|
|
319
|
+
- [ ] Test with multiple GNSS sources (auto-selection)
|
|
320
|
+
- [ ] Test with filtered source
|
|
321
|
+
- [ ] Test with no internet connection
|
|
322
|
+
- [ ] Test with slow internet (timeout scenarios)
|
|
323
|
+
- [ ] Test cleanup of old plugins
|
|
324
|
+
- [ ] Test track file migration
|
|
325
|
+
|
|
326
|
+
## Dependencies
|
|
327
|
+
|
|
328
|
+
```json
|
|
329
|
+
{
|
|
330
|
+
"cron": "^2.1.0", // CRON job scheduling
|
|
331
|
+
"fs-extra": "^10.1.0", // Enhanced file system operations
|
|
332
|
+
"node-fetch": "^2.6.7" // HTTP requests to API
|
|
333
|
+
}
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
## Version History Notes
|
|
337
|
+
|
|
338
|
+
- **1.1.0**: Refactored to modular structure
|
|
339
|
+
- **1.0.x**: Scoped package name, cleanup mechanism
|
|
340
|
+
- **0.1.x**: Original flat structure (deprecated)
|
|
341
|
+
|
|
342
|
+
## Known Technical Debt
|
|
343
|
+
|
|
344
|
+
1. **Empty process.exit()**: [cleanup-old-plugin.js](cleanup-old-plugin.js) setTimeout may not complete
|
|
345
|
+
2. **Error timing**: [PluginCleanup.js](lib/PluginCleanup.js) shows error before retries complete
|
|
346
|
+
3. **No test suite**: Manual testing only, no automated tests
|
|
347
|
+
|
|
348
|
+
## SignalK Plugin Conventions
|
|
349
|
+
|
|
350
|
+
This plugin follows SignalK plugin conventions:
|
|
351
|
+
- Exports function returning `{id, name, schema, start, stop}`
|
|
352
|
+
- Uses `app.debug()` for logging
|
|
353
|
+
- Uses `app.setPluginStatus()` and `app.setPluginError()` for UI feedback
|
|
354
|
+
- Subscribes via `app.subscriptionmanager.subscribe()`
|
|
355
|
+
- Emits deltas via `app.handleMessage(pluginId, delta)`
|
|
356
|
+
- Config stored in `plugin-config-data/` directory
|
|
357
|
+
- Data stored in plugin's data directory
|
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
Effortlessly log your boat's movement to **noforeignland.com**
|
|
3
3
|
|
|
4
4
|
## Important for 0.1.x users
|
|
5
|
-
Upgrade to >1.0
|
|
5
|
+
Upgrade to >1.1.0 by installing this plugin from the Appstore again. Your old config will be migrated and old plugins will be automatically removed.
|
|
6
6
|
|
|
7
7
|
## Features
|
|
8
8
|
* Automatically log your position to noforeignland.com
|
|
@@ -19,7 +19,7 @@ Upgrade to >1.0.1 by installing this plugin from the Appstore ageain. Your old c
|
|
|
19
19
|
|
|
20
20
|
## Requirements
|
|
21
21
|
* An internet connection is required in order to update noforeignland.com
|
|
22
|
-
* A navigation.position data path inside Signal K for self, which is your current
|
|
22
|
+
* A navigation.position data path inside Signal K for self, which is your current GNSS position
|
|
23
23
|
* A **noforeignland.com** account
|
|
24
24
|
* Your Boat API Key from the **noforeignland.com** website:
|
|
25
25
|
* Account > Settings > Boat tracking > API Key
|
|
@@ -49,5 +49,8 @@ https://github.com/noforeignland/nfl-signalk/issues
|
|
|
49
49
|
# Virctron Cerbo GX Users
|
|
50
50
|
|
|
51
51
|
## Limited storage
|
|
52
|
-
Signal K can quickly exhaust the small onboard storage of the device, especially when a lot of logging is enabled.
|
|
52
|
+
Signal K can quickly exhaust the small onboard storage of the device, especially when a lot of logging is enabled and not properly configured. Even concider to not enable "Keep track files on disk" if you are moving a lot.
|
|
53
|
+
|
|
54
|
+
Vicron Energy addressed this here:
|
|
53
55
|
https://www.victronenergy.com/live/venus-os:large#disk_space_issues_data_partition_full
|
|
56
|
+
|
package/doc/dev
ADDED
|
File without changes
|
package/lib/HealthMonitor.js
CHANGED
|
@@ -43,15 +43,15 @@ class HealthMonitor {
|
|
|
43
43
|
|
|
44
44
|
if (!lastPositionReceived) {
|
|
45
45
|
const errorMsg = this.options.filterSource
|
|
46
|
-
? `No
|
|
47
|
-
: 'No
|
|
46
|
+
? `No GNSS position data received from filtered source '${this.options.filterSource}'. Check Expert Settings > Position source device, or leave empty to use any GNSS source.`
|
|
47
|
+
: 'No GNSS position data received. Check that your GNSS is connected and SignalK is receiving navigation.position data.';
|
|
48
48
|
|
|
49
49
|
onError(errorMsg);
|
|
50
50
|
this.app.debug('Position health check: No position data ever received' + filterMsg);
|
|
51
51
|
} else if (timeSinceLastPosition > 300) {
|
|
52
52
|
const errorMsg = this.options.filterSource
|
|
53
|
-
? `No
|
|
54
|
-
: `No
|
|
53
|
+
? `No GNSS position data${filterMsg} for ${Math.floor(timeSinceLastPosition / 60)} minutes. Check that source '${this.options.filterSource}' is active, or change/clear Position source device in Expert Settings.`
|
|
54
|
+
: `No GNSS position data${filterMsg} for ${Math.floor(timeSinceLastPosition / 60)} minutes. Check your GNSS connection.`;
|
|
55
55
|
|
|
56
56
|
onError(errorMsg);
|
|
57
57
|
this.app.debug(`Position health check: No position for ${timeSinceLastPosition.toFixed(0)} seconds` + filterMsg);
|
|
@@ -68,8 +68,8 @@ class HealthMonitor {
|
|
|
68
68
|
if (!lastPositionReceived) {
|
|
69
69
|
const activeSource = this.options.filterSource || autoSelectedSource || 'any';
|
|
70
70
|
const errorMsg = this.options.filterSource
|
|
71
|
-
? `No
|
|
72
|
-
: 'No
|
|
71
|
+
? `No GNSS position data received after 2 minutes from filtered source '${this.options.filterSource}'. Check Expert Settings > Position source device. You may need to leave it empty to use any available GNSS source.`
|
|
72
|
+
: 'No GNSS position data received after 2 minutes. Check that your GNSS is connected and SignalK is receiving navigation.position data.';
|
|
73
73
|
|
|
74
74
|
onError(errorMsg);
|
|
75
75
|
this.app.debug('Initial position check: No position data received' +
|
package/lib/TrackLogger.js
CHANGED
|
@@ -130,7 +130,7 @@ class TrackLogger {
|
|
|
130
130
|
}
|
|
131
131
|
|
|
132
132
|
/**
|
|
133
|
-
* Handle
|
|
133
|
+
* Handle GNSS source selection (auto-select or filtered)
|
|
134
134
|
*/
|
|
135
135
|
handleSourceSelection(update) {
|
|
136
136
|
if (!this.options.filterSource) {
|
|
@@ -142,7 +142,7 @@ class TrackLogger {
|
|
|
142
142
|
if (!this.autoSelectedSource) {
|
|
143
143
|
this.autoSelectedSource = update.$source;
|
|
144
144
|
this.lastPositionReceived = new Date().getTime();
|
|
145
|
-
this.app.debug(`Auto-selected
|
|
145
|
+
this.app.debug(`Auto-selected GNSS source: '${this.autoSelectedSource}'`);
|
|
146
146
|
} else if (update.$source !== this.autoSelectedSource) {
|
|
147
147
|
if (timeSinceLastPosition && timeSinceLastPosition > 300) {
|
|
148
148
|
this.app.debug(`Switching from stale source '${this.autoSelectedSource}' to '${update.$source}' (no data for ${timeSinceLastPosition.toFixed(0)}s)`);
|
|
@@ -172,7 +172,7 @@ class TrackLogger {
|
|
|
172
172
|
isValidPosition(position) {
|
|
173
173
|
// Check if near (0,0) - likely invalid
|
|
174
174
|
if (Math.abs(position.latitude) <= 0.01 && Math.abs(position.longitude) <= 0.01) {
|
|
175
|
-
this.app.debug('
|
|
175
|
+
this.app.debug('GNSS coordinates near (0,0), ignoring point to avoid invalid data logging.');
|
|
176
176
|
return false;
|
|
177
177
|
}
|
|
178
178
|
|