signalk-tides 1.2.3 → 1.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/dist/calculations.js +27 -0
- package/dist/index.js +26 -8
- package/package.json +1 -1
- package/CONTRIBUTING.md +0 -1
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.approximateTideHeightAt = approximateTideHeightAt;
|
|
4
|
+
/** Given a list of tide extremes, estimate the height at a specific time. */
|
|
5
|
+
function approximateTideHeightAt(extremes, time) {
|
|
6
|
+
const sorted = extremes.slice().sort((a, b) => new Date(a.time).getTime() - new Date(b.time).getTime());
|
|
7
|
+
const prev = sorted.filter(h => new Date(h.time) <= time).at(-1);
|
|
8
|
+
const next = sorted.filter(h => new Date(h.time) >= time).at(0);
|
|
9
|
+
if (!prev)
|
|
10
|
+
throw new Error("Missing height data before " + time.toISOString());
|
|
11
|
+
if (!next)
|
|
12
|
+
throw new Error("Missing height data after " + time.toISOString());
|
|
13
|
+
const progress = (time.getTime() - new Date(prev.time).getTime()) /
|
|
14
|
+
(new Date(next.time).getTime() - new Date(prev.time).getTime());
|
|
15
|
+
const value = interpolate(prev.value, next.value, easeSine(progress));
|
|
16
|
+
return parseFloat(value.toFixed(3));
|
|
17
|
+
}
|
|
18
|
+
/** Interpolate between two values using the given progress (0-1). */
|
|
19
|
+
function interpolate(start, end, progress) {
|
|
20
|
+
return start + (end - start) * progress;
|
|
21
|
+
}
|
|
22
|
+
function easeSine(progress) {
|
|
23
|
+
// Map progress [0..1] to angle [0..π]
|
|
24
|
+
const angle = progress * Math.PI;
|
|
25
|
+
// Use sine to ease in/out
|
|
26
|
+
return (1 - Math.cos(angle)) / 2;
|
|
27
|
+
}
|
package/dist/index.js
CHANGED
|
@@ -20,10 +20,12 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
20
20
|
const noaa_js_1 = __importDefault(require("./sources/noaa.js"));
|
|
21
21
|
const stormglass_js_1 = __importDefault(require("./sources/stormglass.js"));
|
|
22
22
|
const worldtides_js_1 = __importDefault(require("./sources/worldtides.js"));
|
|
23
|
+
const calculations_js_1 = require("./calculations.js");
|
|
23
24
|
module.exports = function (app) {
|
|
24
25
|
// Interval to update tide data
|
|
25
26
|
const defaultPeriod = 60; // 1 hour
|
|
26
27
|
let unsubscribes = [];
|
|
28
|
+
let lastForecast = null;
|
|
27
29
|
const sources = [
|
|
28
30
|
(0, noaa_js_1.default)(app),
|
|
29
31
|
(0, stormglass_js_1.default)(app),
|
|
@@ -52,7 +54,7 @@ module.exports = function (app) {
|
|
|
52
54
|
period: {
|
|
53
55
|
title: "Update frequency",
|
|
54
56
|
type: "number",
|
|
55
|
-
description: "How often to update tide
|
|
57
|
+
description: "How often to update tide forecast (minutes)",
|
|
56
58
|
default: 60,
|
|
57
59
|
minimum: 1,
|
|
58
60
|
},
|
|
@@ -104,18 +106,16 @@ module.exports = function (app) {
|
|
|
104
106
|
// @ts-expect-error: TODO[TS]: fix Delta type upstream
|
|
105
107
|
values.forEach(({ path }) => {
|
|
106
108
|
if (path === "navigation.position") {
|
|
107
|
-
|
|
109
|
+
updateForecast();
|
|
108
110
|
}
|
|
109
111
|
});
|
|
110
112
|
});
|
|
111
113
|
});
|
|
112
|
-
async function
|
|
114
|
+
async function updateForecast(now = new Date()) {
|
|
113
115
|
try {
|
|
114
|
-
|
|
115
|
-
// Use server date, or current date if not available
|
|
116
|
-
const now = new Date(app.getSelfPath("navigation.datetime.value") ?? Date.now());
|
|
116
|
+
lastForecast = await provider();
|
|
117
117
|
const nextTide = {};
|
|
118
|
-
extremes.forEach(({ type, value, time }) => {
|
|
118
|
+
lastForecast.extremes.forEach(({ type, value, time }) => {
|
|
119
119
|
// Get the first tide of this type after now
|
|
120
120
|
if (!nextTide[type] && new Date(time) > now) {
|
|
121
121
|
nextTide[type] = { time, value };
|
|
@@ -137,6 +137,7 @@ module.exports = function (app) {
|
|
|
137
137
|
};
|
|
138
138
|
app.debug("Sending delta: " + JSON.stringify(delta));
|
|
139
139
|
app.handleMessage(plugin.id, delta);
|
|
140
|
+
updateHeightNow();
|
|
140
141
|
app.setPluginStatus("Updated tide data");
|
|
141
142
|
}
|
|
142
143
|
catch (e) {
|
|
@@ -146,8 +147,25 @@ module.exports = function (app) {
|
|
|
146
147
|
app.error(e);
|
|
147
148
|
}
|
|
148
149
|
}
|
|
150
|
+
async function updateHeightNow(now = new Date()) {
|
|
151
|
+
if (!lastForecast)
|
|
152
|
+
return;
|
|
153
|
+
// Combine heights and extremes to account for min/max being between height samples
|
|
154
|
+
const height = (0, calculations_js_1.approximateTideHeightAt)(lastForecast.extremes, now);
|
|
155
|
+
app.handleMessage(plugin.id, {
|
|
156
|
+
context: "vessels." + app.selfId,
|
|
157
|
+
updates: [
|
|
158
|
+
{
|
|
159
|
+
timestamp: now.toISOString(),
|
|
160
|
+
values: [{ path: "environment.tide.heightNow", value: height }]
|
|
161
|
+
}
|
|
162
|
+
]
|
|
163
|
+
});
|
|
164
|
+
}
|
|
149
165
|
// Perform initial update on startup after short delay to allow gnss position to be populated
|
|
150
|
-
delay(4000).then(() => {
|
|
166
|
+
delay(4000).then(() => { updateForecast(); });
|
|
167
|
+
// Update heightNow every minute
|
|
168
|
+
setInterval(updateHeightNow, 60 * 1000);
|
|
151
169
|
};
|
|
152
170
|
function delay(time) {
|
|
153
171
|
return new Promise((resolve) => setTimeout(resolve, time));
|
package/package.json
CHANGED
package/CONTRIBUTING.md
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
# Contributing
|