Thank you for your donation!


Cloudsmith graciously provides open-source package management and distribution for our project.


Idea: Change GPIO state on mpd play / stop
#1
I've borrrowed / adapted a bash script I found on the internet to control a relay based on the contents of the /proc/asound/card0/pcm0p/sub0/status file.

It sits and checks that file every n seconds, and if 'RUNNING' is found, changes the state of y GPIO.

If 'RUNNING' is then not found it waits x seconds before changing the state of the y GPIO back again.

I run this as a service and it works well with mpd / shairport etc. However, it would be great to incorporate this in worker.php or somewhere more suitable.

The feature could be generalised - so if 'RUNNING' is found run 'up.sh' / not found run 'down.sh' - just like network configuration, as I'm sure there are other things people would like to run if they hit play.

The variables could be:

Check interval (seconds): n
State change delay (seconds): x
Set-up script (optional): allows initialisation of a specified GPIO pin on boot
Play script: user set field like the LCD update script
Stop script: user set field like the LCD update script

And in these two files the user could implement anything they want.

Or it could be made 'amplifier relay specific' as someone on the forum has done - with a dedicated page for amplifier control.

Code:
#!/bin/bash

set -e

#   Exports pin to userspace
echo "23" > /sys/class/gpio/export

# Sets pin 23 as an output
echo "out" > /sys/class/gpio/gpio23/direction

#time to wait until the amplifier is turned off in seconds
off_timer_time=60

#set variables
last_is_playing=0
off_timer=0

while true
do
    if cat /proc/asound/card0/pcm0p/sub0/status | grep -i RUNNING > /dev/null
    then
        is_playing=1
    else
        is_playing=0
    fi

    #0->1
    if [[ "$last_is_playing" -eq "0" && "$is_playing" -eq "1" ]]
    then
        off_timer=0
        echo "Turning amplifier on"
        echo "1" > /sys/class/gpio/gpio23/value
    fi

    #1->0
    if [[ "$last_is_playing" -eq "1" && "$is_playing" -eq "0" ]]
    then
        off_timer=1
    fi

    if [ "$off_timer" -ne "0" ]
    then
        if [ "$off_timer" -eq "$off_timer_time" ]
        then
            off_timer=0
            echo "Turning amplifier off"
            echo "0" > /sys/class/gpio/gpio23/value
        else
            ((off_timer++))
            #echo $off_timer
        fi
    fi

    last_is_playing=$is_playing
    sleep 1
done

Code:
[Unit]
Description=Automatic Amplifier Control

[Service]
Type=simple
ExecStart=/home/pi/autoamp.sh
User=root

[Install]
WantedBy=multi-user.target

#systemctl enable autoamp.service
#systemctl daemon-reload
#systemctl start autoamp.service
Reply
#2
Thanks to this, I finally got around to looking at the /proc/asound virtual file system maintained by ALSA. Cool beans.

At first blush, the generalization would have to include the possibility that it's not card0 that's been selected. Case in point, my USB DAC is card1 (because card0 is the "onboard audio device").

Regards,
Kent
Reply
#3
Hi @tristanc,

Scripts that contain their own polling loops and delays need to be run separately from worker.php. This is because worker contains its own polling loop for processing jobs, updating renderer status, etc., and this loop requires a fixed time interval.

-Tim
Enjoy the Music!
moodeaudio.org | Mastodon Feed | GitHub
Reply
#4
(01-23-2019, 05:06 PM)Tim Curtis Wrote: Hi @tristanc,

Scripts that contain their own polling loops and delays need to be run separately from worker.php. This is because worker  contains its own polling loop for processing jobs, updating renderer status, etc., and this loop requires a fixed time interval.

-Tim

Ah, so there'd need to be something 'above' worker.php. And doing a quick google suggests multi-threaded PHP is not recommended for web purposes...

Perhaps best left as a service outside of Moode then unless there's something clever that can be done.
Reply
#5
(01-23-2019, 10:54 AM)tristanc Wrote: I've borrrowed / adapted a bash script I found on the internet to control a relay based on the contents of the /proc/asound/card0/pcm0p/sub0/status file.

It sits and checks that file every n seconds, and if 'RUNNING' is found, changes the state of y GPIO.

If 'RUNNING' is then not found it waits x seconds before changing the state of the y GPIO back again.

I run this as a service and it works well with mpd / shairport etc. However, it would be great to incorporate this in worker.php or somewhere more suitable.

The feature could be generalised - so if 'RUNNING' is found run 'up.sh' / not found run 'down.sh' - just like network configuration, as I'm sure there are other things people would like to run if they hit play.

The variables could be:

Check interval (seconds): n
State change delay (seconds): x
Set-up script (optional): allows initialisation of a specified GPIO pin on boot
Play script: user set field like the LCD update script
Stop script: user set field like the LCD update script

And in these two files the user could implement anything they want.

Or it could be made 'amplifier relay specific' as someone on the forum has done - with a dedicated page for amplifier control.

Code:
#!/bin/bash

set -e

#   Exports pin to userspace
echo "23" > /sys/class/gpio/export

# Sets pin 23 as an output
echo "out" > /sys/class/gpio/gpio23/direction

#time to wait until the amplifier is turned off in seconds
off_timer_time=60

#set variables
last_is_playing=0
off_timer=0

while true
do
    if cat /proc/asound/card0/pcm0p/sub0/status | grep -i RUNNING > /dev/null
    then
        is_playing=1
    else
        is_playing=0
    fi

    #0->1
    if [[ "$last_is_playing" -eq "0" && "$is_playing" -eq "1" ]]
    then
        off_timer=0
        echo "Turning amplifier on"
        echo "1" > /sys/class/gpio/gpio23/value
    fi

    #1->0
    if [[ "$last_is_playing" -eq "1" && "$is_playing" -eq "0" ]]
    then
        off_timer=1
    fi

    if [ "$off_timer" -ne "0" ]
    then
        if [ "$off_timer" -eq "$off_timer_time" ]
        then
            off_timer=0
            echo "Turning amplifier off"
            echo "0" > /sys/class/gpio/gpio23/value
        else
            ((off_timer++))
            #echo $off_timer
        fi
    fi

    last_is_playing=$is_playing
    sleep 1
done

Code:
[Unit]
Description=Automatic Amplifier Control

[Service]
Type=simple
ExecStart=/home/pi/autoamp.sh
User=root

[Install]
WantedBy=multi-user.target

#systemctl enable autoamp.service
#systemctl daemon-reload
#systemctl start autoamp.service


Haha I'm like a mole, digging up old old topics. Wink

As I have little problems with GPIO in shell, I rewrote your script to python. I hope no one will be offended.
Just be sure to carefully check that the path is proc/asound/....  refers to your card.

Code:
#!/usr/bin/python3

import RPi.GPIO as GPIO
import os
import time

Pin_mute = 16

off_timer_time = 60
last_is_playing = 0
off_timer = 0

GPIO.setwarnings(False)
GPIO.setmode(GPIO.BCM)
GPIO.setup(Pin_mute, GPIO.OUT)

while True:
   if os.system('cat /proc/asound/card0/pcm0p/sub0/status | grep -i RUNNING > /dev/null') == 0:
       is_playing = 1
   else:
       is_playing = 0
#0->1    
   if last_is_playing == 0 and is_playing == 1:
       off_timer = 0
       print('Turning amplifier ON')
       GPIO.output(Pin_mute, 1)
#1->0        
   if last_is_playing == 1 and is_playing == 0:
       off_timer = 1
   
   if off_timer != 0:
       if off_timer == off_timer_time:
           off_timer = 0
           print('Turning amplifier OFF')
           GPIO.output(Pin_mute, 0)
       else:
           off_timer += 1
   last_is_playing = is_playing
   time.sleep(1)

Cheers.


AD. 
2 hours later...
I found a solution to the message problem when initializing the GPIO port
echo 16 > /sys/class/gpio/export
-bash: echo: write error: device or resource busy

Code:
echo "16" > /sys/class/gpio/export
to this
Code:
[ -L /sys/class/gpio/gpio16 ] || echo "16" > /sys/class/gpio/export
to prevent a message a write error: device or resource busy

found here: Raspbery Pi forum
Reply


Forum Jump: