GPIO Pins to control volume

Peter,

Nice script and setup!
For what kind o f project are you using your gadaget, i read something about train, Xmas, werbung… etc?

Could you publish your shutdown script?
I have a pythonscript running but it shutdown random without pressing a button!!!

Greetings

Harry

Hi Harry

I am currently away fom home but will respond to your question soon.

Peter

Hi Harry

I added a short description of my Volumio project in the DIY section:

http://volumio.org/forum/christmas-t2281.html

You can find the shutdown script there.

Hope this helps.

Greetings, Peter

Hi!
For a new project, I start to think about what I need to drive the system.
What I want :
A lcd display, I orderd that one : amazon.fr/gp/product/B00AT8K … ge_o08_s00
I2C interface : amazon.fr/gp/product/B00GBSW … ge_o02_s00 (not sure I need it…)
a play/ pause button
a next button
a previous button
a stop button
a shutdown button
a rotary encoder to set volume (I tried a script written in python and it works)
So I’m looking for a script (or several ) to do all that!
I saw some with additionnal features but without some I need :frowning:
And I am not programmer I need something easy to modify.(if needed)
A question : as I used a I2C dac, will it work with the i2c interface ?
Voila ! If you get this, please let me know ! :smiley:

Buckler ,
Why your script VolumeKnob.py don*t work (((( :confused:

pi@volumio:~$ sudo python /home/pi/VolumeKnob.py File "/home/pi/VolumeKnob.py", line 10 import subprocess ^ IndentationError: unexpected indent pi@volumio:~$
You know what the problem is ??? :confused:

pi@volumio:~$ sudo python /home/pi/VolumeKnob.py Traceback (most recent call last): File "/home/pi/VolumeKnob.py", line 13, in <module> from rotary_class import RotaryEncoder ImportError: No module named rotary_class pi@volumio:~$

What you say ???

@solaar1974

Did you use the “Select all” option? If so when you paste the code you will have extra spaces at each line and create an indentation error.

Voorbeeld.jpg

Just select the code and paste.

Rotary Class
Did you download the rotary_class.py from http://www.bobrathbone.com/raspberrypi_rotary.htm

Here is the code, save as: /home/pi/rotary_class.py

[code]
#!/usr/bin/env python

Raspberry Pi Rotary Encoder Class

$Id: rotary_class.py,v 1.2 2014/01/31 13:34:48 bob Exp $

Author : Bob Rathbone

Site : http://www.bobrathbone.com

This class uses standard rotary encoder with push switch

import RPi.GPIO as GPIO

class RotaryEncoder:

CLOCKWISE=1
ANTICLOCKWISE=2
BUTTONDOWN=3
BUTTONUP=4

rotary_a = 0
rotary_b = 0
rotary_c = 0
last_state = 0
direction = 0

# Initialise rotary encoder object
def __init__(self,pinA,pinB,button,callback):
	self.pinA = pinA
	self.pinB = pinB
	self.button = button
	self.callback = callback

	GPIO.setmode(GPIO.BCM)
	
	# The following lines enable the internal pull-up resistors
	# on version 2 (latest) boards
	GPIO.setwarnings(False)
	GPIO.setup(self.pinA, GPIO.IN, pull_up_down=GPIO.PUD_UP)
	GPIO.setup(self.pinB, GPIO.IN, pull_up_down=GPIO.PUD_UP)
	GPIO.setup(self.button, GPIO.IN, pull_up_down=GPIO.PUD_UP)

	# For version 1 (old) boards comment out the above four lines
	# and un-comment the following 3 lines
	#GPIO.setup(self.pinA, GPIO.IN)
	#GPIO.setup(self.pinB, GPIO.IN)
	#GPIO.setup(self.button, GPIO.IN)

	# Add event detection to the GPIO inputs
	GPIO.add_event_detect(self.pinA, GPIO.FALLING, callback=self.switch_event)
	GPIO.add_event_detect(self.pinB, GPIO.FALLING, callback=self.switch_event)
	GPIO.add_event_detect(self.button, GPIO.BOTH, callback=self.button_event, bouncetime=200)
	return

# Call back routine called by switch events
def switch_event(self,switch):
	if GPIO.input(self.pinA):
		self.rotary_a = 1
	else:
		self.rotary_a = 0

	if GPIO.input(self.pinB):
		self.rotary_b = 1
	else:
		self.rotary_b = 0

	self.rotary_c = self.rotary_a ^ self.rotary_b
	new_state = self.rotary_a * 4 + self.rotary_b * 2 + self.rotary_c * 1
	delta = (new_state - self.last_state) % 4
	self.last_state = new_state
	event = 0

	if delta == 1:
		if self.direction == self.CLOCKWISE:
			# print "Clockwise"
			event = self.direction
		else:
			self.direction = self.CLOCKWISE
	elif delta == 3:
		if self.direction == self.ANTICLOCKWISE:
			# print "Anticlockwise"
			event = self.direction
		else:
			self.direction = self.ANTICLOCKWISE
	if event > 0:
		self.callback(event)
	return


# Push button up event
def button_event(self,button):
	if GPIO.input(button): 
		event = self.BUTTONUP 
	else:
		event = self.BUTTONDOWN 
	self.callback(event)
	return

# Get a switch state
def getSwitchState(self, switch):
	return  GPIO.input(switch)

End of RotaryEncoder class[/code]

We carefull with the indentation… :wink:

Thank you !! !! !!

Works !
Only was mistake and I changed volume control mixer on position “Software”.

Why “Pause” button? Why not “Mute” ?

And if you put 2 encoder:
1 - swivel 360 degrees encoder (Volume left-DOWN & right-UP and push button Mute),
2 - swing-return encoder (left-Previous - right-Next and push button Play/Pause) , like “Sony” (Jog-Dial, in my opinion is called) ?

en.wikipedia.org/wiki/Jog_dial

That would be great and still to this script would someone? :smiley::D:D

…And then I would have finished my project ))) “Brick”… :smiley::D:D …waiting for parts from China )…

