Thank you for your donation!


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


Instruction Guide Use hardware momentary switches to control moOde
#86
Sorry for the noob question, but I'm hapless with code. I'm trying to make a super-simple radio for my mother-in-law that has two dials -- volume, and track change (I'd rather it be playlist change, but I'll take what I can get). I have the rotary encoders wired up, and I borrowed Cyanoazemins' script and edited it, which is I'm sure where my problems start. Instead of having one rotary encoder that does volume, one that changes track, and the pushbutton switch toggling pause/play on both, I have one rotary encoder that mutes the audio if I push the button.

Here's the code I came up with:

Code:
#!/usr/bin/python
#coding: utf8
# Script for mpc/mpd audio GPIO buttons partly based on remy1961's code on http://moodeaudio.org/forum/showthread.php?tid=198&pid=8382#pid8382
# Rotary encoder mostly based on hrvoje's code https://www.raspberrypi.org/forums/viewtopic.php?t=140250 . Comments on the reliability of RPi.GPIO library there
# mpd on default settings: localhost 6600
# Worked with one rotary encoder only (with two not reliably enough) in my case
# All buttons and rotary encoder connect to ground without hardware debouncing or hardware pull-up/-down. Rotary encoder bouncing is not improved with capacitors across A/B and ground.

import RPi.GPIO as GPIO             # pigpio library does NOT work, due to loud noise (louder than the music)
import threading                    # rotary interrupt
import time
import os
import subprocess
#import datetime                    # for testing only

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


#Define your GPIO pins (pin 20, 18, etc. not suitable in my case, i.e. not working or crashing), 7 buttons + 1 rotary encoder with button
RO_PREV = 27                        # Previous
RO_NEXT = 22                         # Next
SW_PLAY2 = 12                     # Toggle play/pause, e.g. button on the rotary encoder
RO_A = 6                           # Volume up
RO_B = 5                           # Volume down

PRELL = 500                         # debouncing for regular buttons
PRELLL = 1500                       # debouncing for "add to list" buttons
PRELLROT = 30                       # debouncing for rotary, favorable to diminish skipping. Higher value allows only slow volume increase
SCHRITT = 5                         # % change in Volume
SPRING = 10                         # % forward within current song
LockRotary = threading.Lock()        # create lock for rotary switch
Current_A = 0                        # Assume that rotary switch is not moving while we init software
Current_B = 0
Current_PREV = 0
Current_NEXT 0

