8 cfg = config.services.homeassistant-satellite;
25 # override the package with the relevant vad dependencies
26 package = cfg.package.overridePythonAttrs (oldAttrs: {
27 propagatedBuildInputs = oldAttrs.propagatedBuildInputs
28 ++ lib.optional (cfg.vad == "webrtcvad") cfg.package.optional-dependencies.webrtc
29 ++ lib.optional (cfg.vad == "silero") cfg.package.optional-dependencies.silerovad
30 ++ lib.optional (cfg.pulseaudio.enable) cfg.package.optional-dependencies.pulseaudio;
36 meta.buildDocsInSandbox = false;
38 options.services.homeassistant-satellite = with types; {
39 enable = mkEnableOption (mdDoc "Home Assistant Satellite");
41 package = mkPackageOptionMD pkgs "homeassistant-satellite" { };
46 description = mdDoc ''
47 User to run homeassistant-satellite under.
54 description = mdDoc ''
55 Group to run homeassistant-satellite under.
61 example = "home-assistant.local";
62 description = mdDoc ''
63 Hostname on which your Home Assistant instance can be reached.
70 description = mdDoc ''
71 Port on which your Home Assistance can be reached.
77 type = enum [ "http" "https" ];
80 description = mdDoc ''
81 The transport protocol used to connect to Home Assistant.
85 tokenFile = mkOption {
87 example = "/run/keys/hass-token";
88 description = mdDoc ''
89 Path to a file containing a long-lived access token for your Home Assistant instance.
91 apply = escapeShellArg;
98 description = mdDoc ''
99 Audio file to play when the wake word is detected.
106 description = mdDoc ''
107 Audio file to play when the voice command is done.
113 type = enum [ "disabled" "webrtcvad" "silero" ];
114 default = "disabled";
116 description = mdDoc ''
117 Voice activity detection model. With `disabled` sound will be transmitted continously.
122 enable = mkEnableOption "recording/playback via PulseAudio or PipeWire";
127 example = "/run/user/1000/pulse/native";
128 description = mdDoc ''
129 Path or hostname to connect with the PulseAudio server.
133 duckingVolume = mkOption {
137 description = mdDoc ''
138 Reduce output volume (between 0 and 1) to this percentage value while recording.
142 echoCancellation = mkEnableOption "acoustic echo cancellation";
145 extraArgs = mkOption {
148 description = mdDoc ''
149 Extra arguments to pass to the commandline.
151 apply = escapeShellArgs;
155 config = mkIf cfg.enable {
156 systemd.services."homeassistant-satellite" = {
157 description = "Home Assistant Satellite";
159 "network-online.target"
162 "network-online.target"
169 ] ++ lib.optionals (!cfg.pulseaudio.enable) [
175 # https://github.com/rhasspy/hassio-addons/blob/master/assist_microphone/rootfs/etc/s6-overlay/s6-rc.d/assist_microphone/run
177 ${package}/bin/homeassistant-satellite \
180 --protocol ${cfg.protocol} \
181 --token-file ${cfg.tokenFile} \
183 ${lib.optionalString cfg.pulseaudio.enable "--pulseaudio"}${lib.optionalString (cfg.pulseaudio.socket != null) "=${cfg.pulseaudio.socket}"} \
184 ${lib.optionalString (cfg.pulseaudio.enable && cfg.pulseaudio.duckingVolume != null) "--ducking-volume=${toString cfg.pulseaudio.duckingVolume}"} \
185 ${lib.optionalString (cfg.pulseaudio.enable && cfg.pulseaudio.echoCancellation) "--echo-cancel"} \
186 ${lib.optionalString (cfg.sounds.awake != null) "--awake-sound=${toString cfg.sounds.awake}"} \
187 ${lib.optionalString (cfg.sounds.done != null) "--done-sound=${toString cfg.sounds.done}"} \
190 CapabilityBoundingSet = "";
192 DevicePolicy = "closed";
193 LockPersonality = true;
194 MemoryDenyWriteExecute = false; # onnxruntime/capi/onnxruntime_pybind11_state.so: cannot enable executable stack as shared object requires: Operation not permitted
195 PrivateDevices = true;
197 ProtectHome = false; # Would deny access to local pulse/pipewire server
198 ProtectHostname = true;
199 ProtectKernelLogs = true;
200 ProtectKernelModules = true;
201 ProtectKernelTunables = true;
202 ProtectControlGroups = true;
203 ProtectProc = "invisible";
204 ProcSubset = "all"; # Error in cpuinfo: failed to parse processor information from /proc/cpuinfo
206 RestrictAddressFamilies = [
211 RestrictNamespaces = true;
212 RestrictRealtime = true;
213 SupplementaryGroups = [
216 SystemCallArchitectures = "native";