Thank you for your donation!


Instruction Guide Use hardware momentary switches to control moOde
#1
Hardware momentary switches can be used to control the play, pause, next, previous functions of moode. They can also be used to power off and to launch a playlist.
On the hardware side, you set your hardware button to connect the ground pin of your RPi with a GPIO pin of your choice. Have a look here to see how to select the gpio pins.
Then you have to open a ssh session.

Create a new directory called "hwbuttons"
Code:
mkdir hwbuttons

Go to the new directory
Code:
cd hwbuttons

Open nano text editor
Code:
nano

Paste the following python script. This python script include the following buttons:

Toggle play pause: GPIO 12
Previous: GPIO 10
Next: GPIO 11
Volume up: GPIO 20
Volume down: GPIO 26
Power off: GPIO 9
Launch playlist "JAZZ_STREAM": GPIO 16
Launch playlist "MUSIC_STREAM": GPIO 13

It works for radio stations and music files. Make sure no spaces on playlists names.
If you are not interested in a particular button, mark it with # everywhere it appears.

Code:
#!/usr/bin/python
#script for moode audio GPIO buttons
#not sure this is needed:
#sudo apt-get update
#sudo apt-get install python-dev
#sudo apt-get install python-rpi.gpio
#on playlist names no spaces

#import
import RPi.GPIO as GPIO
import sys
import time
import os
import subprocess

#set GPIO mode
GPIO.setmode(GPIO.BCM)

#Define your GPIO pins
SW_PREV = 10
SW_NEXT = 11
SW_PLAY = 12
SW_VOLUP = 20
SW_VOLDOWN = 26
SW_POWEROFF = 9
SW_PL1 = 16
SW_PL2 = 13