#Code to manage BUTTONS
GPIO.setup(RO_PREV, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(RO_NEXT, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(SW_PLAY2, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(SW_PLAY, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(RO_A, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(RO_B, GPIO.IN, pull_up_down=GPIO.PUD_UP)

# Rotary encoder interrupt is called for both inputs from rotary switch (A and B)
def eRO(PREV_or_NEXT):
    global Current_PREV, Current_NEXT, LockRotary
  
    Switch_PREV = GPIO.input(RO_PREV)                                         # Read both of the switches
    Switch_NEXT = GPIO.input(RO_NEXT)
  
    if Current_PREV == Switch_PREV and Current_NEXT == Switch_NEXT:                    # Now check if state of A or B has changed. If not that means that bouncing caused it
        return                                                               # Same interrupt as before (Bouncing)? Ignore interrupt!

    Current_PREV = Switch_PREV                                                # remember new state
    Current_NEXT = Switch_NEXT                                                # for next bouncing check

    if (Switch_PREV == 0 and Switch_NEXT == 0):                                # Both one active? Yes -> end of sequence
        LockRotary.acquire()                                            # get lock
        if PREV_or_NEXT == RO_NEXT:                                                # Turning direction depends on which input gave last interrupt
                   subprocess.call(['mpc', 'next', '-'+str(SCHRITT) ])
        else:                                                            # so depending on direction either increase or decrease counter
                   subprocess.call(['mpc', 'prev', '-'+str(SCHRITT) ])
        LockRotary.release()                                            # and release lock
    return                                                                # done

def eSW_PLAY2(channel):
   subprocess.call(['mpc', 'toggle' ])
#   print str(datetime.datetime.now())[:19] + " play"                   # for testing only

def eSW_PLAY(channel):
   subprocess.call(['mpc', 'toggle' ])
#   print str(datetime.datetime.now())[:19] + " play"                   # for testing only


# Rotary encoder interrupt is called for both inputs from rotary switch (A and B)
def eRO(A_or_B):
    global Current_A, Current_B, LockRotary
  
    Switch_A = GPIO.input(RO_A)                                         # Read both of the switches
    Switch_B = GPIO.input(RO_B)
  
    if Current_A == Switch_A and Current_B == Switch_B:                    # Now check if state of A or B has changed. If not that means that bouncing caused it
        return                                                               # Same interrupt as before (Bouncing)? Ignore interrupt!

    Current_A = Switch_A                                                # remember new state
    Current_B = Switch_B                                                # for next bouncing check

    if (Switch_A == 0 and Switch_B == 0):                                # Both one active? Yes -> end of sequence
        LockRotary.acquire()                                            # get lock
        if A_or_B == RO_B:                                                # Turning direction depends on which input gave last interrupt
                   subprocess.call(['mpc', 'volume', '+'+str(SCHRITT) ])
        else:                                                            # so depending on direction either increase or decrease counter
                   subprocess.call(['mpc', 'volume', '-'+str(SCHRITT) ])
        LockRotary.release()                                            # and release lock
    return                                                                # done

# Declare interrupt events
GPIO.add_event_detect(RO_PREV, GPIO.FALLING, callback = eRO_PREV, bouncetime = PRELL)
GPIO.add_event_detect(RO_NEXT, GPIO.FALLING, callback = eRO_NEXT, bouncetime = PRELL)
GPIO.add_event_detect(SW_PLAY2, GPIO.FALLING, callback = eSW_POWEROFF, bouncetime = PRELL)
GPIO.add_event_detect(SW_PLAY, GPIO.FALLING, callback = eSW_PLAY, bouncetime = PRELL)
GPIO.add_event_detect(RO_A, GPIO.FALLING, callback=eRO, bouncetime = PRELLROT)
GPIO.add_event_detect(RO_B, GPIO.FALLING, callback=eRO, bouncetime = PRELLROT)

# Main
while True:
   time.sleep(1)
# the following is for testing pins. In my case e.g. pin 20 was low (0) all the time
'''
   print str(GPIO.input(RO_PREV)) + " RO_PREV " + str(RO_PREV) + "   |    " +  \
   str(GPIO.input(RO_NEXT)) + " RO_NEXT " + str(RO_NEXT) + "   |    " +  \
   str(GPIO.input(SW_PLAY2)) + " SW_PLAY2 " + str(SW_PLAY2) + "   |    " +  \
   str(GPIO.input(SW_PLAY)) + " SW_PLAY " + str(SW_PLAY) + "   |    " +  \
   str(GPIO.input(RO_A)) + " RO_A " + str(RO_A) + "   |    " +  \
   str(GPIO.input(RO_B)) + " RO_B " + str(RO_B) + "   |    " +  \       # for testing only
'''

I followed the directions in the first post on this thread for creating the buttons.py file and pointing rc.local to it, but...nope. No controls other than mute as long as I'm holding down the tuner dial's button.

Thanks for the help! (I don't know what 'reliably enough' might mean in that comment line which I didn't notice before now, so if that's my problem -- I guess I just need to lose the volume. Which is acceptable)

EDIT: So I got it. I commented out every line that didn't directly impact my situation, then I went to the config and told the GPIO configurator what the pins were supposed to do, said a short prayer to Baphomet, rebooted, and shazam.
Reply


Messages In This Thread
RE: Use hardware momentary switches to control moOde - by Geiiga - 08-10-2021, 01:52 PM

Forum Jump: