@rhizomatics/signalk-einklabel-plugin 0.8.1 → 0.8.2
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 +4 -0
- package/README.md +4 -0
- package/dist/devices/zhsunyco/index.js +1 -1
- package/dist/render/assets.d.ts +6 -0
- package/dist/render/assets.js +14 -0
- package/dist/render/svgRenderer.js +1 -1
- package/dist/repaintScheduler.js +32 -14
- package/package.json +1 -1
- package/templates/tide.svg +4 -1
package/CHANGELOG.md
CHANGED
package/README.md
CHANGED
|
@@ -322,6 +322,10 @@ If you're a global cruiser, then use something like [signalk-set-gps-timezone](h
|
|
|
322
322
|
|
|
323
323
|
Try a BLE proxy device, ESP32 is popular for this.
|
|
324
324
|
|
|
325
|
+
### Can't edit the text contents of SVG template in VSCode
|
|
326
|
+
|
|
327
|
+
If you have an SVG viewer extension, this wll show the image rather than allowing editing of text. To solve, right click on the file in VSCode _Explorer_ view and choose to edit with _Text Editor_.
|
|
328
|
+
|
|
325
329
|
## Other ESL and General eInk Resources
|
|
326
330
|
|
|
327
331
|
- [Open ePaper Link](https://openepaperlink.de) - Alternative open source firmware to flash onto eInk shelf labels, with Home Assistant integration.
|
|
@@ -150,7 +150,7 @@ async function readDeviceDetails(device, address, advertisedInfo) {
|
|
|
150
150
|
// which otherwise stays set forever and silently skips every later scan).
|
|
151
151
|
return Promise.race([
|
|
152
152
|
read(),
|
|
153
|
-
(0, bleDiscovery_1.sleep)(SCAN_CONNECT_TIMEOUT_MS *
|
|
153
|
+
(0, bleDiscovery_1.sleep)(SCAN_CONNECT_TIMEOUT_MS * 3).then(() => {
|
|
154
154
|
console.error(`${pluginVersion_1.PLUGIN_NAME}: zhsunyco [${address}]: battery/config read timed out after ${SCAN_CONNECT_TIMEOUT_MS * 2}ms`);
|
|
155
155
|
return fallback;
|
|
156
156
|
}),
|
package/dist/render/assets.d.ts
CHANGED
|
@@ -21,3 +21,9 @@ export declare function resolveAssetPath(templatesDir: string, bundledTemplatesD
|
|
|
21
21
|
* directory, is readable) - the miss is then just this value's.
|
|
22
22
|
*/
|
|
23
23
|
export declare function describeAssetsDirProblem(templatesDir: string, bundledTemplatesDir: string, assetsName: string): string | undefined;
|
|
24
|
+
/**
|
|
25
|
+
* Counts the `.svg` files in whichever `assets/<assetsName>` directory `selectAssetsDir` would read
|
|
26
|
+
* from, for a caller to report alongside a resolved-but-empty-key miss - confirms which directory is in
|
|
27
|
+
* play and how populated it is, which "the directory exists" alone doesn't convey.
|
|
28
|
+
*/
|
|
29
|
+
export declare function countAssets(templatesDir: string, bundledTemplatesDir: string, assetsName: string): number;
|
package/dist/render/assets.js
CHANGED
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.normalizeAssetKey = normalizeAssetKey;
|
|
4
4
|
exports.resolveAssetPath = resolveAssetPath;
|
|
5
5
|
exports.describeAssetsDirProblem = describeAssetsDirProblem;
|
|
6
|
+
exports.countAssets = countAssets;
|
|
6
7
|
const fs_1 = require("fs");
|
|
7
8
|
const path_1 = require("path");
|
|
8
9
|
/**
|
|
@@ -86,3 +87,16 @@ function describeAssetsDirProblem(templatesDir, bundledTemplatesDir, assetsName)
|
|
|
86
87
|
const problem = describeDir(selectAssetsDir(templatesDir, bundledTemplatesDir, assetsName));
|
|
87
88
|
return problem && `assets directory ${problem}`;
|
|
88
89
|
}
|
|
90
|
+
/**
|
|
91
|
+
* Counts the `.svg` files in whichever `assets/<assetsName>` directory `selectAssetsDir` would read
|
|
92
|
+
* from, for a caller to report alongside a resolved-but-empty-key miss - confirms which directory is in
|
|
93
|
+
* play and how populated it is, which "the directory exists" alone doesn't convey.
|
|
94
|
+
*/
|
|
95
|
+
function countAssets(templatesDir, bundledTemplatesDir, assetsName) {
|
|
96
|
+
try {
|
|
97
|
+
return (0, fs_1.readdirSync)(selectAssetsDir(templatesDir, bundledTemplatesDir, assetsName)).filter((name) => name.endsWith(".svg")).length;
|
|
98
|
+
}
|
|
99
|
+
catch {
|
|
100
|
+
return 0;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
@@ -136,7 +136,7 @@ class SvgRenderer {
|
|
|
136
136
|
console.error(key
|
|
137
137
|
? `${pluginVersion_1.PLUGIN_NAME}: image "${descElement.textContent}" has no asset file for value "${key}" in "${binding.assets}"`
|
|
138
138
|
: `${pluginVersion_1.PLUGIN_NAME}: image "${descElement.textContent}" resolved to empty value to select asset`);
|
|
139
|
-
console.error(`${pluginVersion_1.PLUGIN_NAME}: ${dirProblem ?? `
|
|
139
|
+
console.error(`${pluginVersion_1.PLUGIN_NAME}: ${dirProblem ?? `directory "${binding.assets}" found with ${(0, assets_1.countAssets)(templatesDir, bundledTemplatesDir, binding.assets)} assets`}`);
|
|
140
140
|
element.parentNode?.removeChild(element);
|
|
141
141
|
continue;
|
|
142
142
|
}
|
package/dist/repaintScheduler.js
CHANGED
|
@@ -16,8 +16,10 @@ const unitCategories_1 = require("./unitCategories");
|
|
|
16
16
|
const pathMeta_1 = require("./pathMeta");
|
|
17
17
|
const resolveApiUrl_1 = require("./resolveApiUrl");
|
|
18
18
|
const pluginVersion_1 = require("./pluginVersion");
|
|
19
|
+
const httpJson_1 = require("./httpJson");
|
|
19
20
|
const INTERVAL_POLL_MS = 60000;
|
|
20
21
|
const SUBSCRIPTION_DEBOUNCE_MS = 2000;
|
|
22
|
+
const RESOURCES_API_PATH = "/signalk/v2/api/resources";
|
|
21
23
|
/**
|
|
22
24
|
* The most recent wall-clock instant at or before `now` that an `interval`-triggered device's own
|
|
23
25
|
* periodic check (below, in `startRepaintScheduler`) would fire at - every `intervalHours` hours,
|
|
@@ -85,13 +87,16 @@ function setAtPath(target, path, value) {
|
|
|
85
87
|
* CLI's HTTP-fetched equivalent (`assembleLiveContext` in `cli/liveContext.ts`), so a `path=` binding
|
|
86
88
|
* resolves to the same value either way - without it, `resolveBinding` would hand back the whole
|
|
87
89
|
* wrapper object instead of e.g. a plain string, breaking any binding that expects one (a `<image>`'s
|
|
88
|
-
* `assets=`, a `format=` formatter, etc). `resources`-sourced bindings
|
|
89
|
-
* in-process too, with no such wrapper
|
|
90
|
-
*
|
|
91
|
-
*
|
|
92
|
-
*
|
|
93
|
-
*
|
|
94
|
-
*
|
|
90
|
+
* `assets=`, a `format=` formatter, etc). `resources`-sourced bindings with no `provider=` pin go
|
|
91
|
+
* through `app.resourcesApi` in-process too, with no such wrapper - but a `provider=`-pinned binding
|
|
92
|
+
* goes over HTTP instead (see the resources loop below), since the in-process API doesn't actually
|
|
93
|
+
* honor `providerId` on signalk-server 2.30.0. Per-path unit-conversion metadata (`pathMeta`, for
|
|
94
|
+
* automatic conversion - see `renderBinding`) and an explicit `category=` binding's resolved
|
|
95
|
+
* conversion both have no in-process equivalent (confirmed against the signalk-server source - that
|
|
96
|
+
* resolution only happens in its REST layer), so both need `apiUrl` - fetching `pathMeta` is
|
|
97
|
+
* best-effort (a missing/unreachable server just means no automatic conversion), but a `category=`
|
|
98
|
+
* binding (and now a `provider=`-pinned resource binding) is a declared dependency, so a missing
|
|
99
|
+
* `apiUrl` is a hard error there.
|
|
95
100
|
*/
|
|
96
101
|
async function assembleRawContext(app, apiUrl, bindings) {
|
|
97
102
|
var _a;
|
|
@@ -130,13 +135,26 @@ async function assembleRawContext(app, apiUrl, bindings) {
|
|
|
130
135
|
resourceBindings.set((0, binding_1.resourceContextKey)(binding), binding);
|
|
131
136
|
}
|
|
132
137
|
for (const [key, binding] of resourceBindings) {
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
138
|
+
if (binding.provider) {
|
|
139
|
+
// `app.resourcesApi.listResources(resType, params, providerId)` validates providerId against the
|
|
140
|
+
// registered providers but then - confirmed against signalk-server 2.30.0's own source - ignores
|
|
141
|
+
// it and merges every registered provider's results together (its internal `listFromAll`), so a
|
|
142
|
+
// second provider for the same resource type can silently clobber the one a binding pinned. The
|
|
143
|
+
// REST API's own `?provider=` query param doesn't have this bug (it queries only that provider),
|
|
144
|
+
// so a pinned binding goes over HTTP instead of the in-process API to actually get what it asked for.
|
|
145
|
+
if (!apiUrl) {
|
|
146
|
+
throw new Error(`binding pins resource "${binding.resource}" to provider "${binding.provider}" but no SignalK API base URL is configured`);
|
|
147
|
+
}
|
|
148
|
+
resources[key] = await (0, httpJson_1.fetchJson)(`${apiUrl}${RESOURCES_API_PATH}/${binding.resource}?provider=${encodeURIComponent(binding.provider)}`);
|
|
149
|
+
}
|
|
150
|
+
else {
|
|
151
|
+
// `listResources`'s type only allows the standard SignalKResourceType union, but the underlying
|
|
152
|
+
// Resources API (and a custom provider like signalk-tides, registered under the non-standard
|
|
153
|
+
// "tides" type) accepts any registered resource type string - this cast matches `getResource`'s
|
|
154
|
+
// wider, accurate signature. No `provider=` pin here, so the in-process call's default-provider
|
|
155
|
+
// behavior (whichever the server picks) is fine - and cheaper than a redundant HTTP round trip.
|
|
156
|
+
resources[key] = await app.resourcesApi.listResources(binding.resource, {}, undefined);
|
|
157
|
+
}
|
|
140
158
|
}
|
|
141
159
|
const categoryNames = new Set(bindings.filter((binding) => binding.category).map((binding) => binding.category));
|
|
142
160
|
if (categoryNames.size > 0 && !apiUrl) {
|
package/package.json
CHANGED
package/templates/tide.svg
CHANGED
|
@@ -12,7 +12,10 @@
|
|
|
12
12
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
|
13
13
|
xmlns:xlink="http://www.w3.org/1999/xlink"
|
|
14
14
|
xmlns="http://www.w3.org/2000/svg"
|
|
15
|
-
xmlns:svg="http://www.w3.org/2000/svg"
|
|
15
|
+
xmlns:svg="http://www.w3.org/2000/svg"
|
|
16
|
+
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
|
17
|
+
xmlns:cc="http://creativecommons.org/ns#"
|
|
18
|
+
xmlns:dc="http://purl.org/dc/elements/1.1/"><defs
|
|
16
19
|
id="defs1" /><sodipodi:namedview
|
|
17
20
|
id="namedview1"
|
|
18
21
|
pagecolor="#ffffff"
|