Ich höre zu Hause Musik über Spotify Premium und nutze als Abspielgeräte überwiegend Alexa-Geräte von Amazon.
Ich wollte, dass meine Tochter ihre Lieblingslieder selbst starten kann, ohne ein Handy oder einen Bildschirm bedienen zu müssen. Eine NFC-Karte an den Leser halten, und die Musik läuft: eine Art Tonie-Box, nur selbst gebaut. Der Leser basiert auf einem ESP32-Mikrocontroller. Ich habe ihn mit dem ESPHome Builder nach der Vorlage von adonno/tagreader aufgebaut.
Der naheliegende Ansatz in Home Assistant ist die offizielle Spotify-Integration zusammen mit media_player.play_media. Für einen Kaltstart reicht das aber nicht. Mit der Integration lässt sich play_media erst sinnvoll verwenden, wenn auf dem Spotify-Player bereits etwas läuft. Soll ein bestimmter Song, eine Playlist oder ein Podcast aus dem Stand starten, greift dieser Weg zu kurz. Das ist keine Fehlkonfiguration, sondern eine Einschränkung der Integration und ihres aktuellen media_player-Verhaltens.
Die Lösung ist ein kleines Python-Skript. Es fragt die Spotify-Web-API nach den verfügbaren Spotify-Connect-Geräten, sucht die gewünschte Alexa anhand ihres Spotify-Gerätenamens und startet dort die Wiedergabe der angegebenen Spotify-URI. Home Assistant ruft das Skript über shell_command auf.
Warum kein fertiges Add-on? Der zusätzliche Aufwand für die Web-API ist überschaubar. Dafür entfällt eine weitere Abhängigkeit. Das Skript verwendet den OAuth-Token, den die Spotify-Integration ohnehin gespeichert hat, und erneuert ihn bei Bedarf. Damit gibt es keine zweite Anmeldung, keinen zusätzlichen Dienst und kein weiteres Add-on. Der Preis: Das Skript muss im Home-Assistant-Konfigurationsordner liegen, Zugriff auf die gespeicherten Integrationsdaten haben und seine Ausgabe muss beim Debugging separat protokolliert werden.
Der Aufbau in fünf Bausteinen
- Die Spotify-Integration erhält Zugriff auf den Spotify-Account, der die verwendeten Alexa-Geräte steuert.
- Das Skript startet die Wiedergabe über die Spotify-Web-API.
shell_commandmacht das Skript für Home Assistant aufrufbar.- Ein
input_text-Helper enthält den gewünschten Spotify-Gerätenamen. - Eine Automation liefert nur den Auslöser und die Spotify-URI. Der Auslöser kann NFC, ein Taster, eine Uhrzeit, Anwesenheit oder ein anderes Skript sein.
Wichtig: Die Alexa muss bei Spotify als Spotify-Connect-Gerät erreichbar sein. Das Ziel ist der Gerätename bei Spotify, nicht die Home-Assistant-Entität der Alexa. Für die Steuerung über die Web-API wird außerdem Spotify Premium benötigt.
Schritt 1: Spotify in Home Assistant einrichten
Im Spotify-Entwicklerportal legst du eine App an und kopierst Client-ID und Client-Secret. Das Secret gehört nur in die Zugangsdatenverwaltung, nicht in eine YAML-Datei und nicht in dieses Tutorial.
- Öffne im Entwicklerportal die Einstellungen deiner Spotify-App.
- Trage die von Home Assistant vorgegebene Redirect-URI ein. Sie muss exakt mit der URI übereinstimmen, die Home Assistant beim Einrichten der Integration anzeigt.
- Öffne in Home Assistant Einstellungen → Geräte & Dienste und füge die Spotify-Integration hinzu.
- Verwende Client-ID und Client-Secret und schließe den OAuth-Dialog ab.
- Melde dich mit dem Spotify-Konto an, das auf den Alexas verwendet wird. Das ist nicht zwingend das Konto, mit dem du Home Assistant verwaltest.
Nach der Einrichtung sollte die Integration unter Einstellungen → Geräte & Dienste erscheinen. Dort kannst du die angelegte Integration öffnen und prüfen, ob Home Assistant die Spotify-Geräte und das verbundene Konto anzeigt.