Edit january 03 2015 import sys ->import sys,os
EDIT : UPDATE CODE
Hi!
I’m proud to show you my code to add physical buttons to my Volumio project.
Code is inspirated from what I read here and on the web.
It provide buttons for :

-previous

-next

-stop

-play

-stop

-volume control through rotary coder

It is written for Raspberry b+, so for other models need to be adapted.
Script is not finished yet but it works !!! :smiley: :smiley:
Now, I have to manage for the display but I’m waiting for my order to arrive…
It’s my first python script … so if you see error or something wrong, let me know :wink:
Now the code

[code]#!/usr/bin/python

button-rasp

December 28, 2014

Remix by Balbuze (balbuze@gmail.com)2014 December

written for Raspberry B+ :for other model please re-assign gpio port!!!

add physical buttons for a mdp player system (used with Volumio)

Provide : -previous

-next

-stop

-play

-volume control through rotary coder

My first python script !!! Surely not perfect…To be improved

To do : add code to manage lcd display

inspirated from :

Connecting a Push Switch http://razzpisampler.oreilly.com/ch07.html

Tutorial: Raspberry Pi GPIO PINS AND PYTHON http://makezine.com/projects/tutorial-raspberry-pi-gpio-pins-and-python/

radio.py

January 23, 2013

Written by Sheldon Hartling for Usual Panic.

MIT license, all text above must be included in any redistribution

