signalk-webhook-bridge 2.0.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/CHANGELOG.md +52 -0
- package/LICENSE +674 -0
- package/README.md +358 -0
- package/assets/icon-128.png +0 -0
- package/docs/screenshots/config.png +0 -0
- package/package.json +63 -0
- package/plugin/index.js +481 -0
- package/plugin/paths.js +38 -0
- package/plugin/storage.js +145 -0
- package/plugin/units.js +90 -0
- package/plugin/webhook.js +52 -0
- package/public/540.main.js +2 -0
- package/public/540.main.js.LICENSE.txt +9 -0
- package/public/651.main.js +2 -0
- package/public/651.main.js.LICENSE.txt +9 -0
- package/public/main.js +2 -0
- package/public/main.js.LICENSE.txt +9 -0
- package/public/remoteEntry.js +1 -0
package/README.md
ADDED
|
@@ -0,0 +1,358 @@
|
|
|
1
|
+
# Webhook Bridge
|
|
2
|
+
|
|
3
|
+
Webhook Bridge is a Signal K server plugin for sending selected vessel data to an external HTTP webhook at a configurable interval.
|
|
4
|
+
|
|
5
|
+
Choose the Signal K data paths you want to send, assign simple field names, select your preferred output units, and Webhook Bridge will deliver them as a JSON payload to your endpoint.
|
|
6
|
+
|
|
7
|
+
If the webhook is unavailable, data is stored locally in a persistent queue and automatically delivered in order when the connection returns.
|
|
8
|
+
|
|
9
|
+
## Features
|
|
10
|
+
|
|
11
|
+
- Send selected Signal K data to any HTTP webhook
|
|
12
|
+
- Choose from Signal K paths currently available on the server
|
|
13
|
+
- Assign custom field names for the outgoing payload
|
|
14
|
+
- Convert supported values into useful output units
|
|
15
|
+
- Configurable delivery interval
|
|
16
|
+
- Optional Bearer token authentication
|
|
17
|
+
- Persistent offline queue using SQLite
|
|
18
|
+
- FIFO delivery preserves the original order of queued updates
|
|
19
|
+
- Queued data survives Signal K and system restarts
|
|
20
|
+
- Automatic retry when the webhook becomes available again
|
|
21
|
+
- Manual **Retry Now** control
|
|
22
|
+
- Live delivery and queue status in the plugin configuration screen
|
|
23
|
+
- Values are sent at their available precision without artificial rounding
|
|
24
|
+
|
|
25
|
+
## How it works
|
|
26
|
+
|
|
27
|
+
Webhook Bridge periodically takes a snapshot of the Signal K paths you have configured.
|
|
28
|
+
|
|
29
|
+
The snapshot is written to the local queue **before** delivery is attempted. This means the data is safely queued even if the network connection or receiving server is unavailable at the time of capture.
|
|
30
|
+
|
|
31
|
+
Webhook Bridge then attempts to deliver the oldest queued entry first.
|
|
32
|
+
|
|
33
|
+
An entry is removed from the queue only after the receiving webhook returns a successful HTTP response. If delivery fails, the entry remains in the queue and later entries wait behind it, preserving chronological order.
|
|
34
|
+
|
|
35
|
+
When connectivity returns, the backlog is automatically delivered oldest first.
|
|
36
|
+
|
|
37
|
+
## Configuration
|
|
38
|
+
|
|
39
|
+
Open **Server → Plugin Config → Webhook Bridge** in the Signal K administration interface.
|
|
40
|
+
|
|
41
|
+
### Webhook URL
|
|
42
|
+
|
|
43
|
+
Enter the HTTP or HTTPS endpoint that should receive the data.
|
|
44
|
+
|
|
45
|
+
For example:
|
|
46
|
+
|
|
47
|
+
```text
|
|
48
|
+
https://example.com/api/vessel-data
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### Authentication Key
|
|
52
|
+
|
|
53
|
+
An optional authentication key can be supplied.
|
|
54
|
+
|
|
55
|
+
When configured, Webhook Bridge sends it using the HTTP `Authorization` header as a Bearer token:
|
|
56
|
+
|
|
57
|
+
```text
|
|
58
|
+
Authorization: Bearer YOUR_KEY
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### Send Interval
|
|
62
|
+
|
|
63
|
+
Sets the interval, in minutes, between data snapshots.
|
|
64
|
+
|
|
65
|
+
Each snapshot is stored in the local queue before Webhook Bridge attempts to send it.
|
|
66
|
+
|
|
67
|
+
### Signal K Data Paths
|
|
68
|
+
|
|
69
|
+
Add the Signal K values that you want to include in each webhook update.
|
|
70
|
+
|
|
71
|
+
For each path you can configure:
|
|
72
|
+
|
|
73
|
+
**Signal K Path**
|
|
74
|
+
The source value in Signal K, for example:
|
|
75
|
+
|
|
76
|
+
```text
|
|
77
|
+
navigation.speedOverGround
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
**Webhook Field Name**
|
|
81
|
+
The name that will be used for the value in the outgoing JSON, for example:
|
|
82
|
+
|
|
83
|
+
```text
|
|
84
|
+
speed
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
**Output Units**
|
|
88
|
+
Where supported, the Signal K value can be converted before transmission.
|
|
89
|
+
|
|
90
|
+
The available conversion options depend on the native units of the selected Signal K path.
|
|
91
|
+
|
|
92
|
+
## Supported unit conversions
|
|
93
|
+
|
|
94
|
+
Webhook Bridge currently recognises the following native Signal K units:
|
|
95
|
+
|
|
96
|
+
| Native unit | Available output |
|
|
97
|
+
| --- | --- |
|
|
98
|
+
| `m/s` | Native, knots, km/h, mph |
|
|
99
|
+
| `rad` | Native, degrees |
|
|
100
|
+
| `m` | Native, metres, feet |
|
|
101
|
+
| `K` | Native, Celsius, Fahrenheit |
|
|
102
|
+
| `Pa` | Native, hPa, mbar |
|
|
103
|
+
|
|
104
|
+
Paths using other units can still be sent using their native value.
|
|
105
|
+
|
|
106
|
+
Webhook Bridge does not deliberately round converted values. This allows the receiving application to decide how much precision it requires.
|
|
107
|
+
|
|
108
|
+
## Payload Format
|
|
109
|
+
|
|
110
|
+
Webhook Bridge sends data to the configured URL as an HTTP `POST` request with a JSON body.
|
|
111
|
+
|
|
112
|
+
Each Signal K path configured in the plugin becomes a top-level field in the JSON object. The field name is taken from the **Webhook Field Name** entered in the plugin configuration.
|
|
113
|
+
|
|
114
|
+
For example, if the following paths are configured:
|
|
115
|
+
|
|
116
|
+
| Signal K Path | Webhook Field Name | Output Units |
|
|
117
|
+
| --- | --- | --- |
|
|
118
|
+
| `navigation.speedOverGround` | `speed` | Knots |
|
|
119
|
+
| `environment.depth.belowTransducer` | `depth` | Native |
|
|
120
|
+
|
|
121
|
+
the webhook may receive:
|
|
122
|
+
|
|
123
|
+
```json
|
|
124
|
+
{
|
|
125
|
+
"timestamp": "2026-09-13T10:15:00.000Z",
|
|
126
|
+
"speed": 5.649988373552611,
|
|
127
|
+
"depth": 12.8,
|
|
128
|
+
"units": {
|
|
129
|
+
"speed": "kn",
|
|
130
|
+
"depth": "m"
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
### Timestamp
|
|
136
|
+
|
|
137
|
+
Every request contains a `timestamp` field in ISO 8601 UTC format:
|
|
138
|
+
|
|
139
|
+
```json
|
|
140
|
+
"timestamp": "2026-09-13T10:15:00.000Z"
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
This is the time the snapshot was **captured and added to the local queue**, not necessarily the time it was delivered.
|
|
144
|
+
|
|
145
|
+
This distinction is important when a webhook has been unavailable. Queued updates retain their original capture timestamps when they are subsequently delivered.
|
|
146
|
+
|
|
147
|
+
### Values
|
|
148
|
+
|
|
149
|
+
Values are sent as JSON values rather than Signal K value objects.
|
|
150
|
+
|
|
151
|
+
For example:
|
|
152
|
+
|
|
153
|
+
```json
|
|
154
|
+
"speed": 5.649988373552611
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
rather than:
|
|
158
|
+
|
|
159
|
+
```json
|
|
160
|
+
"speed": {
|
|
161
|
+
"value": 5.649988373552611
|
|
162
|
+
}
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
Webhook Bridge does **not round numeric values**. Converted values are sent at the precision produced by the conversion.
|
|
166
|
+
|
|
167
|
+
### Units
|
|
168
|
+
|
|
169
|
+
Every payload contains a `units` object identifying the units used for each configured field:
|
|
170
|
+
|
|
171
|
+
```json
|
|
172
|
+
"units": {
|
|
173
|
+
"speed": "kn",
|
|
174
|
+
"depth": "m"
|
|
175
|
+
}
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
If **Native** is selected, the unit reported by Signal K metadata is used.
|
|
179
|
+
|
|
180
|
+
If another output unit is selected, Webhook Bridge converts the value before sending it and reports the selected output unit.
|
|
181
|
+
|
|
182
|
+
Common output labels include:
|
|
183
|
+
|
|
184
|
+
| Output unit | Payload label |
|
|
185
|
+
| --- | --- |
|
|
186
|
+
| Knots | `kn` |
|
|
187
|
+
| Kilometres per hour | `km/h` |
|
|
188
|
+
| Miles per hour | `mph` |
|
|
189
|
+
| Metres | `m` |
|
|
190
|
+
| Feet | `ft` |
|
|
191
|
+
| Degrees | `deg` |
|
|
192
|
+
| Celsius | `degC` |
|
|
193
|
+
| Fahrenheit | `degF` |
|
|
194
|
+
| Hectopascals | `hPa` |
|
|
195
|
+
| Millibars | `mbar` |
|
|
196
|
+
|
|
197
|
+
### Authentication
|
|
198
|
+
|
|
199
|
+
If an **Authentication Key** is configured, Webhook Bridge sends it as a Bearer token in the HTTP `Authorization` header:
|
|
200
|
+
|
|
201
|
+
```http
|
|
202
|
+
Authorization: Bearer your-authentication-key
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
If no Authentication Key is configured, the `Authorization` header is omitted.
|
|
206
|
+
|
|
207
|
+
The request body is sent as JSON with:
|
|
208
|
+
|
|
209
|
+
```http
|
|
210
|
+
Content-Type: application/json
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
### Successful Delivery
|
|
214
|
+
|
|
215
|
+
Your webhook should return an HTTP **2xx status code** when the payload has been successfully received and accepted.
|
|
216
|
+
|
|
217
|
+
Only after a successful response is the corresponding update removed from Webhook Bridge's local queue.
|
|
218
|
+
|
|
219
|
+
### Failed Delivery
|
|
220
|
+
|
|
221
|
+
If the webhook cannot be reached, returns an unsuccessful HTTP response, or another delivery error occurs, the queued update is **not deleted**.
|
|
222
|
+
|
|
223
|
+
Webhook Bridge retains it locally and attempts delivery again later.
|
|
224
|
+
|
|
225
|
+
Queued updates are delivered in **FIFO order (oldest first)**. This means that after an outage, the receiving system may receive several requests in succession as Webhook Bridge works through the backlog.
|
|
226
|
+
|
|
227
|
+
Each request retains its original capture `timestamp`, allowing the receiving system to determine when the data was recorded rather than when it eventually arrived.
|
|
228
|
+
|
|
229
|
+
### Receiving the Webhook
|
|
230
|
+
|
|
231
|
+
The receiving application only needs to:
|
|
232
|
+
|
|
233
|
+
1. Accept HTTP `POST` requests at the configured URL.
|
|
234
|
+
2. Parse the request body as JSON.
|
|
235
|
+
3. Optionally validate the Bearer token if authentication is configured.
|
|
236
|
+
4. Process or store the supplied values.
|
|
237
|
+
5. Return a `2xx` HTTP response only when the payload has been successfully accepted.
|
|
238
|
+
|
|
239
|
+
Because field names are user-configurable, receiving applications should not assume particular names such as `speed` or `depth`. They should be written to handle the field names configured for that Webhook Bridge installation.
|
|
240
|
+
|
|
241
|
+
## Offline operation and queueing
|
|
242
|
+
|
|
243
|
+
Webhook Bridge is designed for installations where internet connectivity may be intermittent.
|
|
244
|
+
|
|
245
|
+
This is particularly useful aboard vessels where Signal K may continue collecting data while the connection to a shore-based server is unavailable.
|
|
246
|
+
|
|
247
|
+
Every snapshot is written to a persistent SQLite queue before transmission is attempted.
|
|
248
|
+
|
|
249
|
+
If delivery fails:
|
|
250
|
+
|
|
251
|
+
1. The snapshot remains in the queue.
|
|
252
|
+
2. New snapshots continue to be added at the configured interval.
|
|
253
|
+
3. Webhook Bridge periodically attempts delivery again.
|
|
254
|
+
4. When the webhook becomes available, queued entries are delivered oldest first.
|
|
255
|
+
5. An entry is deleted only after successful delivery.
|
|
256
|
+
|
|
257
|
+
The queue is persistent, so queued entries are retained if Signal K or the host system is restarted.
|
|
258
|
+
|
|
259
|
+
There is intentionally no configurable queue-size limit. The practical limit is the storage available on the host system.
|
|
260
|
+
|
|
261
|
+
## Status
|
|
262
|
+
|
|
263
|
+
The configuration screen provides live information about the webhook connection and local queue, including:
|
|
264
|
+
|
|
265
|
+
- Current delivery state
|
|
266
|
+
- Number of entries waiting
|
|
267
|
+
- Last data capture
|
|
268
|
+
- Last successful delivery
|
|
269
|
+
- Last delivery error, when applicable
|
|
270
|
+
|
|
271
|
+
The status display updates automatically.
|
|
272
|
+
|
|
273
|
+
The **Retry Now** button can be used to immediately attempt delivery of the existing queue. It does **not** create an additional data snapshot.
|
|
274
|
+
|
|
275
|
+
## HTTP responses
|
|
276
|
+
|
|
277
|
+
Webhook Bridge considers a request successfully delivered when the receiving server returns a successful HTTP response.
|
|
278
|
+
|
|
279
|
+
If the receiving server returns an error response, or the request cannot be completed, the queued entry is retained for another attempt.
|
|
280
|
+
|
|
281
|
+
Receivers should therefore return a successful HTTP status only once they have accepted the payload.
|
|
282
|
+
|
|
283
|
+
## Requirements
|
|
284
|
+
|
|
285
|
+
- Signal K Server
|
|
286
|
+
- Node.js 22.5 or later
|
|
287
|
+
|
|
288
|
+
Node.js 22.5+ is required because Webhook Bridge uses the built-in `node:sqlite` module for persistent queue storage.
|
|
289
|
+
|
|
290
|
+
## Installation
|
|
291
|
+
|
|
292
|
+
Install **Webhook Bridge** through the Signal K AppStore.
|
|
293
|
+
|
|
294
|
+
After installation:
|
|
295
|
+
|
|
296
|
+
1. Enable the plugin.
|
|
297
|
+
2. Open its configuration page.
|
|
298
|
+
3. Enter your webhook URL.
|
|
299
|
+
4. Add the Signal K paths you want to send.
|
|
300
|
+
5. Choose field names and output units.
|
|
301
|
+
6. Set the required send interval.
|
|
302
|
+
7. Save the configuration.
|
|
303
|
+
|
|
304
|
+
The status panel can then be used to confirm that data is being captured and delivered.
|
|
305
|
+
|
|
306
|
+
## Development
|
|
307
|
+
|
|
308
|
+
Clone the repository and install the dependencies:
|
|
309
|
+
|
|
310
|
+
```bash
|
|
311
|
+
npm install
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
Build the configuration interface:
|
|
315
|
+
|
|
316
|
+
```bash
|
|
317
|
+
npm run build
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
Run the automated tests:
|
|
321
|
+
|
|
322
|
+
```bash
|
|
323
|
+
npm test
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
Before publishing a release, it is also recommended to run:
|
|
327
|
+
|
|
328
|
+
```bash
|
|
329
|
+
npm audit
|
|
330
|
+
npm pack --dry-run
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
The built configuration interface is included with the published package; the plugin does not rely on an install-time build step.
|
|
334
|
+
|
|
335
|
+
## Data storage
|
|
336
|
+
|
|
337
|
+
The persistent webhook queue is stored within the plugin's Signal K data directory using `app.getDataDirPath()`.
|
|
338
|
+
|
|
339
|
+
Webhook Bridge does not require a separate database server.
|
|
340
|
+
|
|
341
|
+
Authentication keys are configuration values and are not included in webhook status responses.
|
|
342
|
+
|
|
343
|
+
## Licence
|
|
344
|
+
|
|
345
|
+
Copyright © 2026 Matt Barraud.
|
|
346
|
+
|
|
347
|
+
Webhook Bridge is free software licensed under the GNU General Public License v3.0 or later. See [LICENSE](LICENSE) for details.
|
|
348
|
+
|
|
349
|
+
## Author
|
|
350
|
+
|
|
351
|
+
Developed by Matt Barraud.
|
|
352
|
+
|
|
353
|
+
## Source
|
|
354
|
+
|
|
355
|
+
Source code, issues and releases:
|
|
356
|
+
|
|
357
|
+
[github.com/50North4West/signalk-webhook-bridge](https://github.com/50North4West/signalk-webhook-bridge)
|
|
358
|
+
|
|
Binary file
|
|
Binary file
|
package/package.json
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "signalk-webhook-bridge",
|
|
3
|
+
"version": "2.0.0",
|
|
4
|
+
"description": "Send selected Signal K data paths to an external webhook with unit conversion, persistent queueing and automatic retry.",
|
|
5
|
+
"main": "plugin/index.js",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"build": "webpack --mode production",
|
|
8
|
+
"dev": "webpack --mode development --watch",
|
|
9
|
+
"test": "node --test",
|
|
10
|
+
"prepublishOnly": "npm run build && npm test"
|
|
11
|
+
},
|
|
12
|
+
"keywords": [
|
|
13
|
+
"signalk-node-server-plugin",
|
|
14
|
+
"signalk-plugin-configurator",
|
|
15
|
+
"signalk-category-utility",
|
|
16
|
+
"signalk",
|
|
17
|
+
"webhook"
|
|
18
|
+
],
|
|
19
|
+
"signalk-plugin-enabled-by-default": false,
|
|
20
|
+
"engines": {
|
|
21
|
+
"node": ">=22.5.0"
|
|
22
|
+
},
|
|
23
|
+
"signalk": {
|
|
24
|
+
"displayName": "Webhook Bridge",
|
|
25
|
+
"appIcon": "./assets/icon-128.png",
|
|
26
|
+
"screenshots": [
|
|
27
|
+
"./docs/screenshots/config.png"
|
|
28
|
+
]
|
|
29
|
+
},
|
|
30
|
+
"author": "Matt Barraud",
|
|
31
|
+
"license": "GPL-3.0-or-later",
|
|
32
|
+
"repository": {
|
|
33
|
+
"type": "git",
|
|
34
|
+
"url": "https://github.com/50North4West/signalk-webhook-bridge.git"
|
|
35
|
+
},
|
|
36
|
+
"homepage": "https://github.com/50North4West/signalk-webhook-bridge#readme",
|
|
37
|
+
"bugs": {
|
|
38
|
+
"url": "https://github.com/50North4West/signalk-webhook-bridge/issues"
|
|
39
|
+
},
|
|
40
|
+
"files": [
|
|
41
|
+
"plugin/",
|
|
42
|
+
"public/",
|
|
43
|
+
"assets/",
|
|
44
|
+
"docs/screenshots/",
|
|
45
|
+
"README.md",
|
|
46
|
+
"CHANGELOG.md",
|
|
47
|
+
"LICENSE"
|
|
48
|
+
],
|
|
49
|
+
"dependencies": {
|
|
50
|
+
"@signalk/server-admin-ui-dependencies": "^2.23.0",
|
|
51
|
+
"node-fetch": "^2.6.1",
|
|
52
|
+
"react": "^19.3.0",
|
|
53
|
+
"react-dom": "^19.3.0"
|
|
54
|
+
},
|
|
55
|
+
"devDependencies": {
|
|
56
|
+
"@babel/core": "^7.29.7",
|
|
57
|
+
"@babel/preset-env": "^7.29.7",
|
|
58
|
+
"@babel/preset-react": "^7.29.7",
|
|
59
|
+
"babel-loader": "^9.2.1",
|
|
60
|
+
"webpack": "^5.110.3",
|
|
61
|
+
"webpack-cli": "^7.2.3"
|
|
62
|
+
}
|
|
63
|
+
}
|