116 lines
3.4 KiB
Markdown
116 lines
3.4 KiB
Markdown
title: Random Audiobook on MPD
|
|
order: 10
|
|
---
|
|
I want the Zigbee light switch attached directly to the headboard of my bed to play a random Sherlock Holmes or Three Investigators episode when pressed and held. To do this, I first need to write a Python script that connects to my [MPD](https://de.wikipedia.org/wiki/Music_Player_Daemon) and retrieves a list of all possible audiobooks, then selects one at random and plays it. The script then needs to be made available on the Pi running Home Assistant and linked to the button.
|
|
|
|
## Setup Homeassistant
|
|
I run Homeassistant inside a Docker container. Therefor i need to mount the folder with the python script inside the container. I use the /opt directly in this setup
|
|
|
|
```
|
|
services:
|
|
homeassistant:
|
|
image: "ghcr.io/home-assistant/home-assistant:stable"
|
|
volumes:
|
|
- /opt/:/opt/root
|
|
...
|
|
|
|
```
|
|
|
|
after that i could make the script visible to homeassistant by adding the following content to my `configuration.yaml`:
|
|
|
|
```
|
|
shell_command:
|
|
hoerbuch: python3 /opt/root/randomhoerbuch
|
|
|
|
```
|
|
Than i used the Homeassistant GUI to create an automation which run the script on the hold action of the button:
|
|
|
|
```
|
|
alias: Button Bed Long
|
|
description: ""
|
|
trigger:
|
|
- platform: device
|
|
domain: mqtt
|
|
device_id: cdb815a53346bc4bca446b097a2da234
|
|
type: action
|
|
subtype: hold
|
|
discovery_id: 0x00158d00027d83ba action_hold
|
|
condition: []
|
|
action:
|
|
- service: shell_command.hoerbuch
|
|
data: {}
|
|
mode: single
|
|
```
|
|
|
|
## Python code
|
|
```pthon
|
|
#!/bin/python3
|
|
import random
|
|
from mpd import MPDClient
|
|
|
|
# Konfigurierbare Einstellungen
|
|
MPD_HOST = "192.168.1.101"
|
|
MPD_PORT = 6600
|
|
MPD_PASSWORD = None # oder z.B. "meinPasswort"
|
|
ALBUM_ARTISTS = ["Sherlock Holms - Aus den Tagebüchern"] # Beispielkünstler
|
|
|
|
def connect_to_mpd():
|
|
client = MPDClient()
|
|
client.timeout = 10
|
|
client.idletimeout = None
|
|
client.connect(MPD_HOST, MPD_PORT)
|
|
if MPD_PASSWORD:
|
|
client.password(MPD_PASSWORD)
|
|
return client
|
|
|
|
def get_albums_by_artist(client, artist):
|
|
albums = client.list("album", "albumartist", artist)
|
|
return [album for album in albums if album]
|
|
|
|
def get_songs_from_album(client, artist, album):
|
|
# Versuche zuerst mit albumartist
|
|
songs = client.find("albumartist", artist, "album", album)
|
|
if not songs:
|
|
# Fallback auf artist, falls albumartist nicht funktioniert
|
|
songs = client.find("artist", artist, "album", album)
|
|
print(f"Keine Songs gefunden für:\nArtist: {artist}\nAlbum: {album}")
|
|
return songs
|
|
|
|
def main():
|
|
client = connect_to_mpd()
|
|
|
|
|
|
# Alle Alben sammeln
|
|
artist_album_map = {}
|
|
for artist in ALBUM_ARTISTS:
|
|
albums = get_albums_by_artist(client, artist)
|
|
if albums:
|
|
artist_album_map[artist] = albums
|
|
|
|
# Zufällig Künstler und Album wählen
|
|
if not artist_album_map:
|
|
print("Keine Alben gefunden.")
|
|
return
|
|
|
|
artist = random.choice(list(artist_album_map.keys()))
|
|
album_entry = random.choice(artist_album_map[artist])
|
|
album = album_entry["album"] if isinstance(album_entry, dict) else album_entry
|
|
|
|
print(f"Spiele zufälliges Album:\nKünstler: {artist}\nAlbum: {album}")
|
|
|
|
# Songs holen und abspielen
|
|
songs = get_songs_from_album(client, artist, album)
|
|
|
|
client.clear()
|
|
for song in songs:
|
|
client.add(song["file"])
|
|
client.play()
|
|
|
|
client.close()
|
|
client.disconnect()
|
|
|
|
if __name__ == "__main__":
|
|
main()
|
|
|
|
|
|
```
|