signalk-tides 1.4.0 → 2.0.0-beta.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/.github/workflows/ci.yml +65 -0
- package/.playwright-mcp/console-2026-06-06T09-48-18-232Z.log +1 -0
- package/.playwright-mcp/console-2026-06-12T13-01-03-706Z.log +1 -0
- package/.playwright-mcp/console-2026-06-12T13-15-30-205Z.log +44 -0
- package/.playwright-mcp/console-2026-06-12T13-16-00-389Z.log +1 -0
- package/README.md +25 -178
- package/dist/cache.js +8 -11
- package/dist/calculations.js +7 -10
- package/dist/index.js +95 -82
- package/dist/middleware.js +49 -0
- package/dist/routes.js +176 -0
- package/dist/sources/index.js +7 -0
- package/dist/sources/neaps.js +47 -0
- package/dist/sources/noaa.js +250 -88
- package/dist/sources/stormglass.js +189 -46
- package/dist/sources/worldtides.js +211 -45
- package/dist/types.js +1 -2
- package/package.json +38 -19
- package/public/assets/index-8PLt-an_.css +1 -0
- package/public/assets/index-CvXA6qTu.js +12 -0
- package/public/assets/maplibre-gl-lX2dHdJ0.js +800 -0
- package/public/index.html +3 -3
- package/tides-dev-server.ts +119 -0
- package/tsconfig.json +2 -1
- package/tsconfig.node.json +2 -2
- package/tsconfig.test.json +8 -0
- package/vitest.config.browser.ts +27 -0
- package/vitest.config.node.ts +18 -0
- package/public/assets/index-DDL3NhwZ.js +0 -49
- package/public/assets/index-v5sE8dbG.css +0 -1
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push: {}
|
|
5
|
+
|
|
6
|
+
jobs:
|
|
7
|
+
lint:
|
|
8
|
+
name: Lint
|
|
9
|
+
runs-on: ubuntu-latest
|
|
10
|
+
steps:
|
|
11
|
+
- name: Checkout repository
|
|
12
|
+
uses: actions/checkout@v6
|
|
13
|
+
|
|
14
|
+
- name: Setup Node.js
|
|
15
|
+
uses: actions/setup-node@v6
|
|
16
|
+
|
|
17
|
+
- name: Install dependencies
|
|
18
|
+
run: npm install
|
|
19
|
+
|
|
20
|
+
- name: Run linter
|
|
21
|
+
run: npm run lint
|
|
22
|
+
|
|
23
|
+
test:
|
|
24
|
+
name: Test
|
|
25
|
+
runs-on: ubuntu-latest
|
|
26
|
+
env:
|
|
27
|
+
CI: true
|
|
28
|
+
steps:
|
|
29
|
+
- name: Checkout repository
|
|
30
|
+
uses: actions/checkout@v6
|
|
31
|
+
|
|
32
|
+
- name: Setup Node.js
|
|
33
|
+
uses: actions/setup-node@v6
|
|
34
|
+
|
|
35
|
+
- name: Install dependencies
|
|
36
|
+
run: npm install
|
|
37
|
+
|
|
38
|
+
- name: Install Playwright browsers
|
|
39
|
+
run: npx playwright install chromium
|
|
40
|
+
|
|
41
|
+
- name: Run build
|
|
42
|
+
run: npm run build
|
|
43
|
+
|
|
44
|
+
- name: Run Tests
|
|
45
|
+
run: npm run test
|
|
46
|
+
|
|
47
|
+
publish:
|
|
48
|
+
needs: [lint, test]
|
|
49
|
+
runs-on: ubuntu-latest
|
|
50
|
+
permissions:
|
|
51
|
+
id-token: write
|
|
52
|
+
pull-requests: write
|
|
53
|
+
steps:
|
|
54
|
+
- uses: actions/checkout@v6
|
|
55
|
+
|
|
56
|
+
- uses: actions/setup-node@v6
|
|
57
|
+
|
|
58
|
+
- name: Install modules
|
|
59
|
+
run: npm install
|
|
60
|
+
|
|
61
|
+
- name: Build
|
|
62
|
+
run: npm run build
|
|
63
|
+
|
|
64
|
+
- name: Publish to pkg.pr.new
|
|
65
|
+
run: npx pkg-pr-new publish
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
[ 2058ms] [ERROR] Failed to load resource: net::ERR_NETWORK_IO_SUSPENDED @ https://docs.stormglass.io/_media/logo.svg:0
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
[ 239ms] [ERROR] Failed to load resource: the server responded with a status of 404 (Not Found) @ http://localhost:3000/signalk-tides/assets/icon.svg:0
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
[ 260ms] [LOG] [ConnectionStateMachine] Service initialized @ http://localhost:3000/@mxtommy/kip/chunk-2TP7C66X.js:0
|
|
2
|
+
[ 265ms] [LOG] [AppInit Network Service] Connection Configuration not found. Creating configuration using Auto-Discovery URL: http://localhost:3000 @ http://localhost:3000/@mxtommy/kip/main-UBENKC2D.js:0
|
|
3
|
+
[ 268ms] [LOG] [ConnectionStateMachine] Starting HTTP discovery: Connecting to http://localhost:3000 @ http://localhost:3000/@mxtommy/kip/chunk-2TP7C66X.js:0
|
|
4
|
+
[ 268ms] [LOG] [Connection Service] Connecting to: http://localhost:3000 @ http://localhost:3000/@mxtommy/kip/chunk-2TP7C66X.js:0
|
|
5
|
+
[ 279ms] [LOG] [ConnectionStateMachine] HTTP discovery successful @ http://localhost:3000/@mxtommy/kip/chunk-2TP7C66X.js:0
|
|
6
|
+
[ 279ms] [LOG] [AppSettings Service] Service startup... @ http://localhost:3000/@mxtommy/kip/chunk-2TP7C66X.js:3
|
|
7
|
+
[ 279ms] [LOG] [AppSettings Service] LocalStorage enabled @ http://localhost:3000/@mxtommy/kip/chunk-2TP7C66X.js:4
|
|
8
|
+
[ 279ms] [LOG] [AppSettings Service] Error loading appConfig config. Force loading appConfig defaults @ http://localhost:3000/@mxtommy/kip/chunk-2TP7C66X.js:4
|
|
9
|
+
[ 279ms] [LOG] [AppSettings Service] Error loading dashboardsConfig config. Force loading dashboardsConfig defaults @ http://localhost:3000/@mxtommy/kip/chunk-2TP7C66X.js:4
|
|
10
|
+
[ 279ms] [LOG] [AppSettings Service] Error loading themeConfig config. Force loading themeConfig defaults @ http://localhost:3000/@mxtommy/kip/chunk-2TP7C66X.js:4
|
|
11
|
+
[ 280ms] [LOG] [AppSettings Service] Saving Application config to LocalStorage @ http://localhost:3000/@mxtommy/kip/chunk-2TP7C66X.js:4
|
|
12
|
+
[ 280ms] [LOG] [DatasetStreamService] Auto Starting 0 Datasets @ http://localhost:3000/@mxtommy/kip/chunk-5SMHTIVS.js:0
|
|
13
|
+
[ 280ms] [LOG] [AppInit Network Service] Initialization completed @ http://localhost:3000/@mxtommy/kip/main-UBENKC2D.js:0
|
|
14
|
+
[ 280ms] [LOG] [ConnectionStateMachine] WebSocket mode enabled @ http://localhost:3000/@mxtommy/kip/chunk-2TP7C66X.js:0
|
|
15
|
+
[ 280ms] [LOG] [AppInit Network Service] Starting WebSocket connection after initialization @ http://localhost:3000/@mxtommy/kip/main-UBENKC2D.js:0
|
|
16
|
+
[ 280ms] [LOG] [ConnectionStateMachine] Starting WebSocket connection @ http://localhost:3000/@mxtommy/kip/chunk-2TP7C66X.js:0
|
|
17
|
+
[ 280ms] [LOG] [Delta Service] ConnectionStateMachine request: WebSocket opening... @ http://localhost:3000/@mxtommy/kip/chunk-IXUKD73N.js:0
|
|
18
|
+
[ 287ms] [WARNING] [Dashboard Service] No dashboards found in settings, creating blank dashboard @ http://localhost:3000/@mxtommy/kip/chunk-5SMHTIVS.js:0
|
|
19
|
+
[ 289ms] [LOG] [Remote Dashboards] Cleaning paths on server @ http://localhost:3000/@mxtommy/kip/main-UBENKC2D.js:0
|
|
20
|
+
[ 290ms] [LOG] [UI Event Service] PWA mode: false @ http://localhost:3000/@mxtommy/kip/chunk-5SMHTIVS.js:49
|
|
21
|
+
[ 300ms] [LOG] *********** KIP Version Information *********** @ http://localhost:3000/@mxtommy/kip/chunk-NS2OV2OW.js:0
|
|
22
|
+
[ 300ms] [LOG] ** App Version: 4.8.0 @ http://localhost:3000/@mxtommy/kip/chunk-NS2OV2OW.js:0
|
|
23
|
+
[ 300ms] [LOG] ** Browser Version: Chrome 149 @ http://localhost:3000/@mxtommy/kip/chunk-NS2OV2OW.js:0
|
|
24
|
+
[ 300ms] [LOG] ** OS Version: macOS @ http://localhost:3000/@mxtommy/kip/chunk-NS2OV2OW.js:0
|
|
25
|
+
[ 300ms] [LOG] *********************************************** @ http://localhost:3000/@mxtommy/kip/chunk-NS2OV2OW.js:0
|
|
26
|
+
[ 305ms] [LOG] [AppSettings Service] Saving Dashboard config to LocalStorage @ http://localhost:3000/@mxtommy/kip/chunk-2TP7C66X.js:4
|
|
27
|
+
[ 323ms] [LOG] [Delta Service] WebSocket connected without Authorization Token @ http://localhost:3000/@mxtommy/kip/chunk-IXUKD73N.js:0
|
|
28
|
+
[ 324ms] [LOG] [ConnectionStateMachine] WebSocket connected @ http://localhost:3000/@mxtommy/kip/chunk-2TP7C66X.js:0
|
|
29
|
+
[ 324ms] [LOG] [Connection Service] Server Name: signalk-server, Version: 2.23.0-beta.1, Roles: ["master","main"] @ http://localhost:3000/@mxtommy/kip/chunk-2TP7C66X.js:0
|
|
30
|
+
[ 437ms] [WARNING] [Request Service] Status Code: 403 - DENIED: Authorization with R/W or Admin permission level is required to send commands. Configure Sign In credential. @ http://localhost:3000/@mxtommy/kip/chunk-W6MCE3GH.js:0
|
|
31
|
+
[ 437ms] [WARNING] [Request Service] Status Code: 403 - DENIED: Authorization with R/W or Admin permission level is required to send commands. Configure Sign In credential. @ http://localhost:3000/@mxtommy/kip/chunk-W6MCE3GH.js:0
|
|
32
|
+
[ 437ms] [WARNING] [Request Service] Status Code: 403 - DENIED: Authorization with R/W or Admin permission level is required to send commands. Configure Sign In credential. @ http://localhost:3000/@mxtommy/kip/chunk-W6MCE3GH.js:0
|
|
33
|
+
[ 450ms] [WARNING] An iframe which has both allow-scripts and allow-same-origin for its sandbox attribute can escape its sandboxing. @ http://localhost:3000/@mxtommy/kip/chunk-LEY6MANN.js:3
|
|
34
|
+
[ 515ms] [WARNING] An iframe which has both allow-scripts and allow-same-origin for its sandbox attribute can escape its sandboxing. @ http://localhost:3000/@signalk/freeboard-sk/:0
|
|
35
|
+
[ 1311ms] [ERROR] Failed to load resource: the server responded with a status of 401 (Unauthorized) @ http://localhost:3000/plugins/freeboard-sk:0
|
|
36
|
+
[ 1387ms] [ERROR] Failed to load resource: the server responded with a status of 401 (Unauthorized) @ http://localhost:3000/plugins/kip:0
|
|
37
|
+
[ 1387ms] [LOG] [KipSeriesApiClientService] POST http://localhost:3000/plugins/kip/series/reconcile (0 series) @ http://localhost:3000/@mxtommy/kip/chunk-6ZR3M3IQ.js:2
|
|
38
|
+
[ 1403ms] [INFO] Internet connection detected. @ http://localhost:3000/@signalk/freeboard-sk/main-YHMZXR5G.js:249
|
|
39
|
+
[ 1414ms] [ERROR] Failed to load resource: the server responded with a status of 401 (Unauthorized) @ http://localhost:3000/plugins/kip/series/reconcile:0
|
|
40
|
+
[ 1414ms] [ERROR] [KipSeriesApiClientService] Series reconcile request failed: Ar @ http://localhost:3000/@mxtommy/kip/chunk-6ZR3M3IQ.js:2
|
|
41
|
+
[ 1517ms] [ERROR] Failed to load resource: the server responded with a status of 404 (Not Found) @ http://localhost:3000/signalk/v1/api/vessels/self/navigation/anchor:0
|
|
42
|
+
[ 1784ms] [WARNING] Blocked aria-hidden on an element because its descendant retained focus. The focus must not be hidden from assistive technology users. Avoid using aria-hidden on a focused element or its ancestor. Consider using the inert attribute instead, which will also prevent focus. For more details, see the aria-hidden section of the WAI-ARIA specification at https://w3c.github.io/aria/#aria-hidden.
|
|
43
|
+
Element with focus: <div>
|
|
44
|
+
Ancestor with aria-hidden: <app-root> @ http://localhost:3000/@signalk/freeboard-sk/:0
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
[ 68ms] [LOG] [Delta Service] App suspended @ http://localhost:3000/@mxtommy/kip/chunk-IXUKD73N.js:0
|
package/README.md
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
# signalk-tides
|
|
2
2
|
|
|
3
|
-
A SignalK plugin that provides tidal predictions for the vessel's position
|
|
3
|
+
A SignalK plugin that provides offline tidal predictions for the vessel's position, powered by [Neaps](https://github.com/neaps/neaps).
|
|
4
|
+
|
|
5
|
+
Since 2.0, predictions are computed locally from harmonic constituents — no network access or API keys required.
|
|
4
6
|
|
|
5
7
|
## Installation
|
|
6
8
|
|
|
7
|
-
|
|
9
|
+
Install `signalk-tides` from the SignalK Appstore or manually by running `npm install signalk-tides` in the SignalK server directory (`~/.signalk`).
|
|
8
10
|
|
|
9
|
-
2. Optionally go to the plugin settings in "Server => Plugin Config => Tides" and configure which source to use.
|
|
10
11
|
|
|
11
12
|
## Usage
|
|
12
13
|
|
|
@@ -21,195 +22,41 @@ It publishes the following [tide data](https://signalk.org/specification/1.7.0/d
|
|
|
21
22
|
* `environment.tide.heightNow`
|
|
22
23
|
* `environment.tide.stationName`
|
|
23
24
|
|
|
24
|
-
### Tides
|
|
25
|
+
### Tides API
|
|
25
26
|
|
|
26
|
-
|
|
27
|
+
The plugin mounts the [Neaps API](https://github.com/neaps/neaps) at `/signalk/v2/api/tides`, which serves station search, extremes, and timeline predictions. The synthetic station `vessel/current` resolves to the nearest station to the vessel:
|
|
27
28
|
|
|
28
29
|
```
|
|
29
|
-
$ curl http://localhost:3000/signalk/v2/api/
|
|
30
|
+
$ curl http://localhost:3000/signalk/v2/api/tides/stations/vessel/current/extremes
|
|
30
31
|
```
|
|
31
32
|
|
|
32
|
-
|
|
33
|
+
### Tides resource
|
|
34
|
+
|
|
35
|
+
It also registers a `tides` resource, which returns the next 7 days of tide extremes for the vessel's position.
|
|
33
36
|
|
|
34
|
-
|
|
37
|
+
```
|
|
38
|
+
$ curl http://localhost:3000/signalk/v2/api/resources/tides
|
|
39
|
+
```
|
|
35
40
|
|
|
36
41
|
##### Response
|
|
37
42
|
|
|
38
43
|
```json
|
|
39
44
|
{
|
|
40
|
-
"
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
"time" : "2025-03-29T13:18:00.000Z",
|
|
53
|
-
"type" : "Low",
|
|
54
|
-
"value" : 0.044
|
|
55
|
-
},
|
|
56
|
-
{
|
|
57
|
-
"time" : "2025-03-29T19:45:00.000Z",
|
|
58
|
-
"type" : "High",
|
|
59
|
-
"value" : 1.815
|
|
60
|
-
},
|
|
61
|
-
{
|
|
62
|
-
"time" : "2025-03-30T01:24:00.000Z",
|
|
63
|
-
"type" : "Low",
|
|
64
|
-
"value" : 0.164
|
|
65
|
-
},
|
|
66
|
-
{
|
|
67
|
-
"time" : "2025-03-30T07:52:00.000Z",
|
|
68
|
-
"type" : "High",
|
|
69
|
-
"value" : 2.024
|
|
70
|
-
},
|
|
71
|
-
{
|
|
72
|
-
"time" : "2025-03-30T14:05:00.000Z",
|
|
73
|
-
"type" : "Low",
|
|
74
|
-
"value" : -0.131
|
|
75
|
-
},
|
|
76
|
-
{
|
|
77
|
-
"time" : "2025-03-30T20:43:00.000Z",
|
|
78
|
-
"type" : "High",
|
|
79
|
-
"value" : 1.733
|
|
80
|
-
},
|
|
81
|
-
{
|
|
82
|
-
"time" : "2025-03-31T02:05:00.000Z",
|
|
83
|
-
"type" : "Low",
|
|
84
|
-
"value" : 0.334
|
|
85
|
-
},
|
|
86
|
-
{
|
|
87
|
-
"time" : "2025-03-31T08:27:00.000Z",
|
|
88
|
-
"type" : "High",
|
|
89
|
-
"value" : 2.084
|
|
90
|
-
},
|
|
91
|
-
{
|
|
92
|
-
"time" : "2025-03-31T14:53:00.000Z",
|
|
93
|
-
"type" : "Low",
|
|
94
|
-
"value" : -0.247
|
|
95
|
-
},
|
|
96
|
-
{
|
|
97
|
-
"time" : "2025-03-31T21:44:00.000Z",
|
|
98
|
-
"type" : "High",
|
|
99
|
-
"value" : 1.632
|
|
100
|
-
},
|
|
101
|
-
{
|
|
102
|
-
"time" : "2025-04-01T02:48:00.000Z",
|
|
103
|
-
"type" : "Low",
|
|
104
|
-
"value" : 0.517
|
|
105
|
-
},
|
|
106
|
-
{
|
|
107
|
-
"time" : "2025-04-01T09:06:00.000Z",
|
|
108
|
-
"type" : "High",
|
|
109
|
-
"value" : 2.094
|
|
110
|
-
},
|
|
111
|
-
{
|
|
112
|
-
"time" : "2025-04-01T15:46:00.000Z",
|
|
113
|
-
"type" : "Low",
|
|
114
|
-
"value" : -0.29
|
|
115
|
-
},
|
|
116
|
-
{
|
|
117
|
-
"time" : "2025-04-01T22:51:00.000Z",
|
|
118
|
-
"type" : "High",
|
|
119
|
-
"value" : 1.529
|
|
120
|
-
},
|
|
121
|
-
{
|
|
122
|
-
"time" : "2025-04-02T03:37:00.000Z",
|
|
123
|
-
"type" : "Low",
|
|
124
|
-
"value" : 0.695
|
|
125
|
-
},
|
|
126
|
-
{
|
|
127
|
-
"time" : "2025-04-02T09:49:00.000Z",
|
|
128
|
-
"type" : "High",
|
|
129
|
-
"value" : 2.05
|
|
130
|
-
},
|
|
131
|
-
{
|
|
132
|
-
"time" : "2025-04-02T16:43:00.000Z",
|
|
133
|
-
"type" : "Low",
|
|
134
|
-
"value" : -0.263
|
|
135
|
-
},
|
|
136
|
-
{
|
|
137
|
-
"time" : "2025-04-03T00:04:00.000Z",
|
|
138
|
-
"type" : "High",
|
|
139
|
-
"value" : 1.448
|
|
140
|
-
},
|
|
141
|
-
{
|
|
142
|
-
"time" : "2025-04-03T04:35:00.000Z",
|
|
143
|
-
"type" : "Low",
|
|
144
|
-
"value" : 0.847
|
|
145
|
-
},
|
|
146
|
-
{
|
|
147
|
-
"time" : "2025-04-03T10:39:00.000Z",
|
|
148
|
-
"type" : "High",
|
|
149
|
-
"value" : 1.957
|
|
150
|
-
},
|
|
151
|
-
{
|
|
152
|
-
"time" : "2025-04-03T17:50:00.000Z",
|
|
153
|
-
"type" : "Low",
|
|
154
|
-
"value" : -0.189
|
|
155
|
-
},
|
|
156
|
-
{
|
|
157
|
-
"time" : "2025-04-04T01:24:00.000Z",
|
|
158
|
-
"type" : "High",
|
|
159
|
-
"value" : 1.421
|
|
160
|
-
},
|
|
161
|
-
{
|
|
162
|
-
"time" : "2025-04-04T05:49:00.000Z",
|
|
163
|
-
"type" : "Low",
|
|
164
|
-
"value" : 0.946
|
|
165
|
-
},
|
|
166
|
-
{
|
|
167
|
-
"time" : "2025-04-04T11:40:00.000Z",
|
|
168
|
-
"type" : "High",
|
|
169
|
-
"value" : 1.837
|
|
170
|
-
},
|
|
171
|
-
{
|
|
172
|
-
"time" : "2025-04-04T19:07:00.000Z",
|
|
173
|
-
"type" : "Low",
|
|
174
|
-
"value" : -0.11
|
|
175
|
-
},
|
|
176
|
-
{
|
|
177
|
-
"time" : "2025-04-05T02:40:00.000Z",
|
|
178
|
-
"type" : "High",
|
|
179
|
-
"value" : 1.455
|
|
180
|
-
},
|
|
181
|
-
{
|
|
182
|
-
"time" : "2025-04-05T07:19:00.000Z",
|
|
183
|
-
"type" : "Low",
|
|
184
|
-
"value" : 0.958
|
|
185
|
-
},
|
|
186
|
-
{
|
|
187
|
-
"time" : "2025-04-05T12:53:00.000Z",
|
|
188
|
-
"type" : "High",
|
|
189
|
-
"value" : 1.728
|
|
190
|
-
},
|
|
191
|
-
{
|
|
192
|
-
"time" : "2025-04-05T20:25:00.000Z",
|
|
193
|
-
"type" : "Low",
|
|
194
|
-
"value" : -0.061
|
|
195
|
-
}
|
|
196
|
-
],
|
|
197
|
-
"station" : {
|
|
198
|
-
"name" : "Rincon Point, Pier 22 1/2",
|
|
199
|
-
"position" : {
|
|
200
|
-
"latitude" : 37.79,
|
|
201
|
-
"longitude" : -122.387
|
|
202
|
-
}
|
|
203
|
-
}
|
|
45
|
+
"datum": "MLLW",
|
|
46
|
+
"units": "meters",
|
|
47
|
+
"station": {
|
|
48
|
+
"id": "noaa/9414290",
|
|
49
|
+
"name": "San Francisco",
|
|
50
|
+
"latitude": 37.806,
|
|
51
|
+
"longitude": -122.465
|
|
52
|
+
},
|
|
53
|
+
"extremes": [
|
|
54
|
+
{ "time": "2025-03-29T00:45:00.000Z", "level": 0.025, "high": false, "low": true, "label": "Low" },
|
|
55
|
+
{ "time": "2025-03-29T07:20:00.000Z", "level": 1.928, "high": true, "low": false, "label": "High" }
|
|
56
|
+
]
|
|
204
57
|
}
|
|
205
58
|
```
|
|
206
59
|
|
|
207
|
-
## Sources
|
|
208
|
-
|
|
209
|
-
- [NOAA](https://tidesandcurrents.noaa.gov/web_services_info.html) (US only)
|
|
210
|
-
- [WorldTides API](https://www.worldtides.info/) (requires an API key)
|
|
211
|
-
- [StormGlass.io](https://stormglass.io/) (requires an API key)
|
|
212
|
-
|
|
213
60
|
## License
|
|
214
61
|
|
|
215
62
|
This plugin is a fork of the [signalk-tides-api](https://github.com/joabakk/signalk-tides-api) plugin (which is no longer working) and is licensed under the [Apache License 2.0](LICENSE). Kudos to @joabakk and @sbender9 for the original work.
|
package/dist/cache.js
CHANGED
|
@@ -1,28 +1,25 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
const promises_1 = require("fs/promises");
|
|
5
|
-
class FileCache {
|
|
1
|
+
import { join } from "path";
|
|
2
|
+
import { writeFile, readFile, mkdir } from "fs/promises";
|
|
3
|
+
export default class FileCache {
|
|
6
4
|
path;
|
|
7
5
|
constructor(path) {
|
|
8
6
|
this.path = path;
|
|
9
7
|
}
|
|
10
8
|
async get(key) {
|
|
11
9
|
try {
|
|
12
|
-
const content = await
|
|
10
|
+
const content = await readFile(this.getKey(key), "utf-8");
|
|
13
11
|
return JSON.parse(content);
|
|
14
12
|
}
|
|
15
|
-
catch
|
|
13
|
+
catch {
|
|
16
14
|
return undefined;
|
|
17
15
|
}
|
|
18
16
|
}
|
|
19
17
|
async set(key, value) {
|
|
20
18
|
// Ensure directory exists
|
|
21
|
-
await
|
|
22
|
-
return
|
|
19
|
+
await mkdir(this.path, { recursive: true });
|
|
20
|
+
return writeFile(this.getKey(key), JSON.stringify(value));
|
|
23
21
|
}
|
|
24
22
|
getKey(key) {
|
|
25
|
-
return
|
|
23
|
+
return join(this.path, `${key}.json`);
|
|
26
24
|
}
|
|
27
25
|
}
|
|
28
|
-
exports.default = FileCache;
|
package/dist/calculations.js
CHANGED
|
@@ -1,18 +1,15 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.approximateTideHeightAt = approximateTideHeightAt;
|
|
4
1
|
/** 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) =>
|
|
7
|
-
const prev = sorted.filter(h =>
|
|
8
|
-
const next = sorted.filter(h =>
|
|
2
|
+
export function approximateTideHeightAt(extremes, time) {
|
|
3
|
+
const sorted = extremes.slice().sort((a, b) => a.time.getTime() - b.time.getTime());
|
|
4
|
+
const prev = sorted.filter(h => h.time <= time).at(-1);
|
|
5
|
+
const next = sorted.filter(h => h.time >= time).at(0);
|
|
9
6
|
if (!prev)
|
|
10
7
|
throw new Error("Missing height data before " + time.toISOString());
|
|
11
8
|
if (!next)
|
|
12
9
|
throw new Error("Missing height data after " + time.toISOString());
|
|
13
|
-
const progress = (time.getTime() -
|
|
14
|
-
(
|
|
15
|
-
const value = interpolate(prev.
|
|
10
|
+
const progress = (time.getTime() - prev.time.getTime()) /
|
|
11
|
+
(next.time.getTime() - prev.time.getTime());
|
|
12
|
+
const value = interpolate(prev.level, next.level, easeSine(progress));
|
|
16
13
|
return parseFloat(value.toFixed(3));
|
|
17
14
|
}
|
|
18
15
|
/** Interpolate between two values using the given progress (0-1). */
|