Control Hue Smart Plug using Spotify
How to make a dump stereo system smart?⌗
I have connected my stereo system to a Hue smart plug to be able to turn it on or off remotely when needed. Music is played via a Raspberry Pi with Raspotify. The smart plug is useful and convenient to save power in case I fall asleep at night listening to an audio book. This problem can be solved with a simple timer. However, I want my stereo to be on only when I am really using it.
No modifications thanks to a smart plug⌗
In order to achieve this goal I need to detect on the Raspberry Pi if librespot (the software behind Raspotify) has a running alsa process and therefore plays music over the soundcard. If this is the case, the smart plug should be switched on, otherwise it should be switched off.
Librespot runs permanently as a daemon in the background. So in the first step we have to find out which PID the daemon has.
pgrep librespot
The second step is tricky. We collect all alsa processes that are currently accessing a soundcard. In this list PIDs can also be duplicated if a process is accessing multiple soundcards (for example HDMI and audio jack). Now we just have to check if the librespot PID matches one of the alsa PIDs. If this is the case librespot is currently playing music through a soundcard.
sudo lsof +D /dev -F rt | awk '/^p/ {pid=$1} /^t/ {type=$1} /^r0x(74|e)..$/ && type == "tCHR" {print pid}' | cut -c 2- | uniq
The following script is executed on my Raspberry Pi which runs Raspotify. It checks the state of the Hue smart plug and turns it on or off if needed. In my case my smart plug is light id 38.
#!/bin/bash
apikey="********"
ip="hue.zaage.it"
curl="curl -ks -X PUT -H 'Content-Type: application/json' -d"
control="http://$ip/api/$apikey/lights/38/state"
lights="http://$ip/api/$apikey/lights/38"
plug_state="false"
while true; do
alsa_pid=$(sudo lsof +D /dev -F rt | awk '/^p/ {pid=$1} /^t/ {type=$1} /^r0x(74|e)..$/ && type == "tCHR" {print pid}' | cut -c 2- | uniq)
spot_pid=$(pgrep librespot)
# OSRAM Lightify plug states are currently not supported due compatibility issues
# uncomment next line if you are using certified Philips plugs:
plug_state=$(curl -s $lights | jq '.state.on')
if [[ "$spot_pid" == "$alsa_pid" ]]; then
if [[ $plug_state == "false" ]]; then
$curl '{ "on": true }' $control
plug_state="true"
fi
elif [[ $plug_state == "true" ]]; then
$curl '{ "on": false }' $control
plug_state="false"
fi
sleep 1
done