signalk-siparu 0.2.14 → 0.2.16
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/package.json +1 -1
- package/plugin/dist/live.d.ts +2 -0
- package/plugin/dist/live.js +9 -1
- package/plugin/dist/metrics.d.ts +2 -1
- package/plugin/dist/metrics.js +70 -4
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "signalk-siparu",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.16",
|
|
4
4
|
"description": "Kept aboard, proven ashore. Position, wind, depth and voyage history, recorded on the boat and readable from anywhere: sealed to the devices you name, signed on the way out. A read-only Signal K plugin with a built-in dashboard.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"signalk-node-server-plugin",
|
package/plugin/dist/live.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ import type { RemoteLink } from './remotelink';
|
|
|
2
2
|
import type { PathSeriesResult, SnapshotsQuery, SnapshotsResult, TrackResult, VoyageListResult, PhaseListResult, RollupsResult, VoyageStatsResult, FuelPathsView, AisFeed, HealthResult } from './contract';
|
|
3
3
|
export declare const FRAME_EVERY_MS = 2000;
|
|
4
4
|
export declare const STILL_FRAME_EVERY_MS = 60000;
|
|
5
|
+
export declare const PROMPTED_FRAME_FLOOR_MS = 5000;
|
|
5
6
|
export declare const REPORTING_STALE_MS: number;
|
|
6
7
|
export declare const PING_EVERY_MS = 25000;
|
|
7
8
|
export interface LiveSocket {
|
|
@@ -87,6 +88,7 @@ export declare class LiveUplink {
|
|
|
87
88
|
private kill;
|
|
88
89
|
private dispatch;
|
|
89
90
|
private openSealedAsk;
|
|
91
|
+
private greet;
|
|
90
92
|
private sendFrame;
|
|
91
93
|
private scheduleFrame;
|
|
92
94
|
private wayStreak;
|
package/plugin/dist/live.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.LiveUplink = exports.PING_EVERY_MS = exports.REPORTING_STALE_MS = exports.STILL_FRAME_EVERY_MS = exports.FRAME_EVERY_MS = void 0;
|
|
3
|
+
exports.LiveUplink = exports.PING_EVERY_MS = exports.REPORTING_STALE_MS = exports.PROMPTED_FRAME_FLOOR_MS = exports.STILL_FRAME_EVERY_MS = exports.FRAME_EVERY_MS = void 0;
|
|
4
4
|
exports.rpcEnvelope = rpcEnvelope;
|
|
5
5
|
exports.isWatchingNote = isWatchingNote;
|
|
6
6
|
exports.FRAME_EVERY_MS = 2_000;
|
|
7
7
|
exports.STILL_FRAME_EVERY_MS = 60_000;
|
|
8
|
+
exports.PROMPTED_FRAME_FLOOR_MS = 5_000;
|
|
8
9
|
exports.REPORTING_STALE_MS = exports.STILL_FRAME_EVERY_MS * 3;
|
|
9
10
|
const UNDERWAY_SOG_MS = 0.3 * 0.514444;
|
|
10
11
|
const CLEARLY_UNDERWAY_SOG_MS = 1.5 * 0.514444;
|
|
@@ -140,6 +141,7 @@ class LiveUplink {
|
|
|
140
141
|
}
|
|
141
142
|
if (isWatchingNote(data)) {
|
|
142
143
|
this.deps.onWatching?.();
|
|
144
|
+
this.greet(gen);
|
|
143
145
|
return;
|
|
144
146
|
}
|
|
145
147
|
const opened = this.openSealedAsk(data);
|
|
@@ -207,6 +209,12 @@ class LiveUplink {
|
|
|
207
209
|
}
|
|
208
210
|
return open(envelope);
|
|
209
211
|
}
|
|
212
|
+
greet(gen) {
|
|
213
|
+
if (this.lastFrameTs !== null && Date.now() - this.lastFrameTs < exports.PROMPTED_FRAME_FLOOR_MS) {
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
this.sendFrame(gen);
|
|
217
|
+
}
|
|
210
218
|
sendFrame(gen) {
|
|
211
219
|
if (gen !== this.gen || !this.sock)
|
|
212
220
|
return;
|
package/plugin/dist/metrics.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { MetricField, Snapshot } from './contract';
|
|
2
2
|
import { Options } from './config';
|
|
3
3
|
export declare const SUBSCRIBED_PATHS: string[];
|
|
4
|
-
export declare const DYNAMIC_PREFIXES: readonly ["propulsion.", "tanks.", "electrical.generators."];
|
|
4
|
+
export declare const DYNAMIC_PREFIXES: readonly ["propulsion.", "tanks.", "electrical.ac.", "electrical.alternators.", "electrical.batteries.", "electrical.chargers.", "electrical.generators.", "electrical.inverters.", "electrical.solar."];
|
|
5
5
|
export interface Diagnosis {
|
|
6
6
|
code: 'ok' | 'instruments-off' | 'energy-only' | 'no-data';
|
|
7
7
|
message: string;
|
|
@@ -22,6 +22,7 @@ export declare class MetricsState {
|
|
|
22
22
|
private conceptNumeric;
|
|
23
23
|
snapshot(now: number, flushGust: boolean, freshnessMs?: number): Snapshot;
|
|
24
24
|
private dynamicPathCount;
|
|
25
|
+
private evictFiller;
|
|
25
26
|
dynamicPaths(now: number): Record<string, number | string>;
|
|
26
27
|
dynamicPathAges(now: number): Record<string, number>;
|
|
27
28
|
coreFieldAges(now: number): Partial<Record<MetricField, number>>;
|
package/plugin/dist/metrics.js
CHANGED
|
@@ -34,10 +34,20 @@ exports.SUBSCRIBED_PATHS = [
|
|
|
34
34
|
...DEPTH_PATHS,
|
|
35
35
|
...Object.keys(DIRECT_PATHS)
|
|
36
36
|
];
|
|
37
|
-
exports.DYNAMIC_PREFIXES = [
|
|
37
|
+
exports.DYNAMIC_PREFIXES = [
|
|
38
|
+
'propulsion.',
|
|
39
|
+
'tanks.',
|
|
40
|
+
'electrical.ac.',
|
|
41
|
+
'electrical.alternators.',
|
|
42
|
+
'electrical.batteries.',
|
|
43
|
+
'electrical.chargers.',
|
|
44
|
+
'electrical.generators.',
|
|
45
|
+
'electrical.inverters.',
|
|
46
|
+
'electrical.solar.'
|
|
47
|
+
];
|
|
38
48
|
const CORE_PATH_SET = new Set(exports.SUBSCRIBED_PATHS);
|
|
39
49
|
const TEXT_MAX = 32;
|
|
40
|
-
const MAX_DYNAMIC_PATHS =
|
|
50
|
+
const MAX_DYNAMIC_PATHS = 128;
|
|
41
51
|
const PATH_MAX_LEN = 128;
|
|
42
52
|
const PATH_RE = /^[A-Za-z][A-Za-z0-9]*(\.[A-Za-z0-9_-]+)+$/;
|
|
43
53
|
function isDynamicPath(path) {
|
|
@@ -46,6 +56,41 @@ function isDynamicPath(path) {
|
|
|
46
56
|
PATH_RE.test(path) &&
|
|
47
57
|
exports.DYNAMIC_PREFIXES.some((p) => path.startsWith(p)));
|
|
48
58
|
}
|
|
59
|
+
const PRIORITY_LEAVES = new Set([
|
|
60
|
+
'revolutions',
|
|
61
|
+
'temperature',
|
|
62
|
+
'oilPressure',
|
|
63
|
+
'runTime',
|
|
64
|
+
'fuel.rate',
|
|
65
|
+
'alternatorVoltage',
|
|
66
|
+
'engineLoad',
|
|
67
|
+
'exhaustTemperature',
|
|
68
|
+
'state',
|
|
69
|
+
'voltage',
|
|
70
|
+
'current',
|
|
71
|
+
'frequency',
|
|
72
|
+
'power',
|
|
73
|
+
'realPower',
|
|
74
|
+
'lineNeutralVoltage',
|
|
75
|
+
'lineLineVoltage',
|
|
76
|
+
'acin.voltage',
|
|
77
|
+
'acin.current',
|
|
78
|
+
'currentLevel',
|
|
79
|
+
'capacity',
|
|
80
|
+
'capacity.stateOfCharge',
|
|
81
|
+
'capacity.timeRemaining',
|
|
82
|
+
'chargingMode',
|
|
83
|
+
'controllerMode',
|
|
84
|
+
'inverterMode',
|
|
85
|
+
'panelPower',
|
|
86
|
+
'yieldToday'
|
|
87
|
+
]);
|
|
88
|
+
function isPriorityPath(path) {
|
|
89
|
+
const seg = path.split('.');
|
|
90
|
+
if (PRIORITY_LEAVES.has(seg[seg.length - 1]))
|
|
91
|
+
return true;
|
|
92
|
+
return seg.length >= 2 && PRIORITY_LEAVES.has(`${seg[seg.length - 2]}.${seg[seg.length - 1]}`);
|
|
93
|
+
}
|
|
49
94
|
const STRING_FIELDS = new Set(['nav_state', 'ais_class']);
|
|
50
95
|
const TWS_SET = new Set(TWS_PATHS);
|
|
51
96
|
class MetricsState {
|
|
@@ -82,8 +127,10 @@ class MetricsState {
|
|
|
82
127
|
stored = value.slice(0, TEXT_MAX);
|
|
83
128
|
else
|
|
84
129
|
return false;
|
|
85
|
-
if (!this.paths.has(path) && this.dynamicPathCount() >= MAX_DYNAMIC_PATHS)
|
|
86
|
-
|
|
130
|
+
if (!this.paths.has(path) && this.dynamicPathCount() >= MAX_DYNAMIC_PATHS) {
|
|
131
|
+
if (!isPriorityPath(path) || !this.evictFiller())
|
|
132
|
+
return false;
|
|
133
|
+
}
|
|
87
134
|
}
|
|
88
135
|
else {
|
|
89
136
|
if (typeof value !== 'number' || !Number.isFinite(value))
|
|
@@ -230,6 +277,25 @@ class MetricsState {
|
|
|
230
277
|
n++;
|
|
231
278
|
return n;
|
|
232
279
|
}
|
|
280
|
+
evictFiller() {
|
|
281
|
+
let victim = null;
|
|
282
|
+
let victimTs = Infinity;
|
|
283
|
+
for (const [path, bySource] of this.paths) {
|
|
284
|
+
if (!isDynamicPath(path) || isPriorityPath(path))
|
|
285
|
+
continue;
|
|
286
|
+
let last = 0;
|
|
287
|
+
for (const entry of bySource.values())
|
|
288
|
+
last = Math.max(last, entry.ts);
|
|
289
|
+
if (last < victimTs) {
|
|
290
|
+
victimTs = last;
|
|
291
|
+
victim = path;
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
if (victim === null)
|
|
295
|
+
return false;
|
|
296
|
+
this.paths.delete(victim);
|
|
297
|
+
return true;
|
|
298
|
+
}
|
|
233
299
|
dynamicPaths(now) {
|
|
234
300
|
const out = {};
|
|
235
301
|
for (const path of this.paths.keys()) {
|