@sailingnaturali/signalk-dsc 0.2.0 → 0.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/README.md +13 -0
- package/index.js +21 -0
- package/lib/store.js +11 -0
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -142,6 +142,19 @@ $CDDSC,12,3380400790,12,05,00,1423108312,2019,,,S,E*69
|
|
|
142
142
|
$CDDSE,1,1,A,3380400790,00,45894494*1B
|
|
143
143
|
```
|
|
144
144
|
|
|
145
|
+
### Clearing an alarm
|
|
146
|
+
|
|
147
|
+
A received distress/urgency/safety call raises `notifications.dsc.<category>` and is
|
|
148
|
+
re-raised for up to an hour across server restarts. To clear an active alarm — dropping
|
|
149
|
+
the live notification and stopping the restart re-raise:
|
|
150
|
+
|
|
151
|
+
```bash
|
|
152
|
+
SIGNALK_TOKEN=<readwrite-token> npm run clear-dsc -- --category distress
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
`--category all` clears all three. Clearing is a write, so it needs a readwrite token
|
|
156
|
+
(the same one used to fire a test MOB). A new incoming call still alarms normally.
|
|
157
|
+
|
|
145
158
|
## Limitations
|
|
146
159
|
|
|
147
160
|
- Distress relays, acknowledgements, and cancellations are stored (with
|
package/index.js
CHANGED
|
@@ -153,6 +153,15 @@ module.exports = function makePlugin(app) {
|
|
|
153
153
|
});
|
|
154
154
|
}
|
|
155
155
|
|
|
156
|
+
/** Clear an active DSC alarm: drop the live notification from our own source
|
|
157
|
+
* and stamp the stored events so the restart reannounce skips them. */
|
|
158
|
+
function clearCategory(category) {
|
|
159
|
+
app.handleMessage(plugin.id, {
|
|
160
|
+
updates: [{ values: [{ path: `notifications.dsc.${category}`, value: null }] }],
|
|
161
|
+
});
|
|
162
|
+
store.markCleared((e) => e.category === category, new Date().toISOString());
|
|
163
|
+
}
|
|
164
|
+
|
|
156
165
|
function shouldLogbook(event) {
|
|
157
166
|
if (options.logbookEnabled === false) return false;
|
|
158
167
|
if (!options.logbookToken) return false;
|
|
@@ -354,6 +363,17 @@ module.exports = function makePlugin(app) {
|
|
|
354
363
|
app.emitPropertyValue('nmea0183sentenceParser', { sentence: 'DSE', parser: dseParser });
|
|
355
364
|
app.on('N2KAnalyzerOut', onPgn);
|
|
356
365
|
|
|
366
|
+
// Let an operator clear an active DSC alarm: a PUT to the notification path
|
|
367
|
+
// drops the live alert and marks the stored call(s) so a restart will not
|
|
368
|
+
// re-raise it. The readwrite device token authorizes this write.
|
|
369
|
+
for (const category of Object.keys(NOTIFICATION_STATES)) {
|
|
370
|
+
// Value ignored: any PUT to these paths means "clear" — no partial-update semantics.
|
|
371
|
+
app.registerPutHandler('vessels.self', `notifications.dsc.${category}`, () => {
|
|
372
|
+
clearCategory(category);
|
|
373
|
+
return { state: 'COMPLETED', statusCode: 200 };
|
|
374
|
+
});
|
|
375
|
+
}
|
|
376
|
+
|
|
357
377
|
started = true;
|
|
358
378
|
|
|
359
379
|
// Survive server restarts mid-incident: re-raise the newest alert per
|
|
@@ -369,6 +389,7 @@ module.exports = function makePlugin(app) {
|
|
|
369
389
|
for (let i = events.length - 1; i >= 0; i--) {
|
|
370
390
|
const event = events[i];
|
|
371
391
|
if (!NOTIFICATION_STATES[event.category] || reannounced.has(event.category)) continue;
|
|
392
|
+
if (event.clearedAt) continue; // operator-cleared: never resurrect
|
|
372
393
|
const at = Date.parse(event.lastReceivedAt || event.receivedAt);
|
|
373
394
|
if (now - at <= REANNOUNCE_WINDOW_MS) {
|
|
374
395
|
notify(event);
|
package/lib/store.js
CHANGED
|
@@ -76,6 +76,17 @@ class EventStore {
|
|
|
76
76
|
return this.events.find((e) => e.id === id);
|
|
77
77
|
}
|
|
78
78
|
|
|
79
|
+
/** Stamp `clearedAt` on every matching event not already cleared. Returns the
|
|
80
|
+
* count newly stamped; compacts once. */
|
|
81
|
+
markCleared(predicate, at) {
|
|
82
|
+
let touched = 0;
|
|
83
|
+
for (const e of this.events) {
|
|
84
|
+
if (predicate(e) && !e.clearedAt) { e.clearedAt = at; touched += 1; }
|
|
85
|
+
}
|
|
86
|
+
if (touched) this._compact();
|
|
87
|
+
return touched;
|
|
88
|
+
}
|
|
89
|
+
|
|
79
90
|
/** Newest event matching `predicate` received within `windowMs` of `nowMs`. */
|
|
80
91
|
findRecent(predicate, nowMs, windowMs) {
|
|
81
92
|
for (let i = this.events.length - 1; i >= 0; i--) {
|
package/package.json
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sailingnaturali/signalk-dsc",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Receive, log, and alert on DSC (VHF digital selective calling) calls — distress, urgency, safety, routine — from NMEA 0183 ($CDDSC/$CDDSE) and NMEA 2000 (PGN 129808).",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
7
7
|
"test": "node --test",
|
|
8
|
-
"send-test-dsc": "node scripts/send-test-dsc.js"
|
|
8
|
+
"send-test-dsc": "node scripts/send-test-dsc.js",
|
|
9
|
+
"clear-dsc": "node scripts/clear-dsc-alarm.js"
|
|
9
10
|
},
|
|
10
11
|
"keywords": [
|
|
11
12
|
"signalk-node-server-plugin",
|