From e0795c6f4323866c75d55af0706dfea07365efe3 Mon Sep 17 00:00:00 2001 From: matt1432 Date: Sun, 1 Sep 2024 19:19:30 -0400 Subject: [PATCH] feat(homie): init hass service --- devices/cluster/modules/caddy.nix | 2 + devices/homie/default.nix | 2 + devices/homie/modules/home-assistant.nix | 81 ++++++++++++ flake.lock | Bin 52018 -> 51676 bytes flake.nix | Bin 8654 -> 8871 bytes inputs.nix | 7 ++ nixosModules/default.nix | 1 + nixosModules/wyoming-plus/default.nix | 153 +++++++++++++++++++++++ 8 files changed, 246 insertions(+) create mode 100644 devices/homie/modules/home-assistant.nix create mode 100644 nixosModules/wyoming-plus/default.nix diff --git a/devices/cluster/modules/caddy.nix b/devices/cluster/modules/caddy.nix index b16a01c8..fdeea4b6 100644 --- a/devices/cluster/modules/caddy.nix +++ b/devices/cluster/modules/caddy.nix @@ -35,6 +35,7 @@ in { clusterIP = config.services.pcsd.virtualIps.caddy-vip.ip; nosIP = "10.0.0.121"; serviviIP = "10.0.0.249"; + homieIP = "100.64.0.10"; tlsConf = '' tls { @@ -53,6 +54,7 @@ in { // (builtins.removeAttrs extraConf ["extraConfig"]); in { # Public + "Home-Assistant" = mkPublicReverseProxy "homie" "${homieIP}:8123" {}; "Vaultwarden" = mkPublicReverseProxy "vault" "${nosIP}:8781" {}; "Hauk" = mkPublicReverseProxy "hauk" "${nosIP}:3003" {}; "Headscale" = mkPublicReverseProxy "headscale" "${clusterIP}:8085" {}; diff --git a/devices/homie/default.nix b/devices/homie/default.nix index 27f0b27b..23bdf9aa 100644 --- a/devices/homie/default.nix +++ b/devices/homie/default.nix @@ -11,6 +11,8 @@ in { imports = [ ./hardware-configuration.nix + ./modules/home-assistant.nix + self.nixosModules.kmscon self.nixosModules.server ]; diff --git a/devices/homie/modules/home-assistant.nix b/devices/homie/modules/home-assistant.nix new file mode 100644 index 00000000..2bbcbcfe --- /dev/null +++ b/devices/homie/modules/home-assistant.nix @@ -0,0 +1,81 @@ +{ + self, + wakewords-src, + ... +}: { + imports = [self.nixosModules.wyoming-plus]; + + services = { + home-assistant = { + enable = true; + + extraComponents = [ + "esphome" + "holiday" + "met" + "spotify" + "upnp" + "wyoming" + "yamaha_musiccast" + ]; + + config = { + http = { + server_host = "0.0.0.0"; + trusted_proxies = ["100.64.0.8" "100.64.0.9"]; + use_x_forwarded_for = true; + }; + + # Wanted defaults + assist_pipeline = {}; + config = {}; + conversation = {}; + dhcp = {}; + history = {}; + image_upload = {}; + logbook = {}; + mobile_app = {}; + my = {}; + sun = {}; + automation = {}; + zeroconf = {}; + }; + }; + + esphome = { + enable = true; + address = "localhost"; + port = 6052; + }; + + # Needs manual setting in GUI + wyoming = { + piper.servers."en" = { + enable = true; + uri = "tcp://127.0.0.1:10200"; + + # see https://github.com/rhasspy/rhasspy3/blob/master/programs/tts/piper/script/download.py + voice = "en-us-ryan-low"; + speaker = 0; + }; + + faster-whisper.servers."en" = { + enable = true; + uri = "tcp://127.0.0.1:10300"; + + # see https://github.com/rhasspy/rhasspy3/blob/master/programs/asr/faster-whisper/script/download.py + model = "small-int8"; + language = "en"; + device = "cpu"; + }; + + openwakeword-docker = { + enable = true; + uri = "127.0.0.1:10400"; + + customModelsDirectories = ["${wakewords-src}/en/yo_homie"]; + preloadModels = ["yo_homie"]; + }; + }; + }; +} diff --git a/flake.lock b/flake.lock index 1a4d2080a1e0524c57ace4aaeb988a271d83cfeb..55c03168448f3609c6ee1fca6d2fa8e47e0f79ae 100644 GIT binary patch delta 310 zcmdlqjrq=G<_(^zo7L6Va!+0mXgVoAaVi0;<5|g^FUEWme4Q*&Mm;oFFG$@#KRXUYzDehL#4F#>PgIH>%5OxujHhn|kM( zq*!JI8ig5|yJZFX`K9;=r5Jh?I=MPkdX|?~nFi&jyM#;*>=frnD^Dyc$xAJo+{h?0 z$&6JlvA8(1xFj*JL>F#}ZgPH3PHJ*VW`5qpkHTt(7D&H>{PIt z$%$zelYGoKw-{b3W&)}YTl#c!>aq{40`6 zEb^*MLd?o@(knxQ%&UAtjSVcbEpwfm&CM((f7BJ5tg}UJ;ztqnL^E>(OS44dB+H~U zQ?o=%!xTd^O9MkAOXE~i!=yyhBooU-BlFbB4>uQ1-dte7UR+sRlA2pQ*|64Vv+(8% Lf}1ZM<7Nf`6mv@_ diff --git a/flake.nix b/flake.nix index 1682b16c18167f4c53e7ff4badbbe7312e204985..32289e76bf04f67fa2f90d8edeec0ed797ae6e06 100644 GIT binary patch delta 108 zcmX@-yxes|3g^TC-pNP#v?s3=H{U#w^Pf1kfc4~QkQA+XThb+1_Y2}GUC3&eu zO4eKoU{I7=kgs5?pp=oHo2r{wT%1{4l9*Sb3)iKaoS&1Enp~2ZpEvm;qw?f_MSB2p C=qH5$ delta 20 ccmZ4Pdd_)63g=`2M%~SqIsb`I&QP)k09YIc>;M1& diff --git a/inputs.nix b/inputs.nix index 77bd647d..7bd38a81 100644 --- a/inputs.nix +++ b/inputs.nix @@ -170,6 +170,13 @@ let }; srcs = [ + # Home-assistant + { + name = "wakewords-src"; + owner = "fwartner"; + repo = "home-assistant-wakewords-collection"; + } + # Nvim plugins { name = "vimplugin-easytables-src"; diff --git a/nixosModules/default.nix b/nixosModules/default.nix index 1d87a787..10bc1101 100644 --- a/nixosModules/default.nix +++ b/nixosModules/default.nix @@ -7,4 +7,5 @@ self: { nvidia = import ./nvidia; plymouth = import ./plymouth; server = import ./server; + wyoming-plus = import ./wyoming-plus self; } diff --git a/nixosModules/wyoming-plus/default.nix b/nixosModules/wyoming-plus/default.nix new file mode 100644 index 00000000..b860c478 --- /dev/null +++ b/nixosModules/wyoming-plus/default.nix @@ -0,0 +1,153 @@ +self: { + config, + lib, + pkgs, + ... +}: let + inherit + (lib) + attrNames + escapeShellArgs + flatten + filterAttrs + listToAttrs + map + mkEnableOption + mkForce + mkIf + mkOption + nameValuePair + optionals + splitString + types + ; + + flatMap = f: list: flatten (map f list); + + cfg = config.services.wyoming.openwakeword-docker; +in { + imports = [self.nixosModules.docker]; + + options.services.wyoming.openwakeword-docker = { + enable = mkEnableOption "Wyoming openWakeWord server"; + + image = mkOption { + type = types.package; + default = pkgs.dockerTools.pullImage { + imageName = "docker.io/rhasspy/wyoming-openwakeword"; + imageDigest = "sha256:88df83cfdaa5a0dd068f79662d06b81479ec7b59a4bea59751ff5d6f68bad24a"; + sha256 = "1c2yhrhhj1wpd5bcc3zaz1gv8mw8dw5m76cjf42nhf2sgwp2hsjl"; + finalImageName = "docker.io/rhasspy/wyoming-openwakeword"; + finalImageTag = "latest"; + }; + description = '' + The image that docker will use. + ''; + }; + + uri = mkOption { + type = types.str; + default = "0.0.0.0:10400"; + example = "192.0.2.1:5000"; + description = '' + URI to bind the wyoming server to. + ''; + }; + + customModelsDirectories = mkOption { + type = types.listOf types.path; + default = []; + description = '' + Paths to directories with custom wake word models (*.tflite model files). + ''; + }; + + preloadModels = mkOption { + type = with types; listOf str; + default = [ + "ok_nabu" + ]; + example = [ + # wyoming_openwakeword/models/*.tflite + "alexa" + "hey_jarvis" + "hey_mycroft" + "hey_rhasspy" + "ok_nabu" + ]; + description = '' + List of wake word models to preload after startup. + ''; + }; + + threshold = mkOption { + type = types.float; + default = 0.5; + description = '' + Activation threshold (0-1), where higher means fewer activations. + + See trigger level for the relationship between activations and + wake word detections. + ''; + apply = toString; + }; + + triggerLevel = mkOption { + type = types.int; + default = 1; + description = '' + Number of activations before a detection is registered. + + A higher trigger level means fewer detections. + ''; + apply = toString; + }; + + extraArgs = mkOption { + type = with types; listOf str; + default = []; + description = '' + Extra arguments to pass to the server commandline. + ''; + apply = escapeShellArgs; + }; + }; + + config = { + systemd.services = let + unitNames = attrNames ( + filterAttrs (_: v: v.device == "cpu") config.services.wyoming.faster-whisper.servers + ); + in + listToAttrs (map (x: + nameValuePair "wyoming-faster-whisper-${x}" { + serviceConfig.ProcSubset = mkForce "all"; + }) + unitNames); + + khepri = mkIf cfg.enable { + compositions."openwakeword" = { + networks.default = {}; + + services."openwakeword" = { + image = cfg.image; + restart = "always"; + networks = ["default"]; + + volumes = map (dir: "${toString dir}:${toString dir}") cfg.customModelsDirectories; + cmd = + (flatMap (model: ["--preload-model" model]) cfg.preloadModels) + ++ (flatMap (dir: ["--custom-model-dir" (toString dir)]) cfg.customModelsDirectories) + ++ ["--threshold" cfg.threshold] + ++ ["--trigger-level" cfg.triggerLevel] + ++ optionals (cfg.extraArgs != "") (splitString " " cfg.extraArgs); + + ports = ["${cfg.uri}:10400"]; + }; + }; + }; + }; + + # For accurate stack trace + _file = ./default.nix; +}