GPIO Pins to control volume

Ok
I did it following this thread : rpi-volumio-gpio-for-python-t1491.html
It works now ! But I change step from 2 to 4 in the VolumeKnob.py file.
Thanks a lot!

too bad…
I thought it was ok but after a reboot mpd does not work anymore. No webUI… I can ssh to my pi. Get the following error :

pi@volumio-bureau:~$ sudo service mpd restart [ ok ] Stopping Music Player Daemon: mpd. [....] Starting Music Player Daemon: mpdIllegal instruction failed!
What to do to avoid a complete re-install ?
info : At boot time I hear the boot sound of Volumio

I bet some packages have been upgraded during the installation. A complete re-install is the fastest way to get you back up and running.

To prevent this from happening you could try and change “jessie” into “wheezy” in the sources file. This should stop apt from getting newer packages that corrupt volumio and the required services. BUT PLEASE NOTE this needs to be tested, if you see that packages need to be upgraded before you can install some thing using apt try to use an older version of the package you want to install. Many upgrade packages break volumio.

Balbuze you could try and see if you can find the illegal instuction in the config files of mpd.

This difficult is the reason to have something in volumio directly in standard for GPIO :slight_smile:.
Good luck :wink:.

I’m looking for an alternative to python-rpi.gpio, going trough the raspberry pi wiki i found that you should be able to control the GPIO’s using bash scripts. If this works your not required to install python-rpi.gpio and risk corrupting volumio.

I cant test this today, ill see if i can try something tomorrow.

see: elinux.org/RPi_Low-level_peripherals
“Bash shell script, using sysfs, part of the raspbian operating system”

Ooops, I have not publiced my latest instructions!

I had the same problems as Balbuze. But I is possible to install rpi-gpio without killing Volumio!

wget http://sourceforge.net/projects/raspberry-gpio-python/files/raspbian-wheezy/python-rpi.gpio_0.5.8-1_armhf.deb
sudo dpkg -i python-rpi.gpio_0.5.8-1_armhf.deb

…and this works

NespressoPlayer.jpg
Succes!

Harry

Hi
I re-did a fresh install. Now it works following Buckler instructions.
Thank you !
Now, next step is having a display lcd or oled .
Buckler, what model do you use ? wich code and what information are displayed ?
I 'd like to add button to go to next/previous song etc…

@Balbuze

This a really cheap display about 4 euro, 2x16 characters blue & white (HD44780). A OLED would be nice but so expensive…
The first line is showing Time + Status + Volume
The second line is showing Stationname + Artist + Title (scrolling)
When you play a song the time will show the remaining time and the second line will show you the artist + Title

A nice feature is to use an I2C backpack, you will only have 4 wire between the Pi and the Lcd+BP.

You want a display and buttons, is an Adafruit LCD+keypad kit not an options?
There are a lot of python scripts available wich can be installed with Volumio!

Greetings

Harry

Hi
I ran into the same problem with Volumio and GPIO Python. I then searched and found a solution here in this forum (can not currently find it):
I installed the GPIO Python not with this “sudo apt-get install python-rpi.gpio” but instead did this

sudo su
wget http://sourceforge.net/projects/raspberry-gpio-python/files/raspbian-wheezy/python-rpi.gpio_0.5.8-1_armhf.deb
dpkg -i python-rpi.gpio_0.5.8-1_armhf.deb

After that I was able to access GPIO from Python and still have Volumio running.

I have the following system setup and wrote a script to check for 4 button presses (next song, previous song, first song in playlist, random play toggle). The script also reads a 10k (analog) potentiometer using MCP3008 and sets mpd volume accordingly. Works fine.

System Schematics here

xmasTV-schema.jpg

Here is a pic of the back of my gadget running volumio (backpanel with shutdown pushbutton)

Rear_2.jpg

Here is the script

#!/usr/bin/python
# coding: utf-8
#------------------------------------------------------
# Client for mpd-Server
#   Programm starts 8 Threads
#   waits für button click on four buttons - sets up three interrupt routines
#   button 1 (GPIO23) :  jump to next title in playlist
#   button 2 (GPIO24) :  jump to previuos title in playlist
#   button 3  (GPIO8) :  jump to first title in playlist
#   button 4  (GPIO15) : set mpd player to random mode (toggle)
#   Waits also for random seconds to play werbung, suspends currentplaylist
#   
#   Led1 blinks as long as program runs
#   Pressing a buttons blinks Led2 twice for visual feedback
#   Successful connection to mpd Server blinks Led2 twice
#   keyboard Interrupt is catched for testing purposes in Terminal, signals termination to all threads vi variable exitapp
#
#   script also starts thread to read volume potentiometer and sets mpd volume accordingly
#   code to read pot via chip MCP3008 is taken from Adafruits learning unit
#   Analog Inputs for Raspberry Pi Using the MCP3008 (they call it bit banged). 
#   This script uses GPIO Pins 4/17/27/22  for CLK/DOUT/CS/CS
#
#   Script is started via /etc/rc.local
#
#   Pretty simple version found on the Volumio-Forum
#   Extended and adapted by Peter K. Boxler, December 2014 
#-------------------------------------------------------

