@aurora-blue/signalk-connector 0.2.0-dev.22 → 0.2.0-dev.23
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 +2 -0
- package/VERSION +1 -1
- package/dist/src/connector.js +10 -8
- package/dist/src/delta.js +40 -1
- package/dist/src/telemetry-catalog.d.ts +1 -1
- package/dist/src/telemetry-catalog.js +7 -1
- package/dist/src/types.d.ts +1 -1
- package/dist/src/version.d.ts +1 -1
- package/dist/src/version.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -53,6 +53,8 @@ The connector exchanges the pairing code once and clears it from the Signal K pl
|
|
|
53
53
|
|
|
54
54
|
The default configuration sends up to 250 events per batch, waits up to five seconds to combine normal telemetry, samples selected own-vessel Signal K paths every second, samples selected AIS paths every five seconds, and enables the preliminary underway change-or-heartbeat profile. AIS can be disabled independently. The `auto` storage profile selects a constrained, standard, or extended byte budget from filesystem capacity while preserving a free-space reserve. Its effective event limit is derived from measured journal bytes per event instead of a fixed 10,000-event default. Protocol 1.1 permits no more than 500 events per batch, and the server continues to accept exact protocol 1.0 backlog batches during upgrades.
|
|
55
55
|
|
|
56
|
+
The connector also subscribes to scalar values below `electrical.switches.*`, including separate channels on multi-output devices. Switch paths use the instant subscription policy so a periodic retransmission of a cached Signal K value is not mistaken for fresh device evidence. The server may use selected `.state` leaves for conservative equipment-runtime estimates. A silent or unpowered device stops contributing runtime after a short bounded interval; accurate long-running counters require a qualified device-originated liveness source.
|
|
57
|
+
|
|
56
58
|
The optional anchor alarm is an experimental development scaffold. When enabled, position is requested every 250 milliseconds and every received position reaches the safety engine before telemetry reduction. The alarm publishes a local Signal K notification and detects stale position input without requiring the Aurora Blue target. It must not yet be used as the sole safety device.
|
|
57
59
|
|
|
58
60
|
The paired Aurora Blue target controls the device operating mode. Active mode collects and transfers normal telemetry. Standby stops admitting new historical telemetry, drains existing backlog, and keeps only the local position input required by an enabled anchor alarm. Disabled mode preserves the backlog but stops collection, transfer, and local safety subscriptions. Standby and disabled connectors continue a low-rate authenticated configuration heartbeat so an administrator can reactivate them remotely.
|
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
0.2.0-dev.
|
|
1
|
+
0.2.0-dev.23
|
package/dist/src/connector.js
CHANGED
|
@@ -337,14 +337,16 @@ class ConnectorRuntime {
|
|
|
337
337
|
subscribeToContext(context, paths, period) {
|
|
338
338
|
this.app.subscriptionmanager.subscribe({
|
|
339
339
|
context,
|
|
340
|
-
subscribe: paths.map((path) =>
|
|
341
|
-
path: path,
|
|
342
|
-
|
|
343
|
-
path
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
340
|
+
subscribe: paths.map((path) => context === "vessels.self" && path === "electrical.switches.*"
|
|
341
|
+
? { path: path, policy: "instant", minPeriod: 0 }
|
|
342
|
+
: {
|
|
343
|
+
path: path,
|
|
344
|
+
period: context === "vessels.self" &&
|
|
345
|
+
path === "navigation.position" &&
|
|
346
|
+
this.config.anchorAlarm.enabled
|
|
347
|
+
? Math.min(this.config.samplePeriodMs, this.config.safetySamplePeriodMs)
|
|
348
|
+
: period,
|
|
349
|
+
}),
|
|
348
350
|
}, this.unsubscribes, (error) => {
|
|
349
351
|
this.app.setPluginError("Signal K subscription failed.");
|
|
350
352
|
this.app.error(error instanceof Error ? error.message : String(error));
|
package/dist/src/delta.js
CHANGED
|
@@ -53,6 +53,15 @@ const validValue = (context, path, value) => {
|
|
|
53
53
|
if (definition.valueKind === "number") {
|
|
54
54
|
return typeof value === "number" && Number.isFinite(value) ? value : null;
|
|
55
55
|
}
|
|
56
|
+
if (definition.valueKind === "switch") {
|
|
57
|
+
if (typeof value === "boolean")
|
|
58
|
+
return value;
|
|
59
|
+
if (typeof value === "number" && Number.isFinite(value))
|
|
60
|
+
return value;
|
|
61
|
+
return typeof value === "string" && value.length > 0
|
|
62
|
+
? value.slice(0, 255)
|
|
63
|
+
: null;
|
|
64
|
+
}
|
|
56
65
|
if (definition.valueKind === "string") {
|
|
57
66
|
if (path === "mmsi" && !/^[0-9]{9}$/.test(String(value))) {
|
|
58
67
|
return null;
|
|
@@ -101,6 +110,32 @@ const flattenedStaticValues = (context, path, value) => {
|
|
|
101
110
|
{ path: "navigation.state", value: navigation?.state },
|
|
102
111
|
];
|
|
103
112
|
};
|
|
113
|
+
const flattenedSwitchValues = (path, value) => {
|
|
114
|
+
if (path !== "electrical.switches" &&
|
|
115
|
+
!path.startsWith("electrical.switches.")) {
|
|
116
|
+
return [{ path, value }];
|
|
117
|
+
}
|
|
118
|
+
const leaves = [];
|
|
119
|
+
const visit = (currentPath, currentValue, depth) => {
|
|
120
|
+
if (leaves.length >= 100 || depth > 8)
|
|
121
|
+
return;
|
|
122
|
+
if (currentValue === null || Array.isArray(currentValue))
|
|
123
|
+
return;
|
|
124
|
+
if (typeof currentValue !== "object") {
|
|
125
|
+
leaves.push({ path: currentPath, value: currentValue });
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
for (const [name, child] of Object.entries(currentValue)) {
|
|
129
|
+
if (!/^[A-Za-z0-9_:-]+$/.test(name))
|
|
130
|
+
continue;
|
|
131
|
+
visit(`${currentPath}.${name}`, child, depth + 1);
|
|
132
|
+
if (leaves.length >= 100)
|
|
133
|
+
break;
|
|
134
|
+
}
|
|
135
|
+
};
|
|
136
|
+
visit(path, value, 0);
|
|
137
|
+
return leaves;
|
|
138
|
+
};
|
|
104
139
|
const eventsFromDelta = (delta, bootId, receivedAt, subscriptionScope = "self") => {
|
|
105
140
|
const events = [];
|
|
106
141
|
const context = eventContext(delta, subscriptionScope);
|
|
@@ -115,7 +150,11 @@ const eventsFromDelta = (delta, bootId, receivedAt, subscriptionScope = "self")
|
|
|
115
150
|
if (pathValue.state?.timedOut === true) {
|
|
116
151
|
continue;
|
|
117
152
|
}
|
|
118
|
-
|
|
153
|
+
const path = String(pathValue.path);
|
|
154
|
+
const candidates = context === "vessels.self"
|
|
155
|
+
? flattenedSwitchValues(path, pathValue.value)
|
|
156
|
+
: flattenedStaticValues(context, path, pathValue.value);
|
|
157
|
+
for (const candidate of candidates) {
|
|
119
158
|
const value = validValue(context, candidate.path, candidate.value);
|
|
120
159
|
if (value === null) {
|
|
121
160
|
continue;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { EventContext } from "./types";
|
|
2
2
|
export type TelemetryScope = "self" | "ais";
|
|
3
|
-
export type ValueKind = "number" | "position" | "string" | "aisShipType";
|
|
3
|
+
export type ValueKind = "number" | "position" | "string" | "boolean" | "switch" | "aisShipType";
|
|
4
4
|
export type ChangeKind = "scalar" | "angle" | "position" | "identity";
|
|
5
5
|
export interface TelemetryDefinition {
|
|
6
6
|
scope: TelemetryScope;
|
|
@@ -72,7 +72,7 @@ exports.AIS_TELEMETRY = [
|
|
|
72
72
|
ais("communication.callsignVhf", "string", "identity", 60_000, 21_600_000, 0),
|
|
73
73
|
ais("design.aisShipType", "aisShipType", "identity", 60_000, 21_600_000, 0),
|
|
74
74
|
];
|
|
75
|
-
exports.SELF_SUBSCRIPTION_PATHS = exports.SELF_TELEMETRY.map((definition) => definition.path);
|
|
75
|
+
exports.SELF_SUBSCRIPTION_PATHS = exports.SELF_TELEMETRY.map((definition) => definition.path).concat("electrical.switches.*");
|
|
76
76
|
exports.AIS_SUBSCRIPTION_PATHS = exports.AIS_TELEMETRY.map((definition) => definition.path);
|
|
77
77
|
const matchesPath = (pattern, path) => {
|
|
78
78
|
const patternParts = pattern.split(".");
|
|
@@ -83,6 +83,12 @@ const matchesPath = (pattern, path) => {
|
|
|
83
83
|
const isAisContext = (context) => /^vessels\.(?:urn:mrn:imo:mmsi:)?[0-9]{9}$/.test(context);
|
|
84
84
|
exports.isAisContext = isAisContext;
|
|
85
85
|
const telemetryDefinition = (context, path) => {
|
|
86
|
+
if (context === "vessels.self" &&
|
|
87
|
+
path.startsWith("electrical.switches.") &&
|
|
88
|
+
path.length <= 255 &&
|
|
89
|
+
/^electrical\.switches\.[A-Za-z0-9_:-]+(?:\.[A-Za-z0-9_:-]+)+$/.test(path)) {
|
|
90
|
+
return self(path, "switch", "identity", 0, 60_000, 0);
|
|
91
|
+
}
|
|
86
92
|
const definitions = context === "vessels.self"
|
|
87
93
|
? exports.SELF_TELEMETRY
|
|
88
94
|
: (0, exports.isAisContext)(context)
|
package/dist/src/types.d.ts
CHANGED
|
@@ -19,7 +19,7 @@ export interface AisShipTypeValue {
|
|
|
19
19
|
id: number;
|
|
20
20
|
name: string;
|
|
21
21
|
}
|
|
22
|
-
export type EventValue = number | string | PositionValue | AisShipTypeValue;
|
|
22
|
+
export type EventValue = number | string | boolean | PositionValue | AisShipTypeValue;
|
|
23
23
|
export interface EventInput {
|
|
24
24
|
boot_id: string;
|
|
25
25
|
context: EventContext;
|
package/dist/src/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const CONNECTOR_VERSION = "0.2.0-dev.
|
|
1
|
+
export declare const CONNECTOR_VERSION = "0.2.0-dev.23";
|
package/dist/src/version.js
CHANGED
package/package.json
CHANGED