#code to manage BUTTONS
GPIO.setup(SW_PREV,GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(SW_NEXT,GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(SW_PLAY,GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(SW_VOLUP,GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(SW_VOLDOWN,GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(SW_POWEROFF,GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(SW_PL1,GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(SW_PL2,GPIO.IN, pull_up_down=GPIO.PUD_UP)
while True:
  try:
     prev_switch = GPIO.input(SW_PREV)
     next_switch = GPIO.input(SW_NEXT)
     play_switch = GPIO.input(SW_PLAY)
     volup_switch = GPIO.input(SW_VOLUP)
     voldown_switch = GPIO.input(SW_VOLDOWN)
     poweroff_switch = GPIO.input(SW_POWEROFF)
     pl1_switch = GPIO.input(SW_PL1)
     pl2_switch = GPIO.input(SW_PL2)
     if prev_switch == False:
        subprocess.call(['mpc', 'prev' ])
        print "previous"
     elif next_switch == False:
        subprocess.call(['mpc', 'next' ])
        print "next"
     elif poweroff_switch == False:
        subprocess.call(['mpc', 'stop' ])
        subprocess.call(['sudo', 'poweroff' ])
        print "shutting down"
     elif volup_switch == False:
        subprocess.call(['/var/www/vol.sh','up','2' ])
        print "volumeup"
     elif voldown_switch == False:
        subprocess.call(['/var/www/vol.sh','dn','2' ])
        print "volumedown"
     elif pl1_switch == False:
        subprocess.call(['mpc','clear' ])
        subprocess.call(['mpc','load','JAZZ_STREAM' ])
        subprocess.call(['mpc','play' ])
     elif pl2_switch == False:
        subprocess.call(['mpc','clear' ])
        subprocess.call(['mpc','load','MUSIC_STREAM' ])
        subprocess.call(['mpc','play' ])
     elif play_switch == False:
        subprocess.call(['mpc', 'toggle' ])
        print "play"
     time.sleep(0.5)

  except KeyboardInterrupt:
     print "\nExit"
     GPIO.setwarnings(False)
     GPIO.cleanup()
     sys.exit(0)
#End of program

ctrl-x and save the file as "buttons.py"

To set the script to run every time you launch moode
Code:
sudo nano /etc/rc.local


Add the line below just before the exit 0
Code:
sudo python /home/pi/hwbuttons/buttons.py &

It works on my moode streamer. I did put this together from information I found on the volumio forum and from help I received from Kent (aka theoldpresbyope). It is possible that some of the lines in the script are not needed.

Remy
Reply
#2
Very nice. Thank you for share
Reply
#3
Hi Remy,

Thanks for your great tutorial. Combined with your lcd/oled pydPiper script it adds very useful operational flexibility to moOde.

Did you need to de-bounce your momentary push-button switches?

I notice that occasionally the "stop"/"play" toggle appears not to respond, jumping to the previous state due I think to contact bounce. Or maybe it's just poor quality switches I'm using for testing.

Any advice would be appreciated.

Regards,
Richard.
Reply
#4
Hi Richard,
Sorry for the delay. Since mine is working properly with the same script, the problem might be with the switch. Or the software can be improved by forcing a delay after a command is received and before receiving another one. That is beyond what i am able to do.
Remy
Reply
#5
(09-27-2018, 03:49 PM)remy1961 Wrote: Hi Richard,
Sorry for the delay. Since mine is working properly with the same script, the problem might be with the switch. Or the software can be improved by forcing a delay after a command is received and before receiving another one. That is beyond what i am able to do.
Remy

Thanks Remy,

A change of switch minimised the problem.

There is a lot of information on the web about de-bouncing in software but it is beyond me also.

I guess a neat solution would be to insert a schmitt trigger between the swicth and the GPIO pin but with a good switch it's not really worth the effort.

Regards,
Richard.
Reply
#6
(05-20-2018, 03:05 PM)remy1961 Wrote: Hardware momentary switches can be used to control the play, pause, next, previous functions of moode. They can also be used to power off and to launch a playlist
...
Thank you for the code. It works perfectly, but only if some blanks are removed before 
"        elif voldown_switch == False:"
Reply
#7
(02-24-2019, 05:14 PM)Cyanoazimin Wrote:
(05-20-2018, 03:05 PM)remy1961 Wrote: Hardware momentary switches can be used to control the play, pause, next, previous functions of moode. They can also be used to power off and to launch a playlist
...
Thank you for the code. It works perfectly, but only if some blanks are removed before 
"        elif voldown_switch == False:"

Good catch.

In Python correct indentation is important.
Reply
#8
(02-24-2019, 05:14 PM)Cyanoazimin Wrote:
(05-20-2018, 03:05 PM)remy1961 Wrote: Hardware momentary switches can be used to control the play, pause, next, previous functions of moode. They can also be used to power off and to launch a playlist
...
Thank you for the code. It works perfectly, but only if some blanks are removed before 
"        elif voldown_switch == False:"

Correction made. Thanks.
Remy
Reply
#9
I have changed your code to interrupt and debouncing, as it sometimes did not react fast enough. And added time to track bouncing in the serial monitor. No hardware debouncing needed (no pull resistors, capacitors). Works more smoothly now:

Code:
#!/usr/bin/python
#coding: utf8
#script for moode audio GPIO buttons
#on playlist names no spaces

#import
import RPi.GPIO as GPIO
import sys
import time
import datetime
import os
import subprocess

#set GPIO mode instead of GPIO.setmode(GPIO.BOARD) - Zählweise der Pins festlegen
GPIO.setmode(GPIO.BCM)

#Define your GPIO pins
SW_PREV = 10
SW_NEXT = 11
SW_POWEROFF = 9
SW_PLAY = 12
#SW_VOLUP = 20
#SW_VOLDOWN = 26
#SW_PL1 = 16
#SW_PL2 = 13
PRELL = 1000          # Adjust to the button characteristics if necessary

#code to manage BUTTONS
GPIO.setup(SW_PREV,GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(SW_NEXT,GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(SW_POWEROFF,GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(SW_PLAY,GPIO.IN, pull_up_down=GPIO.PUD_UP)
#GPIO.setup(SW_VOLUP,GPIO.IN, pull_up_down=GPIO.PUD_UP)
#GPIO.setup(SW_VOLDOWN,GPIO.IN, pull_up_down=GPIO.PUD_UP)
#GPIO.setup(SW_PL1,GPIO.IN, pull_up_down=GPIO.PUD_UP)
#GPIO.setup(SW_PL2,GPIO.IN, pull_up_down=GPIO.PUD_UP)

# Ereignis-Prozedur für SW_PREV
def eSW_PREV(channel):
       subprocess.call(['mpc', 'prev' ])
       print str(datetime.datetime.now())[:19] + " previous"

def eSW_NEXT(channel):
       subprocess.call(['mpc', 'next' ])
       print str(datetime.datetime.now())[:19] + " next"

def eSW_POWEROFF(channel):
       subprocess.call(['mpc', 'stop' ])
       subprocess.call(['sudo', 'poweroff' ])
       print str(datetime.datetime.now())[:19] + " shutting down"

def eSW_PLAY(channel):
       subprocess.call(['mpc', 'toggle' ])
       print str(datetime.datetime.now())[:19] + " play"        
       
# Ereignis deklarieren
GPIO.add_event_detect(SW_PREV, GPIO.RISING, callback = eSW_PREV, bouncetime = PRELL)
GPIO.add_event_detect(SW_NEXT, GPIO.RISING, callback = eSW_NEXT, bouncetime = PRELL)
GPIO.add_event_detect(SW_POWEROFF, GPIO.RISING, callback = eSW_POWEROFF, bouncetime = PRELL)
GPIO.add_event_detect(SW_PLAY, GPIO.RISING, callback = eSW_PLAY, bouncetime = PRELL)

# Eigentlicher Programmablauf
while True:
   time.sleep(1)
Reply
#10
(03-03-2019, 06:29 PM)Cyanoazimin Wrote: I have changed your code to interrupt and debouncing, as it sometimes did not react fast enough. And added time to track bouncing in the serial monitor. No hardware debouncing needed (no pull resistors, capacitors). Works more smoothly now:

Code:
#!/usr/bin/python
#coding: utf8
#script for moode audio GPIO buttons
#on playlist names no spaces

#import
import RPi.GPIO as GPIO
import sys
import time
import datetime
import os
import subprocess

#set GPIO mode instead of GPIO.setmode(GPIO.BOARD) - Zählweise der Pins festlegen
GPIO.setmode(GPIO.BCM)

#Define your GPIO pins
SW_PREV = 10
SW_NEXT = 11
SW_POWEROFF = 9
SW_PLAY = 12
#SW_VOLUP = 20
#SW_VOLDOWN = 26
#SW_PL1 = 16
#SW_PL2 = 13
PRELL = 1000          # Adjust to the button characteristics if necessary

#code to manage BUTTONS
GPIO.setup(SW_PREV,GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(SW_NEXT,GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(SW_POWEROFF,GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(SW_PLAY,GPIO.IN, pull_up_down=GPIO.PUD_UP)
#GPIO.setup(SW_VOLUP,GPIO.IN, pull_up_down=GPIO.PUD_UP)
#GPIO.setup(SW_VOLDOWN,GPIO.IN, pull_up_down=GPIO.PUD_UP)
#GPIO.setup(SW_PL1,GPIO.IN, pull_up_down=GPIO.PUD_UP)
#GPIO.setup(SW_PL2,GPIO.IN, pull_up_down=GPIO.PUD_UP)

# Ereignis-Prozedur für SW_PREV
def eSW_PREV(channel):
       subprocess.call(['mpc', 'prev' ])
       print str(datetime.datetime.now())[:19] + " previous"

def eSW_NEXT(channel):
       subprocess.call(['mpc', 'next' ])
       print str(datetime.datetime.now())[:19] + " next"

def eSW_POWEROFF(channel):
       subprocess.call(['mpc', 'stop' ])
       subprocess.call(['sudo', 'poweroff' ])
       print str(datetime.datetime.now())[:19] + " shutting down"

def eSW_PLAY(channel):
       subprocess.call(['mpc', 'toggle' ])
       print str(datetime.datetime.now())[:19] + " play"        
       
# Ereignis deklarieren
GPIO.add_event_detect(SW_PREV, GPIO.RISING, callback = eSW_PREV, bouncetime = PRELL)
GPIO.add_event_detect(SW_NEXT, GPIO.RISING, callback = eSW_NEXT, bouncetime = PRELL)
GPIO.add_event_detect(SW_POWEROFF, GPIO.RISING, callback = eSW_POWEROFF, bouncetime = PRELL)
GPIO.add_event_detect(SW_PLAY, GPIO.RISING, callback = eSW_PLAY, bouncetime = PRELL)

# Eigentlicher Programmablauf
while True:
   time.sleep(1)

thanks for sharing, it works perfectly on my pi
Reply


Forum Jump: