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;
+  };
+}