signalk-livedepth-plugin 0.0.0-stage → 0.1.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/LICENSE +21 -0
- package/README.md +51 -2
- package/dist/collector.d.ts +15 -0
- package/dist/collector.d.ts.map +1 -0
- package/dist/collector.js +23 -0
- package/dist/collector.js.map +1 -0
- package/dist/config.d.ts +142 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +161 -0
- package/dist/config.js.map +1 -0
- package/dist/constants.d.ts +5 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +5 -0
- package/dist/constants.js.map +1 -0
- package/dist/fetch.d.ts +5 -0
- package/dist/fetch.d.ts.map +1 -0
- package/dist/fetch.js +13 -0
- package/dist/fetch.js.map +1 -0
- package/dist/history.d.ts +24 -0
- package/dist/history.d.ts.map +1 -0
- package/dist/history.js +76 -0
- package/dist/history.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -0
- package/dist/plugin.d.ts +3 -0
- package/dist/plugin.d.ts.map +1 -0
- package/dist/plugin.js +88 -0
- package/dist/plugin.js.map +1 -0
- package/dist/streams/index.d.ts +3 -0
- package/dist/streams/index.d.ts.map +1 -0
- package/dist/streams/index.js +3 -0
- package/dist/streams/index.js.map +1 -0
- package/dist/streams/live.d.ts +9 -0
- package/dist/streams/live.d.ts.map +1 -0
- package/dist/streams/live.js +62 -0
- package/dist/streams/live.js.map +1 -0
- package/dist/streams/transforms.d.ts +14 -0
- package/dist/streams/transforms.d.ts.map +1 -0
- package/dist/streams/transforms.js +21 -0
- package/dist/streams/transforms.js.map +1 -0
- package/dist/tiles/accumulator.d.ts +34 -0
- package/dist/tiles/accumulator.d.ts.map +1 -0
- package/dist/tiles/accumulator.js +60 -0
- package/dist/tiles/accumulator.js.map +1 -0
- package/dist/tiles/api.d.ts +36 -0
- package/dist/tiles/api.d.ts.map +1 -0
- package/dist/tiles/api.js +75 -0
- package/dist/tiles/api.js.map +1 -0
- package/dist/tiles/grid.d.ts +59 -0
- package/dist/tiles/grid.d.ts.map +1 -0
- package/dist/tiles/grid.js +121 -0
- package/dist/tiles/grid.js.map +1 -0
- package/dist/tiles/index.d.ts +7 -0
- package/dist/tiles/index.d.ts.map +1 -0
- package/dist/tiles/index.js +7 -0
- package/dist/tiles/index.js.map +1 -0
- package/dist/tiles/seed.d.ts +45 -0
- package/dist/tiles/seed.d.ts.map +1 -0
- package/dist/tiles/seed.js +132 -0
- package/dist/tiles/seed.js.map +1 -0
- package/dist/tiles/store.d.ts +36 -0
- package/dist/tiles/store.d.ts.map +1 -0
- package/dist/tiles/store.js +114 -0
- package/dist/tiles/store.js.map +1 -0
- package/dist/tiles/writer.d.ts +15 -0
- package/dist/tiles/writer.d.ts.map +1 -0
- package/dist/tiles/writer.js +46 -0
- package/dist/tiles/writer.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/dist/types.d.ts +10 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/icon.svg +12 -0
- package/package.json +53 -4
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Nick Roberts
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,52 @@
|
|
|
1
|
-
#
|
|
1
|
+
# signalk-livedepth-plugin
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
A Signal K server plugin that builds a **gridded bathymetry tile store** from the
|
|
4
|
+
vessel's own position and depth, and serves it to a chart client's LiveDepth
|
|
5
|
+
layer. It is the server side of Freeboard-SK's LiveDepth layer.
|
|
6
|
+
|
|
7
|
+
## What it does
|
|
8
|
+
|
|
9
|
+
- Subscribes to the vessel's own `environment.depth.*` and `navigation.position`,
|
|
10
|
+
and folds each sounding into a Web-Mercator XYZ tile store: 256-cell tiles,
|
|
11
|
+
base level `z20` (≈0.15 m per cell), min-pooled down to `z4` (≈2.4 km per
|
|
12
|
+
cell). A tile is stored sparsely — only the cells a sounding fell in — as a
|
|
13
|
+
5-byte record (`cx, cy, depthCm, count`) keeping the shallowest depth, so
|
|
14
|
+
zooming out never deepens a shoal.
|
|
15
|
+
- Serves the tiles over HTTP so a chart client can draw a depth surface for the
|
|
16
|
+
area without replaying the raw track or interpolating at query time.
|
|
17
|
+
- Can seed the store from the server's History API at the finest granularity it
|
|
18
|
+
offers — a one-time, resumable rebuild for a store that already has a track.
|
|
19
|
+
|
|
20
|
+
## Routes
|
|
21
|
+
|
|
22
|
+
Mounted by the server at `/plugins/signalk-livedepth-plugin`:
|
|
23
|
+
|
|
24
|
+
| Route | Returns |
|
|
25
|
+
| -------------------------------- | -------------------------------------------------------------------------------------- |
|
|
26
|
+
| `GET /bathymetry/meta` | grid spec (base/min zoom, tile size, record size) and the depth path/offsets to mirror |
|
|
27
|
+
| `GET /bathymetry/tiles/:z/:x/:y` | the sparse tile blob (`application/octet-stream`), or `404` |
|
|
28
|
+
| `GET /bathymetry/seed` | admin only: status of the one-time history rebuild |
|
|
29
|
+
| `POST /bathymetry/seed` | admin only: start the one-time history rebuild (`202`) |
|
|
30
|
+
|
|
31
|
+
A client seeds its view from the tiles, then keeps its own copy current from the
|
|
32
|
+
same Signal K stream.
|
|
33
|
+
|
|
34
|
+
## Configuration
|
|
35
|
+
|
|
36
|
+
- **Path** — the `environment.depth.*` path to record.
|
|
37
|
+
- **Depth Sounder / GPS Receiver** — the sensor offsets, and the source to pin
|
|
38
|
+
each path to (so soundings from a second GPS don't smear the track).
|
|
39
|
+
- **Rebuild from History** — a one-shot rebuild from the server's History API;
|
|
40
|
+
it fires once when saved and clears itself when it finishes.
|
|
41
|
+
|
|
42
|
+
## Development
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
npm install
|
|
46
|
+
npm run build # tsc -b -> dist/
|
|
47
|
+
npm test # vitest
|
|
48
|
+
npm run format
|
|
49
|
+
npm run lint
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Node `>=22.5` (the store uses the built-in `node:sqlite`).
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Writable } from "stream";
|
|
2
|
+
import { ServerAPI } from "@signalk/server-api";
|
|
3
|
+
import { Config } from "./config.js";
|
|
4
|
+
export interface CollectorOptions {
|
|
5
|
+
app: ServerAPI;
|
|
6
|
+
config: Config;
|
|
7
|
+
/** The tile writer fed the live soundings. */
|
|
8
|
+
writer: Writable;
|
|
9
|
+
signal: AbortSignal;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Pair depth with position once and feed the soundings to the tile writer.
|
|
13
|
+
*/
|
|
14
|
+
export declare function createCollector({ app, config, writer, signal, }: CollectorOptions): import("stream-transform").Transformer;
|
|
15
|
+
//# sourceMappingURL=collector.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"collector.d.ts","sourceRoot":"","sources":["../src/collector.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAC;AAClC,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAChD,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAGrC,MAAM,WAAW,gBAAgB;IAC/B,GAAG,EAAE,SAAS,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,8CAA8C;IAC9C,MAAM,EAAE,QAAQ,CAAC;IACjB,MAAM,EAAE,WAAW,CAAC;CACrB;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,EAC9B,GAAG,EACH,MAAM,EACN,MAAM,EACN,MAAM,GACP,EAAE,gBAAgB,0CAkBlB"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { transform } from "stream-transform";
|
|
2
|
+
import { createLiveStream, toPrecision } from "./streams/index.js";
|
|
3
|
+
/**
|
|
4
|
+
* Pair depth with position once and feed the soundings to the tile writer.
|
|
5
|
+
*/
|
|
6
|
+
export function createCollector({ app, config, writer, signal, }) {
|
|
7
|
+
const live = createLiveStream(app, config);
|
|
8
|
+
const precise = live.pipe(transform(toPrecision()));
|
|
9
|
+
precise.pipe(writer);
|
|
10
|
+
const destroy = () => {
|
|
11
|
+
live.destroy();
|
|
12
|
+
precise.destroy();
|
|
13
|
+
writer.destroy();
|
|
14
|
+
};
|
|
15
|
+
if (signal.aborted) {
|
|
16
|
+
destroy();
|
|
17
|
+
}
|
|
18
|
+
else {
|
|
19
|
+
signal.addEventListener("abort", destroy, { once: true });
|
|
20
|
+
}
|
|
21
|
+
return precise;
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=collector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"collector.js","sourceRoot":"","sources":["../src/collector.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAI7C,OAAO,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAUnE;;GAEG;AACH,MAAM,UAAU,eAAe,CAAC,EAC9B,GAAG,EACH,MAAM,EACN,MAAM,EACN,MAAM,GACW;IACjB,MAAM,IAAI,GAAG,gBAAgB,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;IAC3C,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC;IACpD,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAErB,MAAM,OAAO,GAAG,GAAG,EAAE;QACnB,IAAI,CAAC,OAAO,EAAE,CAAC;QACf,OAAO,CAAC,OAAO,EAAE,CAAC;QAClB,MAAM,CAAC,OAAO,EAAE,CAAC;IACnB,CAAC,CAAC;IAEF,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;QACnB,OAAO,EAAE,CAAC;IACZ,CAAC;SAAM,CAAC;QACN,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;IAC5D,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC"}
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import { ServerAPI } from "@signalk/server-api";
|
|
2
|
+
export type Config = {
|
|
3
|
+
path: (typeof DepthPaths)[number];
|
|
4
|
+
sounder: {
|
|
5
|
+
x: number;
|
|
6
|
+
y: number;
|
|
7
|
+
z: number;
|
|
8
|
+
draft?: number;
|
|
9
|
+
make?: string;
|
|
10
|
+
model?: string;
|
|
11
|
+
frequency?: number;
|
|
12
|
+
transducer?: string;
|
|
13
|
+
source?: string;
|
|
14
|
+
};
|
|
15
|
+
gnss: {
|
|
16
|
+
x: number;
|
|
17
|
+
y: number;
|
|
18
|
+
z: number;
|
|
19
|
+
make?: string;
|
|
20
|
+
model?: string;
|
|
21
|
+
source?: string;
|
|
22
|
+
};
|
|
23
|
+
seed?: {
|
|
24
|
+
run?: boolean;
|
|
25
|
+
resolution?: number;
|
|
26
|
+
};
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* The source Signal K currently prioritizes for a path (its `$source`) plus the
|
|
30
|
+
* full list of sources that have reported it. Used to default and populate the
|
|
31
|
+
* source selectors so soundings stay pinned to one sensor rather than mixing
|
|
32
|
+
* antenna offsets from multiple GPS sources.
|
|
33
|
+
*/
|
|
34
|
+
export declare function sourcesFor(app: ServerAPI, path: string): {
|
|
35
|
+
selected: string | undefined;
|
|
36
|
+
available: string[];
|
|
37
|
+
};
|
|
38
|
+
/** Configured source if set, else the server's prioritized source, else undefined. */
|
|
39
|
+
export declare function resolveSource(app: ServerAPI, configured: string | undefined, path: string): string | undefined;
|
|
40
|
+
export declare const DepthPaths: readonly ["belowSurface", "belowTransducer", "belowKeel"];
|
|
41
|
+
export declare function schema(app: ServerAPI): {
|
|
42
|
+
type: string;
|
|
43
|
+
description: string;
|
|
44
|
+
properties: {
|
|
45
|
+
path: {
|
|
46
|
+
type: string;
|
|
47
|
+
title: string;
|
|
48
|
+
description: string;
|
|
49
|
+
enum: readonly ["belowSurface", "belowTransducer", "belowKeel"];
|
|
50
|
+
default: "belowKeel" | "belowSurface" | "belowTransducer" | undefined;
|
|
51
|
+
};
|
|
52
|
+
sounder: {
|
|
53
|
+
type: string;
|
|
54
|
+
title: string;
|
|
55
|
+
required: string[];
|
|
56
|
+
properties: {
|
|
57
|
+
source: {
|
|
58
|
+
type: string;
|
|
59
|
+
title: string;
|
|
60
|
+
enum: string[];
|
|
61
|
+
enumNames: string[];
|
|
62
|
+
default: string | undefined;
|
|
63
|
+
description: string;
|
|
64
|
+
};
|
|
65
|
+
y: {
|
|
66
|
+
type: string;
|
|
67
|
+
title: string;
|
|
68
|
+
minimum: number;
|
|
69
|
+
default: unknown;
|
|
70
|
+
};
|
|
71
|
+
x: {
|
|
72
|
+
type: string;
|
|
73
|
+
title: string;
|
|
74
|
+
description: string;
|
|
75
|
+
default: unknown;
|
|
76
|
+
};
|
|
77
|
+
z: {
|
|
78
|
+
type: string;
|
|
79
|
+
title: string;
|
|
80
|
+
default: unknown;
|
|
81
|
+
};
|
|
82
|
+
draft: {
|
|
83
|
+
type: string;
|
|
84
|
+
title: string;
|
|
85
|
+
description: string;
|
|
86
|
+
default: unknown;
|
|
87
|
+
};
|
|
88
|
+
};
|
|
89
|
+
};
|
|
90
|
+
gnss: {
|
|
91
|
+
type: string;
|
|
92
|
+
title: string;
|
|
93
|
+
required: string[];
|
|
94
|
+
properties: {
|
|
95
|
+
source: {
|
|
96
|
+
type: string;
|
|
97
|
+
title: string;
|
|
98
|
+
enum: string[];
|
|
99
|
+
enumNames: string[];
|
|
100
|
+
default: string | undefined;
|
|
101
|
+
description: string;
|
|
102
|
+
};
|
|
103
|
+
y: {
|
|
104
|
+
type: string;
|
|
105
|
+
title: string;
|
|
106
|
+
minimum: number;
|
|
107
|
+
default: unknown;
|
|
108
|
+
};
|
|
109
|
+
x: {
|
|
110
|
+
type: string;
|
|
111
|
+
title: string;
|
|
112
|
+
description: string;
|
|
113
|
+
default: unknown;
|
|
114
|
+
};
|
|
115
|
+
z: {
|
|
116
|
+
type: string;
|
|
117
|
+
title: string;
|
|
118
|
+
};
|
|
119
|
+
};
|
|
120
|
+
};
|
|
121
|
+
seed: {
|
|
122
|
+
type: string;
|
|
123
|
+
title: string;
|
|
124
|
+
description: string;
|
|
125
|
+
properties: {
|
|
126
|
+
run: {
|
|
127
|
+
type: string;
|
|
128
|
+
default: boolean;
|
|
129
|
+
title: string;
|
|
130
|
+
description: string;
|
|
131
|
+
};
|
|
132
|
+
resolution: {
|
|
133
|
+
type: string;
|
|
134
|
+
default: number;
|
|
135
|
+
title: string;
|
|
136
|
+
description: string;
|
|
137
|
+
};
|
|
138
|
+
};
|
|
139
|
+
};
|
|
140
|
+
};
|
|
141
|
+
};
|
|
142
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAEhD,MAAM,MAAM,MAAM,GAAG;IACnB,IAAI,EAAE,CAAC,OAAO,UAAU,CAAC,CAAC,MAAM,CAAC,CAAC;IAClC,OAAO,EAAE;QACP,CAAC,EAAE,MAAM,CAAC;QACV,CAAC,EAAE,MAAM,CAAC;QACV,CAAC,EAAE,MAAM,CAAC;QACV,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,MAAM,CAAC,EAAE,MAAM,CAAC;KACjB,CAAC;IACF,IAAI,EAAE;QACJ,CAAC,EAAE,MAAM,CAAC;QACV,CAAC,EAAE,MAAM,CAAC;QACV,CAAC,EAAE,MAAM,CAAC;QACV,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,MAAM,CAAC,EAAE,MAAM,CAAC;KACjB,CAAC;IACF,IAAI,CAAC,EAAE;QACL,GAAG,CAAC,EAAE,OAAO,CAAC;QACd,UAAU,CAAC,EAAE,MAAM,CAAC;KACrB,CAAC;CACH,CAAC;AAEF;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM;;;EAUtD;AAED,sFAAsF;AACtF,wBAAgB,aAAa,CAC3B,GAAG,EAAE,SAAS,EACd,UAAU,EAAE,MAAM,GAAG,SAAS,EAC9B,IAAI,EAAE,MAAM,GACX,MAAM,GAAG,SAAS,CAEpB;AAsDD,eAAO,MAAM,UAAU,YACrB,cAAc,EACd,iBAAiB,EACjB,WAAW,CACH,CAAC;AAEX,wBAAgB,MAAM,CAAC,GAAG,EAAE,SAAS;IASjC,IAAI;IACJ,WAAW;IAEX,UAAU;QACR,IAAI;YACF,IAAI;YACJ,KAAK;YACL,WAAW;YAEX,IAAI;YACJ,OAAO;;QAET,OAAO;YACL,IAAI;YACJ,KAAK;YACL,QAAQ;YACR,UAAU;gBACR,MAAM;;;;;;;;gBACN,CAAC;oBACC,IAAI;oBACJ,KAAK;oBACL,OAAO;oBACP,OAAO;;gBAET,CAAC;oBACC,IAAI;oBACJ,KAAK;oBACL,WAAW;oBACX,OAAO;;gBAET,CAAC;oBACC,IAAI;oBACJ,KAAK;oBACL,OAAO;;gBAIT,KAAK;oBACH,IAAI;oBACJ,KAAK;oBACL,WAAW;oBACX,OAAO;;;;QAIb,IAAI;YACF,IAAI;YACJ,KAAK;YACL,QAAQ;YACR,UAAU;gBACR,MAAM;;;;;;;;gBAMN,CAAC;oBACC,IAAI;oBACJ,KAAK;oBACL,OAAO;oBACP,OAAO;;gBAET,CAAC;oBACC,IAAI;oBACJ,KAAK;oBACL,WAAW;oBACX,OAAO;;gBAET,CAAC;oBACC,IAAI;oBACJ,KAAK;;;;QAIX,IAAI;YACF,IAAI;YACJ,KAAK;YACL,WAAW;YAEX,UAAU;gBACR,GAAG;oBACD,IAAI;oBACJ,OAAO;oBACP,KAAK;oBACL,WAAW;;gBAGb,UAAU;oBACR,IAAI;oBACJ,OAAO;oBACP,KAAK;oBACL,WAAW;;;;;EAOtB"}
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The source Signal K currently prioritizes for a path (its `$source`) plus the
|
|
3
|
+
* full list of sources that have reported it. Used to default and populate the
|
|
4
|
+
* source selectors so soundings stay pinned to one sensor rather than mixing
|
|
5
|
+
* antenna offsets from multiple GPS sources.
|
|
6
|
+
*/
|
|
7
|
+
export function sourcesFor(app, path) {
|
|
8
|
+
const node = app.getSelfPath(path);
|
|
9
|
+
const selected = node?.$source;
|
|
10
|
+
// Multi-source paths carry a `values` map keyed by sourceRef; single-source
|
|
11
|
+
// paths have none, so fall back to the active `$source`. Either way, make sure
|
|
12
|
+
// the active source is in the list.
|
|
13
|
+
const available = node?.values ? Object.keys(node.values) : [];
|
|
14
|
+
if (selected && !available.includes(selected))
|
|
15
|
+
available.unshift(selected);
|
|
16
|
+
return { selected, available };
|
|
17
|
+
}
|
|
18
|
+
/** Configured source if set, else the server's prioritized source, else undefined. */
|
|
19
|
+
export function resolveSource(app, configured, path) {
|
|
20
|
+
return configured || sourcesFor(app, path).selected;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* A friendly label for a sourceRef, e.g. "Airmar DST200 (PICAN-M.35)", built
|
|
24
|
+
* from the NMEA 2000 device info Signal K keeps under `sources`. Falls back to
|
|
25
|
+
* the raw sourceRef when no device details are known.
|
|
26
|
+
*/
|
|
27
|
+
function sourceLabel(app, sourceRef) {
|
|
28
|
+
const dot = sourceRef.indexOf(".");
|
|
29
|
+
const label = dot === -1 ? sourceRef : sourceRef.slice(0, dot);
|
|
30
|
+
const instance = dot === -1 ? "" : sourceRef.slice(dot + 1);
|
|
31
|
+
const sources = app.getPath("sources");
|
|
32
|
+
const connection = sources?.[label];
|
|
33
|
+
// The sources tree keys devices by numeric bus address, but with
|
|
34
|
+
// useCanName the sourceRef carries the hex CAN name instead, so fall
|
|
35
|
+
// back to matching each device's n2k.canName (mirrors the admin UI's
|
|
36
|
+
// getDeviceInfo in signalk-server's sourceLabels.ts).
|
|
37
|
+
const n2k = connection?.[instance]?.n2k ??
|
|
38
|
+
Object.values(connection ?? {}).find((device) => device?.n2k?.canName === instance)?.n2k;
|
|
39
|
+
const name = [n2k?.manufacturerCode, n2k?.modelId]
|
|
40
|
+
.filter((p) => typeof p === "string" && p.length > 0)
|
|
41
|
+
.join(" ");
|
|
42
|
+
return name ? `${name} (${sourceRef})` : sourceRef;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Schema for a source selector. Always an enum, with friendly device names via
|
|
46
|
+
* enumNames. When nothing has reported the path yet the enum is empty and the
|
|
47
|
+
* description warns that no data is available so the empty dropdown isn't a
|
|
48
|
+
* mystery.
|
|
49
|
+
*/
|
|
50
|
+
function sourceSchema(app, title, noun, sources) {
|
|
51
|
+
return {
|
|
52
|
+
type: "string",
|
|
53
|
+
title,
|
|
54
|
+
enum: sources.available,
|
|
55
|
+
enumNames: sources.available.map((source) => sourceLabel(app, source)),
|
|
56
|
+
default: sources.selected,
|
|
57
|
+
description: sources.available.length
|
|
58
|
+
? `The ${noun} source to record. Defaults to the source Signal K prioritizes; choose one when the vessel has more than one.`
|
|
59
|
+
: `No ${noun} data available — reload this page once it is being received.`,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
export const DepthPaths = [
|
|
63
|
+
"belowSurface",
|
|
64
|
+
"belowTransducer",
|
|
65
|
+
"belowKeel",
|
|
66
|
+
];
|
|
67
|
+
export function schema(app) {
|
|
68
|
+
const defaultPath = DepthPaths.find((path) => app.getSelfPath(`environment.depth.${path}.value`));
|
|
69
|
+
const positionSources = sourcesFor(app, "navigation.position");
|
|
70
|
+
const depthSources = defaultPath
|
|
71
|
+
? sourcesFor(app, `environment.depth.${defaultPath}`)
|
|
72
|
+
: { selected: undefined, available: [] };
|
|
73
|
+
return {
|
|
74
|
+
type: "object",
|
|
75
|
+
description: "Build a gridded bathymetry tile store from the vessel's own position and depth, and serve it to a chart client's LiveDepth layer.",
|
|
76
|
+
properties: {
|
|
77
|
+
path: {
|
|
78
|
+
type: "string",
|
|
79
|
+
title: "Path",
|
|
80
|
+
description: "The path to the depth data. (e.g. environment.depth.belowTransducer)",
|
|
81
|
+
enum: DepthPaths,
|
|
82
|
+
default: defaultPath,
|
|
83
|
+
},
|
|
84
|
+
sounder: {
|
|
85
|
+
type: "object",
|
|
86
|
+
title: "Depth Sounder",
|
|
87
|
+
required: ["x", "y", "z"],
|
|
88
|
+
properties: {
|
|
89
|
+
source: sourceSchema(app, "Depth source", "depth", depthSources),
|
|
90
|
+
y: {
|
|
91
|
+
type: "number",
|
|
92
|
+
title: "Distance of the transducer from the bow (meters)",
|
|
93
|
+
minimum: 0,
|
|
94
|
+
default: app.getSelfPath("sensors.depth.fromBow.value"),
|
|
95
|
+
},
|
|
96
|
+
x: {
|
|
97
|
+
type: "number",
|
|
98
|
+
title: "Distance of the transducer from the center (meters)",
|
|
99
|
+
description: "+ve to starboard, -ve to port",
|
|
100
|
+
default: app.getSelfPath("sensors.depth.fromCenter.value"),
|
|
101
|
+
},
|
|
102
|
+
z: {
|
|
103
|
+
type: "number",
|
|
104
|
+
title: "Distance of the transducer below the waterline (meters)",
|
|
105
|
+
default: app.getSelfPath("environment.depth.surfaceToTransducer.value"),
|
|
106
|
+
},
|
|
107
|
+
draft: {
|
|
108
|
+
type: "number",
|
|
109
|
+
title: "Draft",
|
|
110
|
+
description: "The draft of the vessel in meters.",
|
|
111
|
+
default: app.getSelfPath("design.draft.value"),
|
|
112
|
+
},
|
|
113
|
+
},
|
|
114
|
+
},
|
|
115
|
+
gnss: {
|
|
116
|
+
type: "object",
|
|
117
|
+
title: "GPS Receiver",
|
|
118
|
+
required: ["x", "y", "z"],
|
|
119
|
+
properties: {
|
|
120
|
+
source: sourceSchema(app, "Position source", "position", positionSources),
|
|
121
|
+
y: {
|
|
122
|
+
type: "number",
|
|
123
|
+
title: "Distance of the antenna from the bow (meters)",
|
|
124
|
+
minimum: 0,
|
|
125
|
+
default: app.getSelfPath("sensors.gps.fromBow.value"),
|
|
126
|
+
},
|
|
127
|
+
x: {
|
|
128
|
+
type: "number",
|
|
129
|
+
title: "Distance of the antenna from the center (meters)",
|
|
130
|
+
description: "+ve to starboard, -ve to port",
|
|
131
|
+
default: app.getSelfPath("sensors.gps.fromCenter.value"),
|
|
132
|
+
},
|
|
133
|
+
z: {
|
|
134
|
+
type: "number",
|
|
135
|
+
title: "Distance of the antenna above the waterline (meters)",
|
|
136
|
+
},
|
|
137
|
+
},
|
|
138
|
+
},
|
|
139
|
+
seed: {
|
|
140
|
+
type: "object",
|
|
141
|
+
title: "Rebuild from History",
|
|
142
|
+
description: "Rebuild the gridded bathymetry tiles from the server's History API at the finest granularity it offers. Slow — it reads the whole record — so run it once; the live stream keeps the tiles current afterwards, and an interrupted run resumes where it stopped.",
|
|
143
|
+
properties: {
|
|
144
|
+
run: {
|
|
145
|
+
type: "boolean",
|
|
146
|
+
default: false,
|
|
147
|
+
title: "Rebuild the bathymetry tiles from history now",
|
|
148
|
+
description: "Starts the rebuild when the configuration is saved. Resets itself when it finishes; leave off to skip.",
|
|
149
|
+
},
|
|
150
|
+
resolution: {
|
|
151
|
+
type: "number",
|
|
152
|
+
default: 0.1,
|
|
153
|
+
title: "History resolution (seconds)",
|
|
154
|
+
description: "Granularity to read. The provider floors this at its native cadence; 0.1 keeps nearly every fix.",
|
|
155
|
+
},
|
|
156
|
+
},
|
|
157
|
+
},
|
|
158
|
+
},
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { Temporal } from "@js-temporal/polyfill";
|
|
2
|
+
/** Earliest instant the history seed reaches back to. signalk-to-influxdb was
|
|
3
|
+
* first released on 2017-06-28 — the earliest recorded bathymetry. */
|
|
4
|
+
export declare const BATHY_EPOCH: Temporal.Instant;
|
|
5
|
+
//# sourceMappingURL=constants.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAEjD;sEACsE;AACtE,eAAO,MAAM,WAAW,kBAEvB,CAAC"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { Temporal } from "@js-temporal/polyfill";
|
|
2
|
+
/** Earliest instant the history seed reaches back to. signalk-to-influxdb was
|
|
3
|
+
* first released on 2017-06-28 — the earliest recorded bathymetry. */
|
|
4
|
+
export const BATHY_EPOCH = Temporal.Instant.from(process.env.BATHY_EPOCH ?? "2017-06-28T00:00:00Z");
|
|
5
|
+
//# sourceMappingURL=constants.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAEjD;sEACsE;AACtE,MAAM,CAAC,MAAM,WAAW,GAAG,QAAQ,CAAC,OAAO,CAAC,IAAI,CAC9C,OAAO,CAAC,GAAG,CAAC,WAAW,IAAI,sBAAsB,CAClD,CAAC"}
|
package/dist/fetch.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fetch.d.ts","sourceRoot":"","sources":["../src/fetch.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,CAAC,OAAO,WAAW,GAAG,EAAE,MAAM,GAAG,GAAG,EAAE,IAAI,GAAE,WAAgB,qBAQjE"}
|
package/dist/fetch.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fetch wrapper that adds a User-Agent, used by the History API HTTP fallback.
|
|
3
|
+
*/
|
|
4
|
+
export default function (url, init = {}) {
|
|
5
|
+
return fetch(url, {
|
|
6
|
+
...init,
|
|
7
|
+
headers: {
|
|
8
|
+
...init.headers,
|
|
9
|
+
"User-Agent": "signalk-livedepth-plugin",
|
|
10
|
+
},
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=fetch.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fetch.js","sourceRoot":"","sources":["../src/fetch.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,CAAC,OAAO,WAAW,GAAiB,EAAE,IAAI,GAAgB,EAAE;IAChE,OAAO,KAAK,CAAC,GAAG,EAAE;QAChB,GAAG,IAAI;QACP,OAAO,EAAE;YACP,GAAG,IAAI,CAAC,OAAO;YACf,YAAY,EAAE,0BAA0B;SACzC;KACF,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { Path, ServerAPI } from "@signalk/server-api";
|
|
2
|
+
import { HistoryApi, ValuesResponse } from "@signalk/server-api/history";
|
|
3
|
+
export type HistoryAPIOptions = {
|
|
4
|
+
app: ServerAPI;
|
|
5
|
+
host?: string;
|
|
6
|
+
};
|
|
7
|
+
/**
|
|
8
|
+
* The History Provider API is new and may not be available. This uses a provider if available,
|
|
9
|
+
* and otherwise falls back to direct HTTP access if available.
|
|
10
|
+
*/
|
|
11
|
+
export declare function getHistoryAPI({ app, port, host, }: HistoryAPIOptions): Promise<HistoryApi | undefined>;
|
|
12
|
+
/**
|
|
13
|
+
* Build a lookup from SignalK path to its column index in a history `DataRow`.
|
|
14
|
+
*
|
|
15
|
+
* `values[i]` describes data column `i + 1` (column 0 is always the timestamp),
|
|
16
|
+
* so the returned index can be used directly against a `DataRow`. The response's
|
|
17
|
+
* `values` metadata is authoritative — v2+ providers may reorder or drop columns
|
|
18
|
+
* — but providers that omit it fall back to the requested path order. When a
|
|
19
|
+
* path appears more than once the first matching column wins.
|
|
20
|
+
*/
|
|
21
|
+
export declare function columnsByPath(values: ValuesResponse["values"] | undefined, requested: readonly {
|
|
22
|
+
path: Path;
|
|
23
|
+
}[]): Map<string, number>;
|
|
24
|
+
//# sourceMappingURL=history.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"history.d.ts","sourceRoot":"","sources":["../src/history.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AACtD,OAAO,EAGL,UAAU,EAIV,cAAc,EACf,MAAM,6BAA6B,CAAC;AAKrC,MAAM,MAAM,iBAAiB,GAAG;IAC9B,GAAG,EAAE,SAAS,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,CAAC;AAMF;;;GAGG;AACH,wBAAsB,aAAa,CAAC,EAClC,GAAG,EAEH,IAAqE,EACrE,IAA8D,GAC/D,EAAE,iBAAiB,GAAG,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC,CA2DrD;AAED;;;;;;;;GAQG;AACH,wBAAgB,aAAa,CAC3B,MAAM,EAAE,cAAc,CAAC,QAAQ,CAAC,GAAG,SAAS,EAC5C,SAAS,EAAE,SAAS;IAAE,IAAI,EAAE,IAAI,CAAA;CAAE,EAAE,GACnC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAOrB"}
|
package/dist/history.js
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { Temporal } from "@js-temporal/polyfill";
|
|
2
|
+
import { BATHY_EPOCH } from "./constants.js";
|
|
3
|
+
import fetch from "./fetch.js";
|
|
4
|
+
/**
|
|
5
|
+
* The History Provider API is new and may not be available. This uses a provider if available,
|
|
6
|
+
* and otherwise falls back to direct HTTP access if available.
|
|
7
|
+
*/
|
|
8
|
+
export async function getHistoryAPI({ app,
|
|
9
|
+
// @ts-expect-error: app.config is not a public API
|
|
10
|
+
port = Number(process.env.PORT) || app.config?.settings?.port || 3000, host = process.env.SIGNALK_HOST ?? `http://localhost:${port}/`, }) {
|
|
11
|
+
try {
|
|
12
|
+
// Try to get the built-in history provider API first. It either returns the API or throws
|
|
13
|
+
// an error if no provider is configured. It will also throw if the API is not available.
|
|
14
|
+
const api = await app.getHistoryApi();
|
|
15
|
+
app.debug("Using built-in history provider");
|
|
16
|
+
return api;
|
|
17
|
+
}
|
|
18
|
+
catch {
|
|
19
|
+
// History provider API not available or no provider configured.
|
|
20
|
+
}
|
|
21
|
+
try {
|
|
22
|
+
await getContexts({
|
|
23
|
+
from: BATHY_EPOCH,
|
|
24
|
+
to: Temporal.Now.instant(),
|
|
25
|
+
});
|
|
26
|
+
app.debug("Using History API available at %s", host);
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
app.debug("History API is not available");
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
return { getValues, getContexts, getPaths };
|
|
33
|
+
async function get(path, params = {}) {
|
|
34
|
+
const url = new URL(path, new URL("/signalk/v2/api/history/", host));
|
|
35
|
+
url.search = new URLSearchParams(params).toString();
|
|
36
|
+
app.debug("Fetching %s", url.toString());
|
|
37
|
+
const res = await fetch(url);
|
|
38
|
+
if (!res.ok) {
|
|
39
|
+
throw new Error(`Failed to fetch ${url}: ${res.status} ${res.statusText}`);
|
|
40
|
+
}
|
|
41
|
+
return res.json();
|
|
42
|
+
}
|
|
43
|
+
function getValues({ pathSpecs, ...query }) {
|
|
44
|
+
return get("values", {
|
|
45
|
+
...query,
|
|
46
|
+
paths: pathSpecs
|
|
47
|
+
.map(({ path, aggregate }) => [path, aggregate].join(":"))
|
|
48
|
+
.join(","),
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
function getContexts(query) {
|
|
52
|
+
return get("contexts", query);
|
|
53
|
+
}
|
|
54
|
+
function getPaths(query) {
|
|
55
|
+
return get("paths", query);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Build a lookup from SignalK path to its column index in a history `DataRow`.
|
|
60
|
+
*
|
|
61
|
+
* `values[i]` describes data column `i + 1` (column 0 is always the timestamp),
|
|
62
|
+
* so the returned index can be used directly against a `DataRow`. The response's
|
|
63
|
+
* `values` metadata is authoritative — v2+ providers may reorder or drop columns
|
|
64
|
+
* — but providers that omit it fall back to the requested path order. When a
|
|
65
|
+
* path appears more than once the first matching column wins.
|
|
66
|
+
*/
|
|
67
|
+
export function columnsByPath(values, requested) {
|
|
68
|
+
const source = values && values.length ? values : requested;
|
|
69
|
+
const columns = new Map();
|
|
70
|
+
source.forEach((column, i) => {
|
|
71
|
+
if (!columns.has(column.path))
|
|
72
|
+
columns.set(column.path, i + 1);
|
|
73
|
+
});
|
|
74
|
+
return columns;
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=history.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"history.js","sourceRoot":"","sources":["../src/history.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import createPlugin from "./plugin.js";
|
|
2
|
+
export default createPlugin;
|
|
3
|
+
export * from "./constants.js";
|
|
4
|
+
export * from "./types.js";
|
|
5
|
+
export * from "./config.js";
|
|
6
|
+
export * from "./streams/index.js";
|
|
7
|
+
export * from "./tiles/index.js";
|
|
8
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,YAAY,MAAM,aAAa,CAAC;eAExB,YAAY;AAC3B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,oBAAoB,CAAC;AACnC,cAAc,kBAAkB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import createPlugin from "./plugin.js";
|
|
2
|
+
export default createPlugin;
|
|
3
|
+
export * from "./constants.js";
|
|
4
|
+
export * from "./types.js";
|
|
5
|
+
export * from "./config.js";
|
|
6
|
+
export * from "./streams/index.js";
|
|
7
|
+
export * from "./tiles/index.js";
|
|
8
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,YAAY,MAAM,aAAa,CAAC;AAEvC,eAAe,YAAY,CAAC;AAC5B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,oBAAoB,CAAC;AACnC,cAAc,kBAAkB,CAAC"}
|
package/dist/plugin.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,EAAgB,MAAM,qBAAqB,CAAC;AAatE,MAAM,CAAC,OAAO,UAAU,YAAY,CAAC,GAAG,EAAE,SAAS,GAAG,MAAM,CAqG3D"}
|