import RPi.GPIO as GPIO
import sys, getopt, os
import mpd
import time
import random
from threading import Thread

GPIO.setmode(GPIO.BCM)
buttonPinNext 	= 8
buttonPinPrev 	= 24
buttonPinStart 	= 23
buttonPinRandom = 15
potschalter =   14

led1=25                 # green led blinks as long as script runs
led2=7                  # red led blinks three times: acks button press
led3=9                  # green led on= random play on off= random play off

# GPIO Pins for bit banged AD Converter (from Adafruit example)
SPICLK = 4
SPIMISO = 17
SPIMOSI = 27
SPICS = 22



debug=0
FALSE=0
TRUE=1
exitapp = FALSE
sleep_ping=30
randomstate=0
waitwerbungfactor_dead=100
waitwerbungfactor_blues=15
waitwerbung=0

global TEST_MPD_HOST, TEST_MPD_PORT, TEST_MPD_PASSWORD
TEST_MPD_HOST     = "localhost"
TEST_MPD_PORT     = "6600"
TEST_MPD_PASSWORD = "volumio"   # password for Volumio / MPD


# ***** Function Parse commandline arguments ***********************
# get and parse commandline args

def arguments(argv):
    global  debug
    try:
        opts, args=getopt.getopt(argv,"dh")
    except getopt.GetoptError:
        print ("Parameter Error")
        sys.exit(2)
    for opt, arg in opts:
        if opt in ("-h", "--help"):
            print ("App mpd-client -----------------------------------")
            print ("usage: mpd-client [-s -h]")
            sys.exit(2)
        elif opt == '-d': 	debug = 1
	
# ***********************************************

#-----------------------------------------------------------  
# get next song to be played          
def get_nexid(mpd):
    global  debug

    status = mpd.status()
    for text in status:
            if text=="nextsongid":
                nexid=int(status.get(text))
                if debug: print "Next SongID: %d" % nexid 
    return(nexid)


#----------------------------------------------------------- 
# lower volume from current value to zero, returns current value           
def lower_volume(mpd):
    global  debug

    status = mpd.status()
    for text in status:
            if text=="volume":
                curvol=int(status.get(text))
                if debug: print "Current Volume: %d" % curvol 
    volume=curvol
    if debug: print "Decreasing Volume"
    while TRUE:
        volume=volume-10
        if volume<0: 
            volume=0
            mpd.setvol(volume)
            if debug: print "Volume ist NULL"
            break   
        mpd.setvol(volume) 
        time.sleep(1.5)
    
    return(curvol)
        


#-----------------------------------------------
def connect_mpd():
# Connect with MPD (music player daemon)
#------------------------------------------------
    global debug
    connected = False
    retry_count=3
    i=1
    while connected == False:
        connected = True
        try:
             client.connect(TEST_MPD_HOST, TEST_MPD_PORT)
        except SocketError as e:
             connected = False
        if connected == False:
                if debug: print "Couldn't connect. Retrying"
                i=i+1
                if i > retry_count:
                    return(9)
                time.sleep(3)
    if debug: print("Connected to MPD-Server")
    return(0)

#---------------------------------------------------------
# read SPI data from MCP3008 chip, 8 possible adc's (0 thru 7)
def readadc(adcnum, clockpin, mosipin, misopin, cspin):
        if ((adcnum > 7) or (adcnum < 0)):
                return -1
        GPIO.output(cspin, True)

        GPIO.output(clockpin, False)  # start clock low
        GPIO.output(cspin, False)     # bring CS low

        commandout = adcnum
        commandout |= 0x18  # start bit + single-ended bit
        commandout <<= 3    # we only need to send 5 bits here
        for i in range(5):
                if (commandout & 0x80):
                        GPIO.output(mosipin, True)
                else:
                        GPIO.output(mosipin, False)
                commandout <<= 1
                GPIO.output(clockpin, True)
                GPIO.output(clockpin, False)

        adcout = 0
        # read in one empty bit, one null bit and 10 ADC bits
        for i in range(12):
                GPIO.output(clockpin, True)
                GPIO.output(clockpin, False)
                adcout <<= 1
                if (GPIO.input(misopin)):
                        adcout |= 0x1

        GPIO.output(cspin, True)
        
        adcout >>= 1       # first bit is 'null' so drop it
        return adcout


#-----------------------------------------------------------
def blink_led1():  # blink led coninuosly when program runs
    while not exitapp:
        for i in range(3):
            GPIO.output(led1, True)
            time.sleep(0.2)
            GPIO.output(led1, False)
            time.sleep(0.8)
    GPIO.output(led1, False)

#-----------------------------------------------------------
def blink_led2(anzahl,laenge):  # Visual feedback if button pressed and connected
    for i in range(anzahl):
        GPIO.output(led2, True)
        time.sleep(laenge)
        GPIO.output(led2, False)
        time.sleep(0.1)


#-----------------------------------------------------------
def my_callback_nx(channel):
    if debug: print "Pin Falling: %d" % channel
    time.sleep(.2)  # confirm the movement by waiting 1 sec 
    if not GPIO.input(buttonPinNext): # and check again the input
        if debug: print("ok, pin ist tief!")
        ret=client.next()
        blink_led2(2,0.1)
        if debug: print ret

#-----------------------------------------------------------
def my_callback_pr(channel):
    if debug: print "Pin Falling: %d" % channel
    time.sleep(.2)  # confirm the movement by waiting 1 sec 
    if not GPIO.input(buttonPinPrev): # and check again the input
        if debug: print("ok, pin ist tief!")
        client.previous()
        blink_led2(2,0.1)

#-----------------------------------------------------------        
def my_callback_start(channel):
    if debug: print "Pin Falling: %d" % channel
    time.sleep(.2)  # confirm the movement by waiting 1 sec 
    if not GPIO.input(buttonPinStart): # and check again the input
        if debug: print("ok, pin ist tief!")
        client.play(0)
        blink_led2(2,0.1)

#-----------------------------------------------------------
def my_callback_rd(channel):
    global randomstate
    if debug: print "Pin Falling: %d" % channel
    time.sleep(.2)  # confirm the movement by waiting 1 sec 
    if not GPIO.input(buttonPinRandom): # and check again the input
        if debug: print("ok, pin ist tief!")
        if randomstate:
            GPIO.output(led3, False)
            client.random(0)
            randomstate=0
        else:
            GPIO.output(led3, True)
            client.random(1)
            randomstate=1
        
        blink_led2(2,0.1)


#-----------------------------------------------------------            
def connection_status():
#    pings server every 60 seconds and prints "pinging" (if debug is specified).
    global sleep_ping, exitapp
    while not exitapp:  # main thread gives terminate signal here
        if debug: print "Connection: pinging the server"
        client.ping()
        wait=sleep_ping
        while wait > 0:
            time.sleep(3)
            wait=wait-3
            if debug: print "Connection: Waiting 3 seconds"
            if exitapp: break

    client.close()      # we need to terminate
    if debug: print "-->Thread Connection terminating..."
    sys.exit(0)

#-----------------------------------------------------------    
def button_nx():
    global exitapp
    GPIO.add_event_detect(buttonPinNext, GPIO.FALLING, callback=my_callback_nx, bouncetime=300)
#
    while not exitapp:
        time.sleep(1)
        pass    # pass ist leer statement
        time.sleep(1)
    if debug: print "-->Thread NEXT terminating..."
    sys.exit(0)

#-----------------------------------------------------------
def button_pr():
    global exitapp
    GPIO.add_event_detect(buttonPinPrev, GPIO.FALLING, callback=my_callback_pr, bouncetime=300)
# 
    while not exitapp:   # main thread gives terminate signal here
        time.sleep(1)
        pass    # pass ist leer statement
        time.sleep(1)
    if debug: print "-->Thread PREVIOUS terminating..."
    sys.exit(0)

#-----------------------------------------------------------    
def button_st():
    global exitapp
    GPIO.add_event_detect(buttonPinStart, GPIO.FALLING, callback=my_callback_start, bouncetime=300)
#
    while not exitapp:   # main thread gives terminate signal here
        time.sleep(1)
        pass    # pass ist leer statement
        time.sleep(1)
    if debug: print "-->Thread START PL terminating..."        
    sys.exit(0)

#-----------------------------------------------------------    
def button_rd():
    global exitapp
    GPIO.add_event_detect(buttonPinRandom, GPIO.FALLING, callback=my_callback_rd, bouncetime=300)