Schritt 2: Das Skript ablegen
Lege die Datei als /config/spotify_play.py im Home-Assistant-Konfigurationsordner ab und mache sie ausführbar:
chmod 755 /config/spotify_play.py
Das Skript liest die Konfiguration der Spotify-Integration aus /config/.storage/core.config_entries. Die Client-Zugangsdaten liegen in /config/.storage/application_credentials. Im Artikel nenne ich bewusst nur die Speicherorte, niemals deren Inhalte. Das Skript gibt weder Client-Secret noch Token aus.
Beim Aufruf passiert Folgendes: Die Spotify-URI wird aus einem spotify:-Schema oder einem open.spotify.com-Link gewonnen. Dann wird der gespeicherte Token geprüft. Ist er abgelaufen oder läuft er in Kürze ab, fordert das Skript mit dem gespeicherten Refresh-Token einen neuen Access-Token an. Anschließend ruft es /v1/me/player/devices ab, sucht den Gerätenamen ohne Beachtung von Groß- und Kleinschreibung und startet mit PUT /v1/me/player/play die Wiedergabe auf der gefundenen Geräte-ID.
Hier ist die vollständige Vorlage. Sie enthält keine echten Zugangsdaten, Tokens, Hausnamen oder internen Adressen:
#!/usr/bin/env python3
"""Start Spotify playback on a Spotify Connect device, by device name.
Why this exists: the Home Assistant Spotify integration only exposes
media_player.play_media while something is already playing
(see spotify/media_player.py, supported_features). This script performs the
initial start through the Web API, which works with nothing playing.
Called from Home Assistant via shell_command. Reuses the OAuth token that the
Spotify integration already stores, and refreshes it when expired. No secret
is ever printed.
Usage:
python3 spotify_play.py --device "Wohnzimmer" --uri spotify:track:EXAMPLE
python3 spotify_play.py --device "Küche" --uri https://open.spotify.com/track/EXAMPLE
"""
from __future__ import annotations
import argparse
import json
import os
import sys
import time
import urllib.error
import urllib.parse
import urllib.request
STORAGE = "/config/.storage"
TOKEN_URL = "https://accounts.spotify.com/api/token"
API = "https://api.spotify.com/v1"
def load(name):
with open(os.path.join(STORAGE, name), encoding="utf-8") as fh:
return json.load(fh)
def to_uri(value: str) -> str:
"""Accept a spotify: URI, an open.spotify.com link, or a bare id set."""
v = value.strip()
if v.startswith("spotify:"):
return v
if v.startswith("http"):
parts = [p for p in urllib.parse.urlparse(v).path.split("/") if p]
if len(parts) >= 2:
return "spotify:%s:%s" % (parts[0], parts[1])
return v
def access_token(entry: dict) -> str:
token = entry["data"]["token"]
if float(token.get("expires_at") or 0) > time.time() + 60:
return token["access_token"]
creds = load("application_credentials")["data"]["items"]
impl = entry["data"].get("auth_implementation")
cred = next((c for c in creds if c.get("id") == impl), creds[0])
body = urllib.parse.urlencode({
"grant_type": "refresh_token",
"refresh_token": token["refresh_token"],
"client_id": cred["client_id"],
"client_secret": cred["client_secret"],
}).encode()
req = urllib.request.Request(
TOKEN_URL, data=body,
headers={"Content-Type": "application/x-www-form-urlencoded"})
try:
with urllib.request.urlopen(req, timeout=20) as resp:
return json.loads(resp.read())["access_token"]
except urllib.error.HTTPError as err:
sys.exit("spotify: token refresh failed: %s %s"
% (err.code, err.read().decode("utf-8", "replace")[:160]))
def main() -> None:
ap = argparse.ArgumentParser()
ap.add_argument("--device", required=True, help="Spotify Connect device name")
ap.add_argument("--uri", required=True, help="spotify: URI or open.spotify.com link")
args = ap.parse_args()
uri = to_uri(args.uri)
entries = load("core.config_entries")["data"]["entries"]
entry = next((e for e in entries if e.get("domain") == "spotify"), None)
if entry is None:
sys.exit("spotify: no spotify config entry found")
token = access_token(entry)
def api(method: str, path: str, payload=None):
data = json.dumps(payload).encode() if payload is not None else None
req = urllib.request.Request(
API + path, data=data, method=method,
headers={"Authorization": "Bearer " + token,
"Content-Type": "application/json"})
try:
with urllib.request.urlopen(req, timeout=25) as resp:
raw = resp.read()
return resp.status, (json.loads(raw) if raw else None)
except urllib.error.HTTPError as err:
return err.code, err.read().decode("utf-8", "replace")[:200]
status, devices = api("GET", "/me/player/devices")
if status != 200 or not isinstance(devices, dict):
sys.exit("spotify: cannot read devices (%s): %s" % (status, devices))
wanted = args.device.strip().casefold()
available = devices.get("devices", [])
device = next((d for d in available
if (d.get("name") or "").casefold() == wanted), None)
if device is None:
sys.exit("spotify: device '%s' not found (available: %s)"
% (args.device, ", ".join(d.get("name", "?") for d in available)))
status, body = api("PUT", "/me/player/play?device_id=" + device["id"],
{"uris": [uri]})
if status in (200, 204):
print("spotify: started %s on %s" % (uri, device["name"]))
return
sys.exit("spotify: play failed (%s): %s" % (status, body))
if __name__ == "__main__":
main()Schritt 3: shell_command konfigurieren
Ergänze in configuration.yaml:
shell_command:
spotify_play: >-
python3 /config/spotify_play.py
--device "{{ device }}"
--uri "{{ uri }}"Die beiden Template-Variablen sind die Schnittstelle zwischen Automation und Skript. device ist der Name des Spotify-Connect-Geräts, uri ist die Spotify-URI oder ein Spotify-Link. Nach der Änderung prüfst du die Konfiguration und startest Home Assistant neu beziehungsweise lädst die YAML-Konfiguration nach.
Die Anführungszeichen schützen hier insbesondere Gerätenamen mit Leerzeichen. Wenn du Namen mit ungewöhnlichen Anführungszeichen verwendest, teste den Aufruf besonders sorgfältig.
Schritt 4: Helper für das Zielgerät
Lege unter Einstellungen → Geräte & Dienste → Helfer einen Text-Helper an. Als Beispiel heißt er input_text.tag_player_target. In den Wert kommt der Name, unter dem die Alexa bei Spotify erscheint, etwa Wohnzimmer oder Küche.
Das ist ausdrücklich nicht der Name der Home-Assistant-Entität. Entscheidend ist die Schreibweise in Spotify Connect. Das Skript vergleicht zwar ohne Beachtung von Groß- und Kleinschreibung, aber ansonsten muss der Name passen.

Schritt 5: NFC-Automation einrichten
Das vorhandene Blueprint nimmt Tag-ID, Spotify-URL und Medientyp entgegen. Der Medientyp bleibt aus Kompatibilitätsgründen im Blueprint; das Skript erkennt den Typ letztlich anhand der URI. Importiere das Blueprint und lege anschließend eine Automation daraus an:
blueprint:
name: NFC tag play Spotify on Alexa
description: >-
Plays a song, playlist or podcast from Spotify on an Alexa device, triggered by a NFC tag.
Starts playback through the Spotify Web API, because the Spotify integration only allows
play_media while something is already playing.
domain: automation
input:
tag_id:
name: NFC Tag id
description: The NFC tag that should trigger the Spotify action. Get id from https://my.home-assistant.io/redirect/tags/
selector:
text:
media_url:
name: Spotify url
description: Eine Spotify-URL für einen Song, eine Playlist oder einen Podcast
selector:
text:
media_type:
name: Media type
description: Medientyp der Spotify-Quelle. Aus Kompatibilitätsgründen enthalten; das Skript verarbeitet die URI direkt.
selector:
select:
options:
- music
- playlist
- podcast
trigger:
- platform: tag
tag_id: !input tag_id
condition: []
action:
- service: shell_command.spotify_play
data:
device: "{{ states('input_text.tag_player_target') }}"
uri: !input media_url
mode: singleBei der Automation wählst du den NFC-Tag aus und trägst den Spotify-Link ein. Für eine Playlist oder einen Podcast kannst du einen normalen Spotify-Link aus der Spotify-App verwenden. Das Skript wandelt ihn in eine Spotify-URI um. Als Ziel wird bei jedem Auslösen der aktuelle Wert von input_text.tag_player_target verwendet.

Schritt 6: Schrittweise testen
- Prüfe zuerst, ob die Spotify-Integration eingerichtet ist und der verwendete Account Premium hat.
- Starte Spotify auf einem anderen Gerät und kontrolliere, ob die Alexa in der Geräteauswahl als Spotify-Connect-Ziel auftaucht.
- Setze den Helper exakt auf diesen Spotify-Gerätenamen.
- Rufe das Skript testweise aus der Home-Assistant-Umgebung mit einer bekannten URI auf.
- Prüfe danach die Automation separat: Wird der NFC-Tag erkannt? Wird der Service
shell_command.spotify_playausgelöst? - Wenn nichts passiert, aktiviere für den Test eine Protokollierung der Shell-Command-Ausgabe. Ohne diese Ausgabe bleibt ein fehlgeschlagener Aufruf sonst oft unbemerkt.
Typische Fehlerquellen
- Token abgelaufen: Prüfe die OAuth-Konfiguration und die Dateien unter
.storage. Das Skript versucht zwar eine Erneuerung, aber ein widerrufener Refresh-Token kann nicht repariert werden. - Gerät nicht gefunden: Der Name im Helper weicht vom Spotify-Namen ab. Home-Assistant-Entitäten sind an dieser Stelle nicht relevant.
- Alexa nicht erreichbar: Die Alexa ist gerade offline oder wird von Spotify nicht als Connect-Gerät angeboten.
- Kein Premium-Konto: Die Steuerung über die Web-API setzt Premium voraus.
- Keine Ausführungsrechte: Prüfe Pfad, Shebang und
chmod 755. - Stiller Fehlschlag: Ohne protokollierte Ausgabe bleibt ein fehlgeschlagener Aufruf sonst oft unbemerkt.
Das Skript aus jeder Automation starten
Die NFC-Karte ist nur mein Auslöser. Der entscheidende Aufruf bleibt immer gleich: Gerätename und Spotify-URI an shell_command.spotify_play übergeben. Alles andere ist austauschbar.
Physischer Taster
alias: Spotify im Wohnzimmer per Taster starten
description: Startet einen festen Spotify-Track auf dem im Helper gewählten Gerät.
trigger:
- platform: state
entity_id: binary_sensor.wohnzimmer_taster
to: "on"
condition: []
action:
- service: shell_command.spotify_play
data:
device: "{{ states('input_text.tag_player_target') }}"
uri: "spotify:track:EXAMPLE_TRACK_ID"
mode: singleZeitsteuerung
alias: Spotify am Morgen starten
description: Startet werktags eine Playlist auf dem im Helper gewählten Gerät.
trigger:
- platform: time
at: "07:00:00"
condition:
- condition: time
weekday:
- mon
- tue
- wed
- thu
- fri
action:
- service: shell_command.spotify_play
data:
device: "{{ states('input_text.tag_player_target') }}"
uri: "spotify:playlist:EXAMPLE_PLAYLIST_ID"
mode: singleAnwesenheit
alias: Spotify bei Ankunft starten
description: Startet einen Podcast, wenn eine Person nach Hause kommt.
trigger:
- platform: state
entity_id: person.beispiel
from: "not_home"
to: "home"
condition: []
action:
- service: shell_command.spotify_play
data:
device: "{{ states('input_text.tag_player_target') }}"
uri: "spotify:episode:EXAMPLE_EPISODE_ID"
mode: singleSprachbefehl oder anderes Skript
alias: Spotify per Sprachbefehl starten
description: Dieses Skript enthält nur den eigentlichen Aufruf.
sequence:
- service: shell_command.spotify_play
data:
device: "{{ states('input_text.tag_player_target') }}"
uri: "spotify:track:EXAMPLE_TRACK_ID"
mode: singleErsetze EXAMPLE_TRACK_ID, EXAMPLE_PLAYLIST_ID und EXAMPLE_EPISODE_ID durch deine eigenen Spotify-URIs. Ebenso müssen die Entitäten und der Helper-Name zu deiner Installation passen. Der Auslöser kann ein Tag, ein Taster, eine Uhrzeit, Anwesenheit oder ein Sprachbefehl sein. Die Logik für die Auswahl der Alexa bleibt davon unberührt.
Fazit
Mit diesem Aufbau startet Home Assistant einen Song, eine Playlist oder einen Podcast aus dem Stand auf einer frei wählbaren Alexa, sofern sie bei Spotify als Connect-Gerät erreichbar ist und das Konto über Premium verfügt. Die Auswahl erfolgt über den Spotify-Gerätenamen im Helper, nicht über eine fest verdrahtete Home-Assistant-Entität.
Der Preis für die kleine Lösung ist überschaubar: ein Python-Skript, Zugriff auf die gespeicherten OAuth-Daten und etwas Aufmerksamkeit beim Debugging. Dafür brauchst du keine zweite Spotify-Anmeldung und keinen zusätzlichen Dienst. Für meinen NFC-Anwendungsfall reicht das genau: Die Karte wird an den Leser gehalten, die Wiedergabe startet. Ohne Bildschirm, ohne Handy und ohne dass die Automation jedes Mal angepasst werden muss.


