signalk-openwakeword 0.0.1 → 0.2.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/README.md +152 -9
- package/dist/config.d.ts +162 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +255 -0
- package/dist/config.js.map +1 -0
- package/dist/index.d.ts +35 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +160 -0
- package/dist/index.js.map +1 -0
- package/dist/service.d.ts +137 -0
- package/dist/service.d.ts.map +1 -0
- package/dist/service.js +465 -0
- package/dist/service.js.map +1 -0
- package/dist/wyoming.d.ts +30 -0
- package/dist/wyoming.d.ts.map +1 -0
- package/dist/wyoming.js +152 -0
- package/dist/wyoming.js.map +1 -0
- package/package.json +63 -5
- package/public/172.mjs +1 -0
- package/public/540.mjs +2 -0
- package/public/540.mjs.LICENSE.txt +9 -0
- package/public/main.mjs +1 -0
- package/public/remoteEntry.js +1 -0
- package/index.js +0 -23
package/README.md
CHANGED
|
@@ -1,16 +1,159 @@
|
|
|
1
1
|
# signalk-openwakeword
|
|
2
2
|
|
|
3
|
-
> **Status:
|
|
3
|
+
> **Status: ALPHA.** This SignalK Wyoming system is 100% vibecoded slop. I
|
|
4
|
+
> don't have the right hardware yet to test it, so I'm putting it out there
|
|
5
|
+
> for people to test in the meantime. It _should_ work. File issues for
|
|
6
|
+
> anything that doesn't.
|
|
4
7
|
|
|
5
|
-
|
|
8
|
+
## What is this?
|
|
6
9
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
Wake word detection for [Signal K](https://signalk.org) — the part of a
|
|
11
|
+
voice assistant that listens for "okay nabu" (or "hey jarvis", "alexa", …)
|
|
12
|
+
so the rest of the stack knows when to start paying attention. The plugin
|
|
13
|
+
runs [openWakeWord](https://github.com/rhasspy/wyoming-openwakeword) as a
|
|
14
|
+
background service and takes care of everything around it: starting it in a
|
|
15
|
+
container (via the
|
|
16
|
+
[signalk-container](https://www.npmjs.com/package/signalk-container)
|
|
17
|
+
plugin), checking that it stays healthy, and telling the rest of the voice
|
|
18
|
+
stack where to find it. You never have to touch docker or podman yourself.
|
|
19
|
+
|
|
20
|
+
It is the wake-word building block of the
|
|
21
|
+
[signalk-wyoming voice-assistant family](https://github.com/hoeken/signalk-wyoming)
|
|
22
|
+
— install it together with the `signalk-wyoming` orchestrator,
|
|
23
|
+
`signalk-whisper` (speech to text), and `signalk-piper` (text to speech) to
|
|
24
|
+
get voice commands on your boat. Because it speaks the standard
|
|
25
|
+
[Wyoming protocol](https://github.com/rhasspy/wyoming), it also works as a
|
|
26
|
+
standalone wake word server for other software such as Home Assistant.
|
|
27
|
+
|
|
28
|
+
**Fully offline:** all wake word models ship inside the container image.
|
|
29
|
+
First start pulls the ~90 MB image and nothing else — no model downloads,
|
|
30
|
+
no surprises at sea.
|
|
31
|
+
|
|
32
|
+
## Requirements
|
|
33
|
+
|
|
34
|
+
- Signal K server ≥ 2.x on **Node 24+**
|
|
35
|
+
- The **signalk-container** plugin with a working podman or docker runtime
|
|
36
|
+
- ~384 MB RAM headroom for the container (the default memory cap)
|
|
37
|
+
- amd64 or arm64 (no armv7 — upstream stopped publishing it)
|
|
38
|
+
|
|
39
|
+
## Install
|
|
40
|
+
|
|
41
|
+
Install **signalk-openwakeword** from the Signal K App Store (or
|
|
42
|
+
`npm install signalk-openwakeword` in your server directory), enable it in
|
|
43
|
+
Plugin Config, and enable the signalk-container plugin if you have not
|
|
44
|
+
already. The plugin pulls and starts a pinned, tested release of the
|
|
45
|
+
service and reports `ready` once the detector actually answers — not just
|
|
46
|
+
once the container is up.
|
|
47
|
+
|
|
48
|
+
## Configuration
|
|
49
|
+
|
|
50
|
+
The plugin ships a graphical configuration panel (Server → Plugin Config →
|
|
51
|
+
openWakeWord) with a live container status card, a one-click image update
|
|
52
|
+
check/apply, a version dropdown fed by Docker Hub, wake word checkboxes
|
|
53
|
+
driven by the models the running service actually advertises, and all the
|
|
54
|
+
settings below — with inline warnings when a selected wake word is missing
|
|
55
|
+
or the service is open to the network. On servers without custom-panel
|
|
56
|
+
support you get a plain settings form with the same options.
|
|
57
|
+
|
|
58
|
+
| Setting | Default | Notes |
|
|
59
|
+
| ---------------------------- | ---------------- | ----------------------------------------------------------------------------------------------------------------------------------------- |
|
|
60
|
+
| `wakeWords` | `["okay_nabu"]` | Wake words your satellites use. See [Wake words & sensitivity](#wake-words--sensitivity). |
|
|
61
|
+
| `threshold` | `0.5` | Wake probability threshold (0–1). Lower = more sensitive, more false wakes. |
|
|
62
|
+
| `triggerLevel` | `1` | Activations above the threshold before a detection fires. Raise it in noisy cabins. |
|
|
63
|
+
| `port` | `10400` | Host TCP port the Wyoming service is published on. |
|
|
64
|
+
| `bind` | `0.0.0.0` | Host interface for the published port. See [Security](#security). |
|
|
65
|
+
| `imageTag` | `auto` | `auto` runs the pinned, tested upstream release (**2.1.0**) and follows plugin updates. Set an explicit Docker tag to pin something else. |
|
|
66
|
+
| `memoryLimit` | `384m` | Container memory cap (swap disabled). |
|
|
67
|
+
| `restartPolicy` | `unless-stopped` | Container restart policy. |
|
|
68
|
+
| `advanced.refractorySeconds` | _(unset)_ | Minimum seconds between re-detections (upstream default 2.0). |
|
|
69
|
+
| `advanced.customModels` | `false` | Load your own model files. See [Custom wake words](#custom-wake-words). |
|
|
70
|
+
| `advanced.advertiseHost` | _(unset)_ | Overrides the host part of the advertised `tcp://` URI (containerized Signal K, multi-NIC hosts). |
|
|
71
|
+
|
|
72
|
+
### Wake words & sensitivity
|
|
73
|
+
|
|
74
|
+
The built-in wake words are `okay_nabu` (default), `hey_jarvis`,
|
|
75
|
+
`hey_mycroft`, `alexa`, and `hey_rhasspy`. The `wakeWords` list is what
|
|
76
|
+
your satellites will listen for — it is validated against the running
|
|
77
|
+
service and shared with the `signalk-wyoming` orchestrator, and the config
|
|
78
|
+
panel warns you if a selected word is not available (note: upstream 2.0.0
|
|
79
|
+
renamed `ok_nabu` to `okay_nabu`; the old name silently matches nothing).
|
|
80
|
+
|
|
81
|
+
Tuning for your boat:
|
|
82
|
+
|
|
83
|
+
- **Missing wakes** (it doesn't hear you): lower `threshold` a little, e.g.
|
|
84
|
+
`0.4`.
|
|
85
|
+
- **False wakes** (it triggers on engine noise or conversation): raise
|
|
86
|
+
`threshold`, or raise `triggerLevel` to `2`–`3` so a single borderline
|
|
87
|
+
hit isn't enough.
|
|
88
|
+
- **Double triggers** from one utterance: set
|
|
89
|
+
`advanced.refractorySeconds` (upstream default is 2 seconds between
|
|
90
|
+
re-detections).
|
|
91
|
+
|
|
92
|
+
## Custom wake words
|
|
93
|
+
|
|
94
|
+
Want your boat to answer to its own name? Enable
|
|
95
|
+
`advanced.customModels`, then drop openWakeWord `.tflite` model files into
|
|
96
|
+
the `custom/` folder inside the **signalk-container** plugin's data
|
|
97
|
+
directory (`<signalk>/plugin-config-data/signalk-container/custom/` —
|
|
98
|
+
create `custom/` if it doesn't exist; note this is signalk-container's
|
|
99
|
+
directory, shared by all plugins that use it, not this plugin's own) and
|
|
100
|
+
restart the plugin. If Signal K itself runs in a container with a
|
|
101
|
+
volume-backed data directory, put the files in the corresponding location
|
|
102
|
+
inside that volume. A `_v1.0`-style filename suffix is stripped for the
|
|
103
|
+
model id. A webapp upload UI is planned for v1.x; the manual drop works
|
|
104
|
+
today.
|
|
105
|
+
|
|
106
|
+
## Using it from other software
|
|
107
|
+
|
|
108
|
+
Once ready, the service is a plain Wyoming wake word server at
|
|
109
|
+
`tcp://<boat-server>:10400`:
|
|
110
|
+
|
|
111
|
+
- **signalk-wyoming** discovers it automatically — nothing to configure.
|
|
112
|
+
- **Remote satellites** (cockpit Pis running `wyoming-satellite`) point at
|
|
113
|
+
it with `--wake-uri tcp://<boat-server>:10400 --wake-word-name okay_nabu`.
|
|
114
|
+
- **Home Assistant** (or any other Wyoming client) can use it via the
|
|
115
|
+
Wyoming integration at the same URI — no Signal K required on the client
|
|
116
|
+
side.
|
|
117
|
+
|
|
118
|
+
## HTTP API
|
|
119
|
+
|
|
120
|
+
| Endpoint | Access | Purpose |
|
|
121
|
+
| ----------------------------------------------------- | ---------------------- | ---------------------------------------------------------------------------------------------- |
|
|
122
|
+
| `GET /plugins/signalk-openwakeword/api/status` | any authenticated user | Current state: `{ status, uri, tag, containerState, lastHealth, info }` |
|
|
123
|
+
| `GET /plugins/signalk-openwakeword/api/versions` | any authenticated user | Available image versions from Docker Hub (feeds the config panel; works while plugin disabled) |
|
|
124
|
+
| `GET /plugins/signalk-openwakeword/api/update/check` | admin | Check whether a newer image is available |
|
|
125
|
+
| `POST /plugins/signalk-openwakeword/api/update/apply` | admin | Pull and switch to the newer image |
|
|
126
|
+
|
|
127
|
+
## Health & notifications
|
|
128
|
+
|
|
129
|
+
The plugin checks the service every 30 seconds. If it stops answering,
|
|
130
|
+
after three consecutive failures (about 90 seconds) it raises the Signal K
|
|
131
|
+
notification **`notifications.voice.openwakeword`** with `state: "alarm"`
|
|
132
|
+
and shows an error in Plugin Config. When the service answers again
|
|
133
|
+
everything clears back to normal automatically — no action needed.
|
|
134
|
+
|
|
135
|
+
The alarm is visual-only by design: plugins that read notifications aloud
|
|
136
|
+
won't try to _speak_ the voice stack's own failure.
|
|
137
|
+
|
|
138
|
+
## Security
|
|
139
|
+
|
|
140
|
+
Wyoming has **no authentication.** Unlike whisper/piper (loopback-only by
|
|
141
|
+
default), the wake word service must be reachable from your LAN so remote
|
|
142
|
+
satellites can stream audio to it — that is why `bind` defaults to
|
|
143
|
+
`0.0.0.0`. The exposure is modest (openWakeWord only ever sees audio a
|
|
144
|
+
client chooses to send it, and only ever answers with detections), but the
|
|
145
|
+
_satellites_ on the same network are open live microphones — treat every
|
|
146
|
+
satellite port like a baby monitor. On marina wifi, put the boat network
|
|
147
|
+
behind a firewall or VLAN, or use WireGuard between boat segments. If every
|
|
148
|
+
satellite runs on the server itself, set `bind` to `127.0.0.1`.
|
|
149
|
+
|
|
150
|
+
## Development
|
|
151
|
+
|
|
152
|
+
See [DEVELOPERS.md](DEVELOPERS.md) for the code layout, build/test
|
|
153
|
+
commands, architecture notes, and the service-discovery contract.
|
|
13
154
|
|
|
14
155
|
## License
|
|
15
156
|
|
|
16
|
-
Apache-2.0
|
|
157
|
+
Apache-2.0 © hoeken. The container image it runs is
|
|
158
|
+
[rhasspy/wyoming-openwakeword](https://github.com/rhasspy/wyoming-openwakeword)
|
|
159
|
+
(MIT).
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configuration: settings type, defaults, JSON schema for the Signal K
|
|
3
|
+
* Plugin Config UI, and the pure settings → container-config mapping.
|
|
4
|
+
*/
|
|
5
|
+
import type { ContainerConfig } from "signalk-container-helper";
|
|
6
|
+
export declare const PLUGIN_ID = "signalk-openwakeword";
|
|
7
|
+
export declare const PLUGIN_NAME = "openWakeWord (Wyoming)";
|
|
8
|
+
export declare const IMAGE = "rhasspy/wyoming-openwakeword";
|
|
9
|
+
/** Tag that `imageTag: "auto"` resolves to. */
|
|
10
|
+
export declare const PINNED_TAG = "2.1.0";
|
|
11
|
+
/** Wyoming port inside the container (baked into the image's ENTRYPOINT). */
|
|
12
|
+
export declare const WYOMING_PORT = 10400;
|
|
13
|
+
/** Container name (unprefixed; runtime name is `<namespace>-openwakeword`). */
|
|
14
|
+
export declare const CONTAINER_NAME = "openwakeword";
|
|
15
|
+
/** Short service name used in `notifications.voice.<service>`. */
|
|
16
|
+
export declare const SERVICE_NAME = "openwakeword";
|
|
17
|
+
/**
|
|
18
|
+
* Wake word models bundled with wyoming-openwakeword 2.x. Note the 2.0.0
|
|
19
|
+
* breaking rename: `ok_nabu` → `okay_nabu`.
|
|
20
|
+
*/
|
|
21
|
+
export declare const BUILTIN_WAKE_WORDS: string[];
|
|
22
|
+
export interface AdvancedSettings {
|
|
23
|
+
/** → --refractory-seconds (upstream default 2.0 when omitted). */
|
|
24
|
+
refractorySeconds?: number;
|
|
25
|
+
/**
|
|
26
|
+
* Mount the shared signalk-container data dir at /data and pass
|
|
27
|
+
* --custom-model-dir /data/custom.
|
|
28
|
+
*/
|
|
29
|
+
customModels: boolean;
|
|
30
|
+
/** Replaces the host part of the advertised wyoming-service uri. */
|
|
31
|
+
advertiseHost?: string;
|
|
32
|
+
}
|
|
33
|
+
export interface OpenWakeWordSettings {
|
|
34
|
+
imageTag: string;
|
|
35
|
+
/** Host TCP port the container's Wyoming port is published on. */
|
|
36
|
+
port: number;
|
|
37
|
+
/** Host interface the port binds to. LAN-reachable by default (see §8). */
|
|
38
|
+
bind: "0.0.0.0" | "127.0.0.1";
|
|
39
|
+
/**
|
|
40
|
+
* Wake words satellites may use. NOT passed to the container (2.x selects
|
|
41
|
+
* models per client via the Wyoming `Detect` event) — validated against
|
|
42
|
+
* the service's `info` response and surfaced for orchestrator/docs use.
|
|
43
|
+
*/
|
|
44
|
+
wakeWords: string[];
|
|
45
|
+
/** → --threshold (0–1). */
|
|
46
|
+
threshold: number;
|
|
47
|
+
/** → --trigger-level (activations above threshold before a detection). */
|
|
48
|
+
triggerLevel: number;
|
|
49
|
+
memoryLimit: string;
|
|
50
|
+
restartPolicy: "no" | "unless-stopped" | "always";
|
|
51
|
+
advanced: AdvancedSettings;
|
|
52
|
+
}
|
|
53
|
+
export declare const DEFAULT_SETTINGS: OpenWakeWordSettings;
|
|
54
|
+
/**
|
|
55
|
+
* Merge raw plugin config over the defaults. Signal K does NOT seed schema
|
|
56
|
+
* defaults into a plugin's saved configuration, so every field must be
|
|
57
|
+
* defaulted here. Tolerates missing/malformed input.
|
|
58
|
+
*/
|
|
59
|
+
export declare function withDefaults(raw: unknown): OpenWakeWordSettings;
|
|
60
|
+
/** Map `auto` to the pinned upstream release; explicit tags pass through. */
|
|
61
|
+
export declare function resolveTag(requested: string): string;
|
|
62
|
+
/** True for plain numeric semver tags like "2.1.0" (update-check filter). */
|
|
63
|
+
export declare function isSemverTag(tag: string): boolean;
|
|
64
|
+
/**
|
|
65
|
+
* Container CLI args, appended after the image's baked-in
|
|
66
|
+
* `--uri tcp://0.0.0.0:10400`. Always present and deterministic so
|
|
67
|
+
* signalk-container's drift detection never sees a phantom change.
|
|
68
|
+
*/
|
|
69
|
+
export declare function buildCommand(settings: OpenWakeWordSettings): string[];
|
|
70
|
+
/**
|
|
71
|
+
* Pure settings → ContainerConfig mapping (helper `buildConfig`).
|
|
72
|
+
*
|
|
73
|
+
* openWakeWord must be LAN-reachable for remote satellites (SPEC §8), so the
|
|
74
|
+
* port is published explicitly via `ports` with a default bind of 0.0.0.0 —
|
|
75
|
+
* NOT via `signalkAccessiblePorts` (the two must never share a container
|
|
76
|
+
* port: the loopback mapping would overwrite the explicit binding).
|
|
77
|
+
*/
|
|
78
|
+
export declare function buildContainerConfig(settings: OpenWakeWordSettings, tag: string): ContainerConfig;
|
|
79
|
+
export declare const CONFIG_SCHEMA: {
|
|
80
|
+
type: string;
|
|
81
|
+
properties: {
|
|
82
|
+
wakeWords: {
|
|
83
|
+
type: string;
|
|
84
|
+
title: string;
|
|
85
|
+
items: {
|
|
86
|
+
type: string;
|
|
87
|
+
};
|
|
88
|
+
default: string[];
|
|
89
|
+
description: string;
|
|
90
|
+
};
|
|
91
|
+
threshold: {
|
|
92
|
+
type: string;
|
|
93
|
+
title: string;
|
|
94
|
+
minimum: number;
|
|
95
|
+
maximum: number;
|
|
96
|
+
default: number;
|
|
97
|
+
description: string;
|
|
98
|
+
};
|
|
99
|
+
triggerLevel: {
|
|
100
|
+
type: string;
|
|
101
|
+
title: string;
|
|
102
|
+
minimum: number;
|
|
103
|
+
default: number;
|
|
104
|
+
description: string;
|
|
105
|
+
};
|
|
106
|
+
port: {
|
|
107
|
+
type: string;
|
|
108
|
+
title: string;
|
|
109
|
+
default: number;
|
|
110
|
+
description: string;
|
|
111
|
+
};
|
|
112
|
+
bind: {
|
|
113
|
+
type: string;
|
|
114
|
+
title: string;
|
|
115
|
+
enum: string[];
|
|
116
|
+
default: "0.0.0.0" | "127.0.0.1";
|
|
117
|
+
description: string;
|
|
118
|
+
};
|
|
119
|
+
imageTag: {
|
|
120
|
+
type: string;
|
|
121
|
+
title: string;
|
|
122
|
+
default: string;
|
|
123
|
+
description: string;
|
|
124
|
+
};
|
|
125
|
+
memoryLimit: {
|
|
126
|
+
type: string;
|
|
127
|
+
title: string;
|
|
128
|
+
default: string;
|
|
129
|
+
description: string;
|
|
130
|
+
};
|
|
131
|
+
restartPolicy: {
|
|
132
|
+
type: string;
|
|
133
|
+
title: string;
|
|
134
|
+
enum: string[];
|
|
135
|
+
default: "no" | "unless-stopped" | "always";
|
|
136
|
+
description: string;
|
|
137
|
+
};
|
|
138
|
+
advanced: {
|
|
139
|
+
type: string;
|
|
140
|
+
title: string;
|
|
141
|
+
properties: {
|
|
142
|
+
refractorySeconds: {
|
|
143
|
+
type: string;
|
|
144
|
+
title: string;
|
|
145
|
+
description: string;
|
|
146
|
+
};
|
|
147
|
+
customModels: {
|
|
148
|
+
type: string;
|
|
149
|
+
title: string;
|
|
150
|
+
default: boolean;
|
|
151
|
+
description: string;
|
|
152
|
+
};
|
|
153
|
+
advertiseHost: {
|
|
154
|
+
type: string;
|
|
155
|
+
title: string;
|
|
156
|
+
description: string;
|
|
157
|
+
};
|
|
158
|
+
};
|
|
159
|
+
};
|
|
160
|
+
};
|
|
161
|
+
};
|
|
162
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAEhE,eAAO,MAAM,SAAS,yBAAyB,CAAC;AAChD,eAAO,MAAM,WAAW,2BAA2B,CAAC;AACpD,eAAO,MAAM,KAAK,iCAAiC,CAAC;AACpD,+CAA+C;AAC/C,eAAO,MAAM,UAAU,UAAU,CAAC;AAClC,6EAA6E;AAC7E,eAAO,MAAM,YAAY,QAAQ,CAAC;AAClC,+EAA+E;AAC/E,eAAO,MAAM,cAAc,iBAAiB,CAAC;AAC7C,kEAAkE;AAClE,eAAO,MAAM,YAAY,iBAAiB,CAAC;AAE3C;;;GAGG;AACH,eAAO,MAAM,kBAAkB,UAM9B,CAAC;AAEF,MAAM,WAAW,gBAAgB;IAC/B,kEAAkE;IAClE,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B;;;OAGG;IACH,YAAY,EAAE,OAAO,CAAC;IACtB,oEAAoE;IACpE,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,EAAE,MAAM,CAAC;IACjB,kEAAkE;IAClE,IAAI,EAAE,MAAM,CAAC;IACb,2EAA2E;IAC3E,IAAI,EAAE,SAAS,GAAG,WAAW,CAAC;IAC9B;;;;OAIG;IACH,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,2BAA2B;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,0EAA0E;IAC1E,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,IAAI,GAAG,gBAAgB,GAAG,QAAQ,CAAC;IAClD,QAAQ,EAAE,gBAAgB,CAAC;CAC5B;AAED,eAAO,MAAM,gBAAgB,EAAE,oBAY9B,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,OAAO,GAAG,oBAAoB,CA4B/D;AAED,6EAA6E;AAC7E,wBAAgB,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAEpD;AAED,6EAA6E;AAC7E,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAEhD;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,oBAAoB,GAAG,MAAM,EAAE,CAiBrE;AAED;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,oBAAoB,EAC9B,GAAG,EAAE,MAAM,GACV,eAAe,CAsBjB;AAuBD,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAkHzB,CAAC"}
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configuration: settings type, defaults, JSON schema for the Signal K
|
|
3
|
+
* Plugin Config UI, and the pure settings → container-config mapping.
|
|
4
|
+
*/
|
|
5
|
+
export const PLUGIN_ID = "signalk-openwakeword";
|
|
6
|
+
export const PLUGIN_NAME = "openWakeWord (Wyoming)";
|
|
7
|
+
export const IMAGE = "rhasspy/wyoming-openwakeword";
|
|
8
|
+
/** Tag that `imageTag: "auto"` resolves to. */
|
|
9
|
+
export const PINNED_TAG = "2.1.0";
|
|
10
|
+
/** Wyoming port inside the container (baked into the image's ENTRYPOINT). */
|
|
11
|
+
export const WYOMING_PORT = 10400;
|
|
12
|
+
/** Container name (unprefixed; runtime name is `<namespace>-openwakeword`). */
|
|
13
|
+
export const CONTAINER_NAME = "openwakeword";
|
|
14
|
+
/** Short service name used in `notifications.voice.<service>`. */
|
|
15
|
+
export const SERVICE_NAME = "openwakeword";
|
|
16
|
+
/**
|
|
17
|
+
* Wake word models bundled with wyoming-openwakeword 2.x. Note the 2.0.0
|
|
18
|
+
* breaking rename: `ok_nabu` → `okay_nabu`.
|
|
19
|
+
*/
|
|
20
|
+
export const BUILTIN_WAKE_WORDS = [
|
|
21
|
+
"okay_nabu",
|
|
22
|
+
"hey_jarvis",
|
|
23
|
+
"hey_mycroft",
|
|
24
|
+
"alexa",
|
|
25
|
+
"hey_rhasspy",
|
|
26
|
+
];
|
|
27
|
+
export const DEFAULT_SETTINGS = {
|
|
28
|
+
imageTag: "auto",
|
|
29
|
+
port: WYOMING_PORT,
|
|
30
|
+
bind: "0.0.0.0",
|
|
31
|
+
wakeWords: ["okay_nabu"],
|
|
32
|
+
threshold: 0.5,
|
|
33
|
+
triggerLevel: 1,
|
|
34
|
+
memoryLimit: "384m",
|
|
35
|
+
restartPolicy: "unless-stopped",
|
|
36
|
+
advanced: {
|
|
37
|
+
customModels: false,
|
|
38
|
+
},
|
|
39
|
+
};
|
|
40
|
+
/**
|
|
41
|
+
* Merge raw plugin config over the defaults. Signal K does NOT seed schema
|
|
42
|
+
* defaults into a plugin's saved configuration, so every field must be
|
|
43
|
+
* defaulted here. Tolerates missing/malformed input.
|
|
44
|
+
*/
|
|
45
|
+
export function withDefaults(raw) {
|
|
46
|
+
const cfg = isObject(raw) ? raw : {};
|
|
47
|
+
const adv = isObject(cfg.advanced) ? cfg.advanced : {};
|
|
48
|
+
const settings = {
|
|
49
|
+
imageTag: str(cfg.imageTag) ?? DEFAULT_SETTINGS.imageTag,
|
|
50
|
+
port: num(cfg.port) ?? DEFAULT_SETTINGS.port,
|
|
51
|
+
bind: cfg.bind === "127.0.0.1" ? "127.0.0.1" : DEFAULT_SETTINGS.bind,
|
|
52
|
+
wakeWords: strArray(cfg.wakeWords) ?? [...DEFAULT_SETTINGS.wakeWords],
|
|
53
|
+
threshold: num(cfg.threshold) ?? DEFAULT_SETTINGS.threshold,
|
|
54
|
+
triggerLevel: num(cfg.triggerLevel) ?? DEFAULT_SETTINGS.triggerLevel,
|
|
55
|
+
memoryLimit: str(cfg.memoryLimit) ?? DEFAULT_SETTINGS.memoryLimit,
|
|
56
|
+
restartPolicy: cfg.restartPolicy === "no" || cfg.restartPolicy === "always"
|
|
57
|
+
? cfg.restartPolicy
|
|
58
|
+
: DEFAULT_SETTINGS.restartPolicy,
|
|
59
|
+
advanced: {
|
|
60
|
+
customModels: adv.customModels === true,
|
|
61
|
+
},
|
|
62
|
+
};
|
|
63
|
+
const refractory = num(adv.refractorySeconds);
|
|
64
|
+
if (refractory !== undefined) {
|
|
65
|
+
settings.advanced.refractorySeconds = refractory;
|
|
66
|
+
}
|
|
67
|
+
const advertiseHost = str(adv.advertiseHost);
|
|
68
|
+
if (advertiseHost !== undefined && advertiseHost.trim() !== "") {
|
|
69
|
+
settings.advanced.advertiseHost = advertiseHost.trim();
|
|
70
|
+
}
|
|
71
|
+
return settings;
|
|
72
|
+
}
|
|
73
|
+
/** Map `auto` to the pinned upstream release; explicit tags pass through. */
|
|
74
|
+
export function resolveTag(requested) {
|
|
75
|
+
return requested === "auto" ? PINNED_TAG : requested;
|
|
76
|
+
}
|
|
77
|
+
/** True for plain numeric semver tags like "2.1.0" (update-check filter). */
|
|
78
|
+
export function isSemverTag(tag) {
|
|
79
|
+
return /^\d+\.\d+\.\d+$/.test(tag);
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Container CLI args, appended after the image's baked-in
|
|
83
|
+
* `--uri tcp://0.0.0.0:10400`. Always present and deterministic so
|
|
84
|
+
* signalk-container's drift detection never sees a phantom change.
|
|
85
|
+
*/
|
|
86
|
+
export function buildCommand(settings) {
|
|
87
|
+
const command = [
|
|
88
|
+
"--threshold",
|
|
89
|
+
String(settings.threshold),
|
|
90
|
+
"--trigger-level",
|
|
91
|
+
String(settings.triggerLevel),
|
|
92
|
+
];
|
|
93
|
+
if (settings.advanced.refractorySeconds !== undefined) {
|
|
94
|
+
command.push("--refractory-seconds", String(settings.advanced.refractorySeconds));
|
|
95
|
+
}
|
|
96
|
+
if (settings.advanced.customModels) {
|
|
97
|
+
command.push("--custom-model-dir", "/data/custom");
|
|
98
|
+
}
|
|
99
|
+
return command;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Pure settings → ContainerConfig mapping (helper `buildConfig`).
|
|
103
|
+
*
|
|
104
|
+
* openWakeWord must be LAN-reachable for remote satellites (SPEC §8), so the
|
|
105
|
+
* port is published explicitly via `ports` with a default bind of 0.0.0.0 —
|
|
106
|
+
* NOT via `signalkAccessiblePorts` (the two must never share a container
|
|
107
|
+
* port: the loopback mapping would overwrite the explicit binding).
|
|
108
|
+
*/
|
|
109
|
+
export function buildContainerConfig(settings, tag) {
|
|
110
|
+
const config = {
|
|
111
|
+
image: IMAGE,
|
|
112
|
+
tag,
|
|
113
|
+
command: buildCommand(settings),
|
|
114
|
+
ports: {
|
|
115
|
+
[String(WYOMING_PORT)]: `${settings.bind}:${settings.port}`,
|
|
116
|
+
},
|
|
117
|
+
restart: settings.restartPolicy,
|
|
118
|
+
resources: {
|
|
119
|
+
memory: settings.memoryLimit,
|
|
120
|
+
memorySwap: settings.memoryLimit,
|
|
121
|
+
},
|
|
122
|
+
};
|
|
123
|
+
if (settings.advanced.customModels) {
|
|
124
|
+
// signalkDataMount resolves to the signalk-container plugin's OWN data
|
|
125
|
+
// directory (one globally-cached app.getDataDirPath() of that plugin,
|
|
126
|
+
// shared by every consumer) — NOT this plugin's. Users drop .tflite
|
|
127
|
+
// files in <signalk>/plugin-config-data/signalk-container/custom/.
|
|
128
|
+
config.signalkDataMount = "/data";
|
|
129
|
+
}
|
|
130
|
+
return config;
|
|
131
|
+
}
|
|
132
|
+
function isObject(v) {
|
|
133
|
+
return v !== null && typeof v === "object" && !Array.isArray(v);
|
|
134
|
+
}
|
|
135
|
+
function str(v) {
|
|
136
|
+
return typeof v === "string" && v !== "" ? v : undefined;
|
|
137
|
+
}
|
|
138
|
+
function num(v) {
|
|
139
|
+
return typeof v === "number" && Number.isFinite(v) ? v : undefined;
|
|
140
|
+
}
|
|
141
|
+
function strArray(v) {
|
|
142
|
+
if (!Array.isArray(v))
|
|
143
|
+
return undefined;
|
|
144
|
+
const out = v
|
|
145
|
+
.filter((x) => typeof x === "string")
|
|
146
|
+
.map((x) => x.trim())
|
|
147
|
+
.filter((x) => x !== "");
|
|
148
|
+
return out.length > 0 ? out : undefined;
|
|
149
|
+
}
|
|
150
|
+
export const CONFIG_SCHEMA = {
|
|
151
|
+
type: "object",
|
|
152
|
+
properties: {
|
|
153
|
+
wakeWords: {
|
|
154
|
+
type: "array",
|
|
155
|
+
title: "Wake words",
|
|
156
|
+
items: { type: "string" },
|
|
157
|
+
default: [...DEFAULT_SETTINGS.wakeWords],
|
|
158
|
+
description: "Wake word models your satellites will use. Built-ins: " +
|
|
159
|
+
`${BUILTIN_WAKE_WORDS.join(", ")}. NOTE: version 2.0.0 renamed ` +
|
|
160
|
+
"ok_nabu to okay_nabu — old configs using ok_nabu silently match " +
|
|
161
|
+
"nothing. This list is not passed to the container (clients select " +
|
|
162
|
+
"models per connection); it is checked against the running service " +
|
|
163
|
+
"and used by the signalk-wyoming orchestrator.",
|
|
164
|
+
},
|
|
165
|
+
threshold: {
|
|
166
|
+
type: "number",
|
|
167
|
+
title: "Detection threshold",
|
|
168
|
+
minimum: 0,
|
|
169
|
+
maximum: 1,
|
|
170
|
+
default: DEFAULT_SETTINGS.threshold,
|
|
171
|
+
description: "Wake probability required to activate (0–1). Lower = more " +
|
|
172
|
+
"sensitive but more false wakes.",
|
|
173
|
+
},
|
|
174
|
+
triggerLevel: {
|
|
175
|
+
type: "integer",
|
|
176
|
+
title: "Trigger level",
|
|
177
|
+
minimum: 1,
|
|
178
|
+
default: DEFAULT_SETTINGS.triggerLevel,
|
|
179
|
+
description: "Number of activations above the threshold before a detection " +
|
|
180
|
+
"fires. Raise to reduce false wakes in noisy cabins.",
|
|
181
|
+
},
|
|
182
|
+
port: {
|
|
183
|
+
type: "number",
|
|
184
|
+
title: "Host port",
|
|
185
|
+
default: DEFAULT_SETTINGS.port,
|
|
186
|
+
description: "Host TCP port the Wyoming service is published on " +
|
|
187
|
+
"(remote satellites connect to tcp://<boat-server>:<this port>).",
|
|
188
|
+
},
|
|
189
|
+
bind: {
|
|
190
|
+
type: "string",
|
|
191
|
+
title: "Bind address",
|
|
192
|
+
enum: ["0.0.0.0", "127.0.0.1"],
|
|
193
|
+
default: DEFAULT_SETTINGS.bind,
|
|
194
|
+
description: "SECURITY: the default 0.0.0.0 makes the wake word service " +
|
|
195
|
+
"reachable from your whole network — required for remote " +
|
|
196
|
+
"satellites, and safe-ish (it only ever sees audio that clients " +
|
|
197
|
+
"send it), but Wyoming has no authentication, so firewall or VLAN " +
|
|
198
|
+
"the boat network on marina wifi. Set 127.0.0.1 if every satellite " +
|
|
199
|
+
"runs on this machine.",
|
|
200
|
+
},
|
|
201
|
+
imageTag: {
|
|
202
|
+
type: "string",
|
|
203
|
+
title: "Image tag",
|
|
204
|
+
default: DEFAULT_SETTINGS.imageTag,
|
|
205
|
+
description: `Docker tag of ${IMAGE} to run. "auto" pins the tested release ` +
|
|
206
|
+
`(${PINNED_TAG}) and follows plugin updates; set an explicit tag ` +
|
|
207
|
+
"to stay on a specific upstream version.",
|
|
208
|
+
},
|
|
209
|
+
memoryLimit: {
|
|
210
|
+
type: "string",
|
|
211
|
+
title: "Memory limit",
|
|
212
|
+
default: DEFAULT_SETTINGS.memoryLimit,
|
|
213
|
+
description: 'Container memory cap (e.g. "384m", "1g"). Swap is disabled by ' +
|
|
214
|
+
"setting the swap limit to the same value.",
|
|
215
|
+
},
|
|
216
|
+
restartPolicy: {
|
|
217
|
+
type: "string",
|
|
218
|
+
title: "Restart policy",
|
|
219
|
+
enum: ["no", "unless-stopped", "always"],
|
|
220
|
+
default: DEFAULT_SETTINGS.restartPolicy,
|
|
221
|
+
description: "Container restart policy passed to docker/podman.",
|
|
222
|
+
},
|
|
223
|
+
advanced: {
|
|
224
|
+
type: "object",
|
|
225
|
+
title: "Advanced",
|
|
226
|
+
properties: {
|
|
227
|
+
refractorySeconds: {
|
|
228
|
+
type: "number",
|
|
229
|
+
title: "Refractory seconds",
|
|
230
|
+
description: "Minimum seconds between repeated detections of the same wake " +
|
|
231
|
+
"word (--refractory-seconds). Upstream default: 2.0.",
|
|
232
|
+
},
|
|
233
|
+
customModels: {
|
|
234
|
+
type: "boolean",
|
|
235
|
+
title: "Enable custom wake word models",
|
|
236
|
+
default: DEFAULT_SETTINGS.advanced.customModels,
|
|
237
|
+
description: "Mount the shared signalk-container plugin data directory into " +
|
|
238
|
+
"the container and load custom .tflite models from its custom/ " +
|
|
239
|
+
"subdirectory (--custom-model-dir /data/custom). Drop model " +
|
|
240
|
+
"files into plugin-config-data/signalk-container/custom/ (NOT " +
|
|
241
|
+
"this plugin's own data directory) and restart the plugin.",
|
|
242
|
+
},
|
|
243
|
+
advertiseHost: {
|
|
244
|
+
type: "string",
|
|
245
|
+
title: "Advertise host",
|
|
246
|
+
description: "Overrides the host part of the tcp:// URI advertised to the " +
|
|
247
|
+
"signalk-wyoming orchestrator (for containerized Signal K or " +
|
|
248
|
+
"multi-NIC hosts where 127.0.0.1 is not what consumers should " +
|
|
249
|
+
"dial). Leave empty for automatic.",
|
|
250
|
+
},
|
|
251
|
+
},
|
|
252
|
+
},
|
|
253
|
+
},
|
|
254
|
+
};
|
|
255
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* signalk-openwakeword — Signal K plugin entry point.
|
|
3
|
+
*
|
|
4
|
+
* Runs rhasspy/wyoming-openwakeword (pinned 2.1.0) as a managed container via
|
|
5
|
+
* signalk-container-helper, gates readiness on a Wyoming `describe` exchange,
|
|
6
|
+
* advertises the service on the shared `wyoming-service` PropertyValues
|
|
7
|
+
* convention, and keeps a protocol-native health loop running.
|
|
8
|
+
*/
|
|
9
|
+
import { type RouterLike } from "signalk-container-helper";
|
|
10
|
+
import { type RunnerTiming, type ServiceApp } from "./service.js";
|
|
11
|
+
export interface PluginApp extends ServiceApp {
|
|
12
|
+
savePluginOptions(configuration: object, callback: (err: unknown) => void): void;
|
|
13
|
+
readPluginOptions?(): {
|
|
14
|
+
configuration?: Record<string, unknown>;
|
|
15
|
+
} | undefined;
|
|
16
|
+
}
|
|
17
|
+
export interface PluginRouter extends RouterLike {
|
|
18
|
+
/** Signal K ≥2.x permission registrar; feature-detected. */
|
|
19
|
+
access?(level: "readonly" | "readwrite"): RouterLike;
|
|
20
|
+
}
|
|
21
|
+
export interface OpenWakeWordPlugin {
|
|
22
|
+
id: string;
|
|
23
|
+
name: string;
|
|
24
|
+
description: string;
|
|
25
|
+
schema: () => object;
|
|
26
|
+
start: (config: object) => void;
|
|
27
|
+
stop: () => Promise<void>;
|
|
28
|
+
registerWithRouter: (router: PluginRouter) => void;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Plugin factory. The optional `timing` parameter is a test seam — the
|
|
32
|
+
* Signal K loader only ever passes `app`.
|
|
33
|
+
*/
|
|
34
|
+
export default function createPlugin(app: PluginApp, timing?: Partial<RunnerTiming>): OpenWakeWordPlugin;
|
|
35
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAML,KAAK,UAAU,EAChB,MAAM,0BAA0B,CAAC;AAalC,OAAO,EAEL,KAAK,YAAY,EACjB,KAAK,UAAU,EAChB,MAAM,cAAc,CAAC;AAEtB,MAAM,WAAW,SAAU,SAAQ,UAAU;IAC3C,iBAAiB,CACf,aAAa,EAAE,MAAM,EACrB,QAAQ,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,IAAI,GAC/B,IAAI,CAAC;IACR,iBAAiB,CAAC,IAAI;QAAE,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,GAAG,SAAS,CAAC;CAC/E;AAOD,MAAM,WAAW,YAAa,SAAQ,UAAU;IAC9C,4DAA4D;IAC5D,MAAM,CAAC,CAAC,KAAK,EAAE,UAAU,GAAG,WAAW,GAAG,UAAU,CAAC;CACtD;AAED,MAAM,WAAW,kBAAkB;IACjC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,MAAM,CAAC;IACrB,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IAChC,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1B,kBAAkB,EAAE,CAAC,MAAM,EAAE,YAAY,KAAK,IAAI,CAAC;CACpD;AAED;;;GAGG;AACH,MAAM,CAAC,OAAO,UAAU,YAAY,CAClC,GAAG,EAAE,SAAS,EACd,MAAM,GAAE,OAAO,CAAC,YAAY,CAAM,GACjC,kBAAkB,CAgJpB"}
|