8 cfg = config.services.wyoming.openwakeword;
30 (mkRemovedOptionModule [ "services" "wyoming" "openwakeword" "models" ] "Configuring models has been removed, they are now dynamically discovered and loaded at runtime")
33 meta.buildDocsInSandbox = false;
35 options.services.wyoming.openwakeword = with types; {
36 enable = mkEnableOption "Wyoming openWakeWord server";
38 package = mkPackageOption pkgs "wyoming-openwakeword" { };
41 type = strMatching "^(tcp|unix)://.*$";
42 default = "tcp://0.0.0.0:10400";
43 example = "tcp://192.0.2.1:5000";
45 URI to bind the wyoming server to.
49 customModelsDirectories = mkOption {
50 type = listOf types.path;
53 Paths to directories with custom wake word models (*.tflite model files).
57 preloadModels = mkOption {
63 # wyoming_openwakeword/models/*.tflite
71 List of wake word models to preload after startup.
75 threshold = mkOption {
79 Activation threshold (0-1), where higher means fewer activations.
81 See trigger level for the relationship between activations and
87 triggerLevel = mkOption {
91 Number of activations before a detection is registered.
93 A higher trigger level means fewer detections.
98 extraArgs = mkOption {
102 Extra arguments to pass to the server commandline.
104 apply = escapeShellArgs;
108 config = mkIf cfg.enable {
109 systemd.services."wyoming-openwakeword" = {
110 description = "Wyoming openWakeWord server";
112 "network-online.target"
115 "network-online.target"
122 User = "wyoming-openwakeword";
123 # https://github.com/home-assistant/addons/blob/master/openwakeword/rootfs/etc/s6-overlay/s6-rc.d/openwakeword/run
124 ExecStart = concatStringsSep " " [
125 "${cfg.package}/bin/wyoming-openwakeword"
127 (concatMapStringsSep " " (model: "--preload-model ${model}") cfg.preloadModels)
128 (concatMapStringsSep " " (dir: "--custom-model-dir ${toString dir}") cfg.customModelsDirectories)
129 "--threshold ${cfg.threshold}"
130 "--trigger-level ${cfg.triggerLevel}"
133 CapabilityBoundingSet = "";
135 DevicePolicy = "closed";
136 LockPersonality = true;
137 MemoryDenyWriteExecute = true;
138 PrivateDevices = true;
141 ProtectHostname = true;
142 ProtectKernelLogs = true;
143 ProtectKernelModules = true;
144 ProtectKernelTunables = true;
145 ProtectControlGroups = true;
146 ProtectProc = "invisible";
147 ProcSubset = "all"; # reads /proc/cpuinfo
148 RestrictAddressFamilies = [
153 RestrictNamespaces = true;
154 RestrictRealtime = true;
155 RuntimeDirectory = "wyoming-openwakeword";
156 SystemCallArchitectures = "native";