based on code from Kyle Prier (http://wwww.youtube.com/meistervision)

and AdaFruit Industries (https://www.adafruit.com)

Kyle Prier - https://www.dropbox.com/s/w2y8xx7t6gkq8yz/radio.py

AdaFruit - https://github.com/adafruit/Adafruit-Raspberry-Pi-Python-Code.git, Adafruit_CharLCD

Rotary class part from : Author : Bob Rathbone

Site : http://www.bobrathbone.com

import RPi.GPIO as GPIO
import sys,os
#import mpd
import time
#import random
from rotary_class import RotaryEncoder
import subprocess

#-----------------------------------------------------------

GPIO.setmode(GPIO.BCM)

Define GPIO output pins for Radio Controls

SW_PREV = 12 # Pin 32
SW_NEXT = 16 # Pin 36
SW_STOP = 20 # Pin 38
SW_SHTDWN = 21 # Pin 40
SW_PLAY = 26 # Pin 37

Define GPIO for rotary encoder + button

PIN_A = 23 # Pin 16
PIN_B = 24 # Pin 18
BUTTON = 25 # Pin 22
#------------------------------------------------------------
#As I have a PI-amp from Iqaudio I need to unmute it at startup

#A piece of code will be used to mute it at shutdown
#------------------------------------------------------------

#Code to manage Rotary encoder + switch

This is the event callback routine to handle events

def switch_event(event):
if event == RotaryEncoder.CLOCKWISE:
subprocess.call([‘mpc’, ‘volume’, ‘+2’ ])
time.sleep(.2)
elif event == RotaryEncoder.ANTICLOCKWISE:
subprocess.call([‘mpc’, ‘volume’, ‘-2’ ])
time.sleep(.2)
elif event == RotaryEncoder.BUTTONDOWN:
subprocess.call([‘mpc’, ‘toggle’ ])
print ‘toggle’
#elif event == RotaryEncoder.BUTTONUP:
#print “Button up”
return

Define the switch

rswitch = RotaryEncoder(PIN_A,PIN_B,BUTTON,switch_event)
#----------------------------------------------------------

#code to manage BUTTONS previous,next,stop,play,shutdown
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_STOP,GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(SW_SHTDWN,GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(SW_PLAY,GPIO.IN, pull_up_down=GPIO.PUD_UP)
while True:
try:
prev_switch = GPIO.input(SW_PREV)
next_switch = GPIO.input(SW_NEXT)
stop_switch = GPIO.input(SW_STOP)
shtdwn_switch = GPIO.input(SW_SHTDWN)
play_switch = GPIO.input(SW_PLAY)
if prev_switch == False:
subprocess.call([‘mpc’, ‘prev’ ])
print “PRECED”
elif next_switch == False:
subprocess.call([‘mpc’, ‘next’ ])
print “SUIVANT”
elif stop_switch == False:
subprocess.call([‘mpc’, ‘stop’ ])
print “stop”
elif play_switch == False:
subprocess.call([‘mpc’, ‘play’ ])
print “play”
elif shtdwn_switch == False:
os.system(“shutdown now -h”)
print “shutdown in progress : wait 20 sec before unplug”
time.sleep(0.5)

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

End of program[/code]

I little don’t understand this :

# This is the event callback routine to handle left knob events

What is it “left knob” ?

Looking at your script makes me wonder about the imported modules. I believe there are more imported modules then you use.

mpd - not used?
random - not used?
os - only used to do a shutdown, cant this be done using subprocess?
getopt - not used?

GPIO.setmode
shouldn’t this be used to set it to board or bcm, which one is default? The script doesn’t state what is used.

I must admit i haven’t read all the previous scripts, you might have copied and removed parts you don’t need but missed these. Or there critical could be.

In the notes and your post, you state stop two times one button should be enough :wink: maybe it should be pause :smiley:

Now I have to “Mute” mode instead of a “Pause” mode on my rotary encoder №1:

[code]#!/usr/bin/env python

Raspberry Pi Rotary Test Encoder Class

Author : Bob Rathbone

Site : http://www.bobrathbone.com

This class uses a standard rotary encoder with push switch

import subprocess
import sys
import time
from rotary_class import RotaryEncoder

Define GPIO inputs (BCM)

PIN_A = 23 # Pin 16
PIN_B = 24 # Pin 18
BUTTON = 25 # Pin 22

This is the event callback routine to handle events

def switch_event(event):
if event == RotaryEncoder.CLOCKWISE:
subprocess.call([‘mpc’, ‘volume’, ‘+2’ ])
time.sleep(.2)
elif event == RotaryEncoder.ANTICLOCKWISE:
subprocess.call([‘mpc’, ‘volume’, ‘-2’ ])
time.sleep(.2)
elif event == RotaryEncoder.BUTTONDOWN:
subprocess.call([‘mpc’, ‘volume’, ‘-25’ ])
#elif event == RotaryEncoder.BUTTONUP:
#print “Button up”
return

Define the switch

rswitch = RotaryEncoder(PIN_A,PIN_B,BUTTON,switch_event)

while True:
time.sleep(0.5)[/code]

But if pressing it again makes a return to the original volume… And since you have after you just have to turn the knob to the right (volume+).

…Now I find rotary encoder №2 ( ? ) < Left - Right > in only ONE step with push button ( <Prew - Next>,Pause/Play)… :unamused: :unamused: :unamused:

Personally i prefer pause over mute since mute keeps playing the song.

Right… you updated your post while i was typing…

I guess you want the script to do something like:

On mute press:
- read "mute variable" 
-- If muted
--- set volume to "current volume"
--- set "mute variable" to unmuted
-- else
--- read the "current volume"
--- save "current volume" in a variable
--- set volume to 0
--- set "mute variable" to muted

This would then end up around here

elif event == RotaryEncoder.BUTTONDOWN:
             subprocess.call

I had enough of this. :smiley:

More to add, when rotary volume knob displayed here is

and after the termination of turning the standard mpd info displayed again

:nerd: :nerd: :nerd: :unamused: :unamused: :unamused:

@MobeyDuck @solaar1974
Thank you guys for your comments ! I will correct it !
@solaar1974 have you already have a script for the lcd display ?

No. I don’t have a script. I’m not a programmer. I’m a techie. Only now has it:
how-launch-oled-display-with-now-playing-t2260.html
But I think it’s time to learn python :slight_smile:

I have updated my script. Still job to do… :wink:

I have tried to add some extra function to the button of the rotary encoder. The script is far from perfect but i want to share it and hope to get some feedback to improve the result.

FUNCTIONS:
a short press = (de)activates pause
a long press = at this moment nothing but I would like to add the option that the function of the knob changes from volume-control to station/song-control (or get into a menu with different options but i prefer to keep it simple)
a very long press = shutdown

VolumioKnob.py

[code]#!/usr/bin/env python

#import os
import subprocess
import sys
import time
from rotary_class import RotaryEncoder

global time_stamp
time_stamp = ‘’
time_now = ‘’

Define GPIO inputs

PIN_A = 23 # Pin 8
PIN_B = 24 # Pin 10
BUTTON = 25 # Pin 7

This is the event callback routine to handle events

def switch_event(event):
if event == RotaryEncoder.CLOCKWISE:
subprocess.call([‘mpc’, ‘volume’, ‘+2’ ])
time.sleep(.2)
elif event == RotaryEncoder.ANTICLOCKWISE:
subprocess.call([‘mpc’, ‘volume’, ‘-2’ ])
time.sleep(.2)
elif event == RotaryEncoder.BUTTONDOWN:
global time_stamp
time_stamp=time.time()
time.sleep(.1)
#print “Button Down”
elif event == RotaryEncoder.BUTTONUP:
time_now=time.time()
delta=int(time_now-time_stamp)
#print delta
#print “Button Up”
if delta<=1:
subprocess.call([‘mpc’, ‘toggle’ ])
#print " Toggle"
#time.sleep(.2)
elif delta > 2:
#print “Shutdown”
subprocess.call([‘mpc’, ‘stop’ ])
subprocess.call([‘sudo’, ‘halt’ ])
#elif 1 < delta <= 2:
#print “do something else”
#subprocess.call([‘mpc’, ‘stop’ ])

    return

Define the switch

rswitch = RotaryEncoder(PIN_A,PIN_B,BUTTON,switch_event)

while True:
time.sleep(0.1)[/code]

…so still some work to do :smiley:

I left so : [code]#!/usr/bin/python

button-rasp

December 28, 2014

Remix by Balbuze (balbuze@gmail.com)2014 December

written for Raspberry B+ :for other model please re-assign gpio port!!!

add physical buttons for a mdp player system (used with Volumio)

Provide : -previous

-next

-stop

-play

-volume control through rotary coder

My first python script !!! Surely not perfect…To be improve

To do : add code to manage lcd display

inspirated from :

Connecting a Push Switch http://razzpisampler.oreilly.com/ch07.html

Tutorial: Raspberry Pi GPIO PINS AND PYTHON http://makezine.com/projects/tutorial-raspberry-pi-gpio-pins-and-python/

radio.py

January 23, 2013

Written by Sheldon Hartling for Usual Panic.

MIT license, all text above must be included in any redistribution

based on code from Kyle Prier (http://wwww.youtube.com/meistervision)

and AdaFruit Industries (https://www.adafruit.com)

Kyle Prier - https://www.dropbox.com/s/w2y8xx7t6gkq8yz/radio.py

AdaFruit - https://github.com/adafruit/Adafruit-Raspberry-Pi-Python-Code.git, Adafruit_CharLCD

Rotary class part from : Author : Bob Rathbone

Site : http://www.bobrathbone.com

import RPi.GPIO as GPIO
import sys
#import mpd
import time
#import random
from rotary_class import RotaryEncoder
import subprocess

#-----------------------------------------------------------

GPIO.setmode(GPIO.BCM)

Define GPIO output pins for Radio Controls

SW_PREV = 17 # Pin 11
SW_NEXT = 27 # Pin 13
SW_SHTDWN = 4 # Pin 7
SW_PAUSE = 22 # Pin 15

Define GPIO for rotary encoder + button

PIN_A = 23 # Pin 16
PIN_B = 24 # Pin 18
BUTTON = 25 # Pin 22
#------------------------------------------------------------
#As I have a PI-amp from Iqaudio I need to unmute it at startup

#A piece of code will be used to mute it at shutdown
#------------------------------------------------------------

#Code to manage Rotary encoder + switch

This is the event callback routine to handle events

def switch_event(event):
if event == RotaryEncoder.CLOCKWISE:
subprocess.call([‘mpc’, ‘volume’, ‘+2’ ])
time.sleep(.2)
elif event == RotaryEncoder.ANTICLOCKWISE:
subprocess.call([‘mpc’, ‘volume’, ‘-2’ ])
time.sleep(.2)
elif event == RotaryEncoder.BUTTONDOWN:
subprocess.call([‘mpc’, ‘volume’, ‘-25’ ])
#print ‘toggle’
#elif event == RotaryEncoder.BUTTONUP:
#print “Button up”
return

Define the switch

rswitch = RotaryEncoder(PIN_A,PIN_B,BUTTON,switch_event)
#----------------------------------------------------------

#code to manage BUTTONS previous,next,stop,play,shutdown
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_SHTDWN,GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(SW_PAUSE,GPIO.IN, pull_up_down=GPIO.PUD_UP)
while True:
try:
prev_switch = GPIO.input(SW_PREV)
next_switch = GPIO.input(SW_NEXT)
shtdwn_switch = GPIO.input(SW_SHTDWN)
pause_switch = GPIO.input(SW_PAUSE)
if prev_switch == False:
subprocess.call([‘mpc’, ‘prev’ ])
print “PRECED”
elif next_switch == False:
subprocess.call([‘mpc’, ‘next’ ])
print “SUIVANT”
elif pause_switch == False:
subprocess.call([‘mpc’, ‘pause’ ])
print “pause”
elif shtdwn_switch == False:
subprocess.call([‘sudo’, ‘halt’ ])
print “shutdown in progress : wait 20 sec before unplug”
time.sleep(0.5)

except KeyboardInterrupt:
print “\nExit”
GPIO.setwarnings(False)
GPIO.cleanup()
sys.exit(0)

End of program[/code]

I re-update my script so that shutdown works…