diff --git a/devices/homie/modules/home-assistant/assist.nix b/devices/homie/modules/home-assistant/assist.nix index 9bfcf06b..19967ce4 100644 --- a/devices/homie/modules/home-assistant/assist.nix +++ b/devices/homie/modules/home-assistant/assist.nix @@ -12,7 +12,10 @@ services = { home-assistant = { customComponents = builtins.attrValues { - inherit (self.legacyPackages.${pkgs.system}.hass-components) extended-ollama-conversation; + inherit + (self.legacyPackages.${pkgs.system}.hass-components) + extended-ollama-conversation + ; }; extraComponents = [ diff --git a/devices/homie/modules/home-assistant/bluetooth.nix b/devices/homie/modules/home-assistant/bluetooth.nix index 0e27def5..f87c6910 100644 --- a/devices/homie/modules/home-assistant/bluetooth.nix +++ b/devices/homie/modules/home-assistant/bluetooth.nix @@ -2,10 +2,38 @@ config, lib, pkgs, + self, ... -}: { - # Turn On the speaker automatically when openwakeword is used +}: let + inherit (lib) getExe; + + turnOnUE = pkgs.writeShellApplication { + name = "turnOnUE"; + + runtimeInputs = [config.hardware.bluetooth.package]; + + text = '' + cmd=0x0003 + bt_device_addr=88:C6:26:93:4B:77 + + # This is the MAC address on the first line of `bluetootctl show` + # without the `:` and with `01` added at the end + bt_controller_addr=E848B8C8200001 + + exec gatttool -b $bt_device_addr --char-write-req --handle=$cmd --value=$bt_controller_addr + ''; + }; +in { + environment.systemPackages = [turnOnUE]; + services.home-assistant = { + customComponents = builtins.attrValues { + inherit + (self.legacyPackages.${pkgs.system}.hass-components) + spotifyplus + ; + }; + extraComponents = [ "mpd" @@ -16,23 +44,9 @@ "xiaomi_ble" ]; + # Turn On the speaker automatically when openwakeword is used config = { - shell_command.turn_on_ue = lib.getExe (pkgs.writeShellApplication { - name = "turnOnUE"; - - runtimeInputs = [config.hardware.bluetooth.package]; - - text = '' - cmd=0x0003 - bt_device_addr=88:C6:26:93:4B:77 - - # This is the MAC address on the first line of `bluetootctl show` - # without the `:` and with `01` added at the end - bt_controller_addr=E848B8C8200001 - - exec gatttool -b $bt_device_addr --char-write-req --handle=$cmd --value=$bt_controller_addr - ''; - }); + shell_command.turn_on_ue = getExe turnOnUE; automation = [ { diff --git a/devices/homie/modules/home-assistant/default.nix b/devices/homie/modules/home-assistant/default.nix index 2c4a74dd..86e37e6e 100644 --- a/devices/homie/modules/home-assistant/default.nix +++ b/devices/homie/modules/home-assistant/default.nix @@ -53,6 +53,7 @@ "isal" "met" "spotify" + "switchbot" "upnp" "yamaha_musiccast" ]; diff --git a/flake.lock b/flake.lock index 3b4d465c..38d7582f 100644 --- a/flake.lock +++ b/flake.lock @@ -1665,7 +1665,10 @@ "protonhax-src": "protonhax-src", "secrets": "secrets", "sioyek-theme-src": "sioyek-theme-src", + "smartinspect-src": "smartinspect-src", "sops-nix": "sops-nix", + "spotifyplus-src": "spotifyplus-src", + "spotifywebapi-src": "spotifywebapi-src", "subsync": "subsync", "systems": "systems", "trash-d-src": "trash-d-src", @@ -1730,6 +1733,22 @@ "type": "github" } }, + "smartinspect-src": { + "flake": false, + "locked": { + "lastModified": 1706895365, + "narHash": "sha256-pwqjbfe2J33QeRyrqAjU6SWBkJ9SRhdR7DmljsG7i78=", + "owner": "thlucas1", + "repo": "SmartInspectPython", + "rev": "d1e75880f04fe69b5726e0896f8277f26c98b108", + "type": "github" + }, + "original": { + "owner": "thlucas1", + "repo": "SmartInspectPython", + "type": "github" + } + }, "sops-nix": { "inputs": { "nixpkgs": [ @@ -1768,6 +1787,38 @@ "type": "github" } }, + "spotifyplus-src": { + "flake": false, + "locked": { + "lastModified": 1726513051, + "narHash": "sha256-1Gqp9gtLOinxNcfPBMtbil0eaf60BaWXRuiga/z2eao=", + "owner": "thlucas1", + "repo": "homeassistantcomponent_spotifyplus", + "rev": "a51c5ed7f2a47ff9e54388dae4ccc2fbb4388693", + "type": "github" + }, + "original": { + "owner": "thlucas1", + "repo": "homeassistantcomponent_spotifyplus", + "type": "github" + } + }, + "spotifywebapi-src": { + "flake": false, + "locked": { + "lastModified": 1726167421, + "narHash": "sha256-CK0ngtazmX0vIMmZtZBbuyIdEHG43OTTf9iDlXLldQ8=", + "owner": "thlucas1", + "repo": "SpotifyWebApiPython", + "rev": "fd231c75a0711ecd00ad33a14f87cfdad9e0b66c", + "type": "github" + }, + "original": { + "owner": "thlucas1", + "repo": "SpotifyWebApiPython", + "type": "github" + } + }, "subsync": { "inputs": { "nixpkgs": [ diff --git a/flake.nix b/flake.nix index d01f2d3d..38385627 100644 --- a/flake.nix +++ b/flake.nix @@ -333,12 +333,30 @@ repo = "sioyek"; type = "github"; }; + smartinspect-src = { + flake = false; + owner = "thlucas1"; + repo = "SmartInspectPython"; + type = "github"; + }; sops-nix = { inputs.nixpkgs.follows = "nixpkgs"; owner = "Mic92"; repo = "sops-nix"; type = "github"; }; + spotifyplus-src = { + flake = false; + owner = "thlucas1"; + repo = "homeassistantcomponent_spotifyplus"; + type = "github"; + }; + spotifywebapi-src = { + flake = false; + owner = "thlucas1"; + repo = "SpotifyWebApiPython"; + type = "github"; + }; subsync = { inputs.nixpkgs.follows = "nixpkgs"; owner = "matt1432"; diff --git a/inputs.nix b/inputs.nix index 18a218a2..d3d1ab97 100644 --- a/inputs.nix +++ b/inputs.nix @@ -172,6 +172,21 @@ let owner = "TheNimaj"; repo = "extended_ollama_conversation"; } + { + name = "spotifyplus-src"; + owner = "thlucas1"; + repo = "homeassistantcomponent_spotifyplus"; + } + { + name = "smartinspect-src"; + owner = "thlucas1"; + repo = "SmartInspectPython"; + } + { + name = "spotifywebapi-src"; + owner = "thlucas1"; + repo = "SpotifyWebApiPython"; + } { name = "wakewords-src"; diff --git a/legacyPackages/hass-components/default.nix b/legacyPackages/hass-components/default.nix index bbbd9141..e434660e 100644 --- a/legacyPackages/hass-components/default.nix +++ b/legacyPackages/hass-components/default.nix @@ -1,7 +1,29 @@ {pkgs, ...} @ inputs: pkgs.lib.makeScope pkgs.newScope (hass: let - buildHassComponent = file: - hass.callPackage file (inputs // {}); + spotPython3Packages = pkgs.python3Packages.override { + overrides = self: super: rec { + smartinspect = pkgs.callPackage ./spotifyplus/smartinspect.nix { + inherit (inputs) smartinspect-src; + python3Packages = spotPython3Packages; + }; + + spotifywebapi = pkgs.callPackage ./spotifyplus/spotifywebapi.nix { + inherit (inputs) spotifywebapi-src; + inherit smartinspect urllib3; + python3Packages = spotPython3Packages; + }; + + urllib3 = spotPython3Packages.callPackage ./spotifyplus/urllib3.nix {}; + }; + }; + + buildHassComponent = file: extraArgs: + hass.callPackage file (inputs // extraArgs // {}); in { - extended-ollama-conversation = buildHassComponent ./extended-ollama-conversation.nix; + extended-ollama-conversation = buildHassComponent ./extended-ollama-conversation { + openai = import ./extended-ollama-conversation/openai.nix pkgs; + }; + spotifyplus = buildHassComponent ./spotifyplus { + python3Packages = spotPython3Packages; + }; }) diff --git a/legacyPackages/hass-components/extended-ollama-conversation.nix b/legacyPackages/hass-components/extended-ollama-conversation.nix deleted file mode 100644 index affc726b..00000000 --- a/legacyPackages/hass-components/extended-ollama-conversation.nix +++ /dev/null @@ -1,34 +0,0 @@ -{ - extended-ollama-conversation-src, - buildHomeAssistantComponent, - fetchFromGitHub, - python3Packages, - ... -}: let - inherit (builtins) fromJSON readFile; - - manifest = fromJSON (readFile "${extended-ollama-conversation-src}/custom_components/extended_ollama_conversation/manifest.json"); - - openai = python3Packages.openai.overrideAttrs (o: rec { - name = "${o.pname}-${version}"; - version = "1.3.8"; - - src = fetchFromGitHub { - owner = "openai"; - repo = "openai-python"; - rev = "refs/tags/v${version}"; - hash = "sha256-yU0XWEDYl/oBPpYNFg256H0Hn5AaJiP0vOQhbRLnAxQ="; - }; - - disabledTests = o.disabledTests ++ ["test_retrying_timeout_errors_doesnt_leak" "test_retrying_status_errors_doesnt_leak"]; - }); -in - buildHomeAssistantComponent { - owner = "TheNimaj"; - - inherit (manifest) domain version; - - src = extended-ollama-conversation-src; - - propagatedBuildInputs = [python3Packages.ollama openai]; - } diff --git a/legacyPackages/hass-components/extended-ollama-conversation/default.nix b/legacyPackages/hass-components/extended-ollama-conversation/default.nix new file mode 100644 index 00000000..dc46649e --- /dev/null +++ b/legacyPackages/hass-components/extended-ollama-conversation/default.nix @@ -0,0 +1,23 @@ +{ + extended-ollama-conversation-src, + buildHomeAssistantComponent, + openai, + python3Packages, + ... +}: let + inherit (builtins) fromJSON readFile; + + manifest = fromJSON (readFile "${extended-ollama-conversation-src}/custom_components/extended_ollama_conversation/manifest.json"); +in + buildHomeAssistantComponent { + owner = "TheNimaj"; + + inherit (manifest) domain version; + + src = extended-ollama-conversation-src; + + propagatedBuildInputs = [ + python3Packages.ollama + openai + ]; + } diff --git a/legacyPackages/hass-components/extended-ollama-conversation/openai.nix b/legacyPackages/hass-components/extended-ollama-conversation/openai.nix new file mode 100644 index 00000000..5ff86ad2 --- /dev/null +++ b/legacyPackages/hass-components/extended-ollama-conversation/openai.nix @@ -0,0 +1,19 @@ +pkgs: +pkgs.python3Packages.openai.overrideAttrs (o: rec { + name = "${o.pname}-${version}"; + version = "1.3.8"; + + src = pkgs.fetchFromGitHub { + owner = "openai"; + repo = "openai-python"; + rev = "refs/tags/v${version}"; + hash = "sha256-yU0XWEDYl/oBPpYNFg256H0Hn5AaJiP0vOQhbRLnAxQ="; + }; + + disabledTests = + o.disabledTests + ++ [ + "test_retrying_timeout_errors_doesnt_leak" + "test_retrying_status_errors_doesnt_leak" + ]; +}) diff --git a/legacyPackages/hass-components/spotifyplus/default.nix b/legacyPackages/hass-components/spotifyplus/default.nix new file mode 100644 index 00000000..7b7f5a7b --- /dev/null +++ b/legacyPackages/hass-components/spotifyplus/default.nix @@ -0,0 +1,28 @@ +{ + spotifyplus-src, + buildHomeAssistantComponent, + python3Packages, + ... +}: let + inherit (builtins) fromJSON readFile; + + manifest = fromJSON (readFile "${spotifyplus-src}/custom_components/spotifyplus/manifest.json"); +in + buildHomeAssistantComponent { + owner = "thlucas1"; + + inherit (manifest) domain version; + + src = spotifyplus-src; + + propagatedBuildInputs = with python3Packages; [ + oauthlib + platformdirs + requests + requests_oauthlib + zeroconf + smartinspect # overridden in this python3Packages + spotifywebapi # overridden in this python3Packages + urllib3 # overridden in this python3Packages + ]; + } diff --git a/legacyPackages/hass-components/spotifyplus/smartinspect.nix b/legacyPackages/hass-components/spotifyplus/smartinspect.nix new file mode 100644 index 00000000..d2ff697a --- /dev/null +++ b/legacyPackages/hass-components/spotifyplus/smartinspect.nix @@ -0,0 +1,23 @@ +{ + smartinspect-src, + python3Packages, + ... +}: let + inherit (builtins) elemAt head readFile split; + tag = head (split "\"" (elemAt (split "VERSION:str = \"" (readFile "${smartinspect-src}/smartinspectpython/siconst.py")) 2)); +in + python3Packages.buildPythonPackage { + pname = "smartinspectPython"; + version = "${tag}+${smartinspect-src.shortRev}"; + + src = smartinspect-src; + + propagatedBuildInputs = with python3Packages; [ + pycryptodome + watchdog + ]; + + pythonImportsCheck = [ + "smartinspectpython" + ]; + } diff --git a/legacyPackages/hass-components/spotifyplus/spotifywebapi.nix b/legacyPackages/hass-components/spotifyplus/spotifywebapi.nix new file mode 100644 index 00000000..265ae2fa --- /dev/null +++ b/legacyPackages/hass-components/spotifyplus/spotifywebapi.nix @@ -0,0 +1,35 @@ +{ + spotifywebapi-src, + python3Packages, + ... +}: let + inherit (builtins) elemAt head readFile split; + tag = head (split "\"" (elemAt (split "VERSION:str = \"" (readFile "${spotifywebapi-src}/spotifywebapipython/const.py")) 2)); +in + python3Packages.buildPythonPackage { + pname = "spotifywebapiPython"; + version = "${tag}+${spotifywebapi-src.shortRev}"; + + src = spotifywebapi-src; + + patchPhase = '' + substituteInPlace ./setup.py --replace-warn \ + "docspdoc/build/spotifywebapiPython/" \ + "docspdoc/build/spotifywebapipython/" + ''; + + propagatedBuildInputs = with python3Packages; [ + lxml + oauthlib + platformdirs + requests + requests_oauthlib + zeroconf + smartinspect # overridden in this python3Packages + urllib3 # overridden in this python3Packages + ]; + + pythonImportsCheck = [ + "spotifywebapipython" + ]; + } diff --git a/legacyPackages/hass-components/spotifyplus/urllib3.nix b/legacyPackages/hass-components/spotifyplus/urllib3.nix new file mode 100644 index 00000000..5d8dfc8e --- /dev/null +++ b/legacyPackages/hass-components/spotifyplus/urllib3.nix @@ -0,0 +1,82 @@ +# From nixpkgs 4c0061c983a2bcb888f5c478cfb7631ec1090c22 +{ + lib, + brotli, + brotlicffi, + buildPythonPackage, + certifi, + cryptography, + fetchPypi, + idna, + isPyPy, + mock, + pyopenssl, + pysocks, + pytest-freezegun, + pytest-timeout, + pytestCheckHook, + python-dateutil, + tornado, + trustme, +}: +buildPythonPackage rec { + pname = "urllib3"; + version = "1.26.16"; + format = "setuptools"; + + src = fetchPypi { + inherit pname version; + hash = "sha256-jxNfZQJ1a95rKpsomJ31++h8mXDOyqaQQe3M5/BYmxQ="; + }; + + propagatedBuildInputs = + passthru.optional-dependencies.brotli + ++ passthru.optional-dependencies.socks; + + nativeCheckInputs = [ + python-dateutil + mock + pytest-freezegun + pytest-timeout + pytestCheckHook + tornado + trustme + ]; + + doCheck = false; + + preCheck = '' + export CI # Increases LONG_TIMEOUT + ''; + + pythonImportsCheck = [ + "urllib3" + ]; + + passthru.optional-dependencies = { + brotli = + if isPyPy + then [ + brotlicffi + ] + else [ + brotli + ]; + secure = [ + certifi + cryptography + idna + pyopenssl + ]; + socks = [ + pysocks + ]; + }; + + meta = with lib; { + description = "Powerful, sanity-friendly HTTP client for Python"; + homepage = "https://github.com/shazow/urllib3"; + changelog = "https://github.com/urllib3/urllib3/blob/${version}/CHANGES.rst"; + license = licenses.mit; + }; +}