diff --git a/devices/homie/modules/default.nix b/devices/homie/modules/default.nix
index 457b5e1a..d8fa2972 100644
--- a/devices/homie/modules/default.nix
+++ b/devices/homie/modules/default.nix
@@ -1,5 +1,6 @@
 {...}: {
   imports = [
     ./home-assistant
+    ./music
   ];
 }
diff --git a/devices/homie/modules/home-assistant/bluetooth.nix b/devices/homie/modules/home-assistant/bluetooth.nix
index 89ea1273..0e27def5 100644
--- a/devices/homie/modules/home-assistant/bluetooth.nix
+++ b/devices/homie/modules/home-assistant/bluetooth.nix
@@ -4,101 +4,56 @@
   pkgs,
   ...
 }: {
-  # Setup Bluetooth
-  hardware.bluetooth = {
-    enable = true;
-    powerOnBoot = true;
-
-    settings = {
-      General = {
-        DiscoverableTimeout = 0;
-        Experimental = true;
-        KernelExperimental = true;
-      };
-
-      Policy.AutoEnable = "true";
-    };
-  };
-
-  # Have pulseaudio.service itself start at boot but after bluetooth
-  # so bluetooth accepts sound connections from the start.
-  systemd.user.services.pulseaudio.after = ["bluetooth.service"];
-  systemd.user.targets.default.wants = ["pulseaudio.service"];
-
   # Turn On the speaker automatically when openwakeword is used
-  services.home-assistant.config = {
-    shell_command.turn_on_ue = lib.getExe (pkgs.writeShellApplication {
-      name = "turnOnUE";
+  services.home-assistant = {
+    extraComponents = [
+      "mpd"
 
-      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
-      '';
-    });
-    automation = [
-      {
-        alias = "Turn On UE";
-        mode = "single";
-        trigger = [
-          {
-            platform = "state";
-            entity_id = "wake_word.openwakeword";
-          }
-        ];
-        condition = [];
-        action = [
-          {
-            action = "shell_command.turn_on_ue";
-            metadata = {};
-            data = {};
-          }
-        ];
-      }
+      # BT components
+      "ibeacon"
+      "led_ble"
+      "kegtron"
+      "xiaomi_ble"
     ];
-  };
 
-  # Allow pulseaudio to be managed by MPD
-  hardware.pulseaudio = {
-    enable = true;
+    config = {
+      shell_command.turn_on_ue = lib.getExe (pkgs.writeShellApplication {
+        name = "turnOnUE";
 
-    extraConfig = ''
-      load-module module-native-protocol-tcp auth-ip-acl=127.0.0.1
-    '';
-  };
+        runtimeInputs = [config.hardware.bluetooth.package];
 
-  # Setup MPD
-  services.home-assistant.extraComponents = [
-    "mpd"
+        text = ''
+          cmd=0x0003
+          bt_device_addr=88:C6:26:93:4B:77
 
-    # BT components
-    "ibeacon"
-    "led_ble"
-    "kegtron"
-    "xiaomi_ble"
-  ];
-  services.mpd = {
-    enable = true;
+          # 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
 
-    network = {
-      listenAddress = "127.0.0.1";
-      port = 6600;
+          exec gatttool -b $bt_device_addr --char-write-req --handle=$cmd --value=$bt_controller_addr
+        '';
+      });
+
+      automation = [
+        {
+          alias = "Turn On UE";
+          mode = "single";
+          trigger = [
+            {
+              platform = "state";
+              entity_id = "wake_word.openwakeword";
+            }
+          ];
+          condition = [];
+          action = [
+            {
+              action = "shell_command.turn_on_ue";
+              metadata = {};
+              data = {};
+            }
+          ];
+        }
+      ];
     };
-
-    extraConfig = ''
-      audio_output {
-        type "pulse"
-        name "UE Boom 2"
-        sink "bluez_sink.88_C6_26_93_4B_77.a2dp_sink"
-        server "127.0.0.1"
-      }
-    '';
   };
 }
diff --git a/devices/homie/modules/music/default.nix b/devices/homie/modules/music/default.nix
new file mode 100644
index 00000000..7b14d8fd
--- /dev/null
+++ b/devices/homie/modules/music/default.nix
@@ -0,0 +1,80 @@
+{
+  config,
+  lib,
+  pkgs,
+  ...
+}: {
+  hardware.bluetooth = {
+    enable = true;
+    powerOnBoot = true;
+
+    settings = {
+      General = {
+        DiscoverableTimeout = 0;
+        Experimental = true;
+        KernelExperimental = true;
+      };
+
+      Policy.AutoEnable = "true";
+    };
+  };
+
+  # Have pulseaudio.service itself start at boot but after bluetooth
+  # so bluetooth accepts sound connections from the start.
+  systemd.user.services.pulseaudio.after = ["bluetooth.service"];
+  systemd.user.targets.default.wants = ["pulseaudio.service"];
+
+  # Allow pulseaudio to be managed by MPD
+  hardware.pulseaudio = {
+    enable = true;
+
+    extraConfig = ''
+      load-module module-native-protocol-tcp auth-ip-acl=127.0.0.1
+    '';
+  };
+
+  services = {
+    mpd = {
+      enable = true;
+
+      network = {
+        listenAddress = "127.0.0.1";
+        port = 6600;
+      };
+
+      extraConfig = ''
+        audio_output {
+          type "pulse"
+          name "UE Boom 2"
+          sink "bluez_sink.88_C6_26_93_4B_77.a2dp_sink"
+          server "127.0.0.1"
+        }
+      '';
+    };
+
+    spotifyd = {
+      enable = true;
+
+      settings.global = let
+        cacheDir = "/etc/spotifyd";
+      in {
+        device_name = config.networking.hostName;
+        device_type = "speaker";
+
+        zeroconf_port = 33797;
+        cache_path = cacheDir;
+        username_cmd = "${lib.getExe pkgs.jq} -r .username ${cacheDir}/credentials.json";
+
+        autoplay = false;
+        backend = "pulseaudio";
+        bitrate = 320;
+        no_audio_cache = true;
+        volume_normalisation = false;
+      };
+    };
+  };
+
+  environment.etc."spotifyd/credentials.json" = {
+    source = config.sops.secrets.spotifyd.path;
+  };
+}
diff --git a/flake.lock b/flake.lock
index b74e5deb..637e04ab 100644
--- a/flake.lock
+++ b/flake.lock
@@ -1700,11 +1700,11 @@
         ]
       },
       "locked": {
-        "lastModified": 1725588406,
-        "narHash": "sha256-yX3/SKEP/AB4IJiV8X008tnOepTla0XeJ9m2d6VoQAQ=",
+        "lastModified": 1726679017,
+        "narHash": "sha256-Nflpm4CG7K/c8uaS09G0m1tnxBbeM05u0pNHX2lF7Wo=",
         "ref": "refs/heads/main",
-        "rev": "fe8958ac8792da69e7071e69482bc488a65f926f",
-        "revCount": 76,
+        "rev": "571df8a09d051cf6caa08b94b65c980d92894c7c",
+        "revCount": 77,
         "type": "git",
         "url": "ssh://git@git.nelim.org/matt1432/nixos-secrets"
       },