#
    while not exitapp:   # main thread gives terminate signal here
        time.sleep(1)
        pass    # pass ist leer statement
        time.sleep(1)
    if debug: print "-->Thread RANDOM terminating..."        
    sys.exit(0)


#-----------------------------------------------------------------
# function (thread) to read pot and set volumne
def read_pot():
    global exitapp, debug
# 10k trim pot connected to adc #0
    potentiometer_adc = 0;

    last_read = 0       # this keeps track of the last potentiometer value
    tolerance = 10       # to keep from being jittery we'll only change
                    # volume when the pot has moved more than 5 'counts'

    while not exitapp:  # loop til main threads signals termination
        # we'll assume that the pot didn't move
        trim_pot_changed = False

        # read the analog pin
        trim_pot = readadc(potentiometer_adc, SPICLK, SPIMOSI, SPIMISO, SPICS)
        # how much has it changed since the last read?
        pot_adjust = abs(trim_pot - last_read)


        if ( pot_adjust > tolerance ):
               trim_pot_changed = True
           

        if ( trim_pot_changed ):
                if debug:   
                    print "Pot changed more than tolerance %d", tolerance
                    print "Pot before:", trim_pot
                    print "Pot has changed by:", (trim_pot - last_read)
                    print "Pot last_read", last_read
                set_volume = trim_pot / 10.24           # convert 10bit adc0 (0-1024) trim pot read into 0-100 volume level
                set_volume = round(set_volume)          # round out decimal value
                set_volume = int(set_volume)            # cast volume as integer

                if debug: print 'Volume new = {volume}%' .format(volume = set_volume)
 #               set_vol_cmd = 'sudo amixer cset numid=1 -- {volume}% > /dev/null' .format(volume = set_volume)
 #               os.system(set_vol_cmd)  # set volume
                client.setvol(set_volume)
    

                # save the potentiometer reading for the next loop
                last_read = trim_pot

        # hang out and do nothing for a half second
        time.sleep(0.5)
        
        
# ------------------------------------------------------
# waits randoms seconds and plays werbung
# decreases volume , adds werbung to current playlist, plays werbung, deletes werbung from playlist
# resumes play at next song
def werbung():
    global exitapp, waitwerbung

    while not exitapp:   # main thread gives terminate signal here
        wait=random.randint(5, 15)  
        if debug: 
            wait=wait*15
        else:
            wait=wait*waitwerbung
        if debug: print "Werbung: Going to wait for %d seconds" % wait
        while wait > 0:
            time.sleep(3)
            wait=wait-3
            if debug: print "Werbung: Waiting another %d seconds" % wait
            if exitapp: break
#        ret=connect_mpd(client)
#        if debug: print "Werbung Return from Connect MPD: %d" % ret
        if exitapp: break
        nxid=get_nexid(client)                  # nächstes stück der Playlist holen (ID), wird nach Werbung gespielt
        ident=client.addid("werbung_1.mp3")     # werbung.mp3 zur aktuellen playlist addieren und ID merken
        if debug: print "Werbung ID: %s" % ident
        cur_vol=lower_volume(client)            # Volume vermindern auf Null, aktuellen Wert vorher speichern      
        client.setvol(cur_vol)                  # Volume wieder erstellen
        if debug: print "Werbung: Volume reset to %d" % cur_vol
        client.playid(int(ident))               # Werbung spielen
        time.sleep(9)                           # warten bis gespielt
        client.playid(nxid)                     # vorher gespeichtertes nächstes Stück spielen
        client.deleteid(int(ident))             # Werbung mp3 entfernen aus der Playlist
        time.sleep(5)
#        client.disconnect()
#        if debug: print " Disconnected from MPD"
    if debug: print "-->Thread Werbung terminating..."
    sys.exit(0)


#----------------------------------------------------------
def termplay():    # function not used here
    volume=60
    for i in range(15):
        volume=volume-15
        GPIO.output(led2, True)
        time.sleep(0.3)
        GPIO.output(led2, False)
        time.sleep(3)
        print "Set Volume to %d" % volume
        client.setvol(volume)
        time.sleep(3)

#-----------------------------------------------------------
# --------- MAIN --------

arguments(sys.argv[1:])  # get commandline arguments

#GPIO.cleanup(buttonPinNext)  # cleanup GPIO Pins
#GPIO.cleanup(buttonPinPrev)  # cleanup GPIO Pins
#GPIO.cleanup(buttonPinStart)  # cleanup GPIO Pins

GPIO.setwarnings(False)
GPIO.setup(led1, GPIO.OUT, initial=GPIO.LOW)
GPIO.setup(led2, GPIO.OUT, initial=GPIO.LOW)
GPIO.setup(led3, GPIO.OUT, initial=GPIO.LOW)

GPIO.setup(buttonPinNext, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(buttonPinPrev, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(buttonPinStart, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(buttonPinRandom, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(potschalter, GPIO.IN, pull_up_down=GPIO.PUD_UP)

#------------------------------------------------
# set up the SPI interface pins (ADConverter)
GPIO.setup(SPIMOSI, GPIO.OUT)
GPIO.setup(SPIMISO, GPIO.IN)
GPIO.setup(SPICLK, GPIO.OUT)
GPIO.setup(SPICS, GPIO.OUT)


time.sleep(1)
# setup mpd Client Object
client = mpd.MPDClient()

ret=connect_mpd()                    # connect to MPD server
if ret==9:
    if debug: print "Could not connect to MPD"
    sys.exit(2)


blink_led2(2,0.5)
# reset random play
client.random(0)
# start play with volume 60%
client.setvol(60)
# clear current playlist
client.clear()
if debug:  print "Playlist cleared"
if GPIO.input(potschalter):     # Schalter ist off (ganz links gedreht)
# start playing using playlist Blues-1
    client.load("Blues-1")
    waitwerbung=waitwerbungfactor_blues
    if debug: print "Blues-1 loaded"
else:
# start playing using playlist Dead-1
    client.load("Dead-1")
    waitwerbung=waitwerbungfactor_dead
    if debug: print "Dead-1 loaded"
# start with first song in playlist
if debug: print "WaitFactor: %d" % waitwerbung
client.play(0)


if debug: print "MPD-Version: %s" % client.mpd_version

# create and Start Threads
connect_thread = Thread(target = connection_status)
button_nx_thread = Thread(target = button_nx)
button_pr_thread = Thread(target = button_pr)
button_st_thread = Thread(target = button_st)
button_rd_thread = Thread(target = button_rd)
werbung_thread = Thread(target = werbung)
led1_thread = Thread(target = blink_led1)
volume_thread = Thread(target = read_pot)


connect_thread.start()          # thread to keep connection to mpd
button_nx_thread.start()        # thread to watch for NEXT button
button_pr_thread.start()        # thread to watch for PREVIOUS button
button_st_thread.start()        # thread to watch for START Playlist button
button_rd_thread.start()        # thread to watch for RANDOM PLAY button
werbung_thread.start()          # thread to play werbung at random intervalls
led1_thread.start()             # thread to blink green led
volume_thread.start()           # thread to read pot and set volume

# Main thread goes into loop (wait for ctrl-C)
# ctrl-C bloss für Tests im Vorground !! 
# posit
try:
    while True:
        time.sleep(3)
        if debug: print "Main thread waiting"
        pass    # pass ist leer statement
        
# somebody wants us to stop doing what we are doing...        
except KeyboardInterrupt:
    # cleanup
    blink_led2(5,0.1)
    exitapp = TRUE      # signal exit to the other threads, they will terminate themselfs
    if debug: print "Main: exitapp Signaled"
    raise
    if debug: print "Main: Terminating, waiting 6 seconds"
    GPIO.cleanup(buttonPinNext)  # cleanup GPIO Pins
    GPIO.cleanup(buttonPinPrev)  # cleanup GPIO Pins
    GPIO.cleanup(buttonPinStart)  # cleanup GPIO Pins
    GPIO.output(led3, False)
    GPIO.cleanup(led1)  # cleanup GPIO Pins
    GPIO.cleanup(led2)  # cleanup GPIO Pins
    GPIO.cleanup(led3)  # cleanup GPIO Pins
    GPIO.cleanup(SPIMOSI)
    GPIO.cleanup(SPIMISO)
    GPIO.cleanup(SPICLK)
    GPIO.cleanup(SPICS)
    
    time.sleep(6)       # wait for other threads
    client.disconnect()

    sys.exit(0)

#-----------------------------------------------------------
# The End
#-----------------------------------------------------------

The script is normally started in /etc/rc.local but for testing purposes I run it in a terminal window on my Mac. I use ctrl-C to terminate all threads. It accepts -d as commandline parm for debugging to stdout.
I also have a shutdown script that detects yet another button press from the shutdown button. I might combine these two scripts into one.

Hope this helps.

Greetings, Peter

Sorry, I could not figure out how to add a picture to my post. Help welcome.

Thanks, Peter

Peter,

You can add a picture with the button “Upload Attachment”

Attachement.png

After the upload you place the picture inline with the button [Place inline]

Attachemntinline.png

Succes!

Harry

Thanks Harry

I managed to include inline pics.

Greetings, Peter from Switzerland

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 )…