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
#31
(03-29-2019, 12:14 PM)Tim Curtis Wrote: The feature will be in RC1 which I hope to make available sometime this week :-)

That’s great!!!
Reply
#32
Dear Tim and Remy, I have added a rotaty encoder for volume control (based on hrvoje's algorithm, see link in code). And a way to add the current song to a favorites list (or a list of files to be deleted) by communicating with mpd directly.

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

#On playlist names no spaces
PLFAV = "Favoriten"                 # This is the playlist to which files are saved when pushing the button. /var/lib/mpd/playlists/Favoriten.m3u will be created if it does not exist yet.
PLDEF = "Aktuell"                   # This is the default playlist which is played when pushing the respective button (/var/lib/mpd/playlists/Aktuell.m3u needs to be generated e.g. by renaming an existing .m3u)
PLDLT = "Delete"                    # This is the delete list. /var/lib/mpd/playlists/Delete.m3u will be created if it does not exist.

#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
SW_PREV = 22                        # Previous
SW_NEXT = 4                         # Next
SW_FAV = 26                         # Add to favorites
SW_POWEROFF = 6                     # Shut down
SW_PLAY = 17                        # Toggle play/pause, e.g. button on the rotary encoder
SW_FW = 5                           # Go forward within current song
SW_DEF = 13                         # Play default playlist
SW_DLT = 25                         # adds the currently played song to the delete list (to be deleted semi-manually on the master repository - the Raspberry Pi accesses a copy on my NAS only)
RO_A = 24                           # Volume up
RO_B = 23                           # 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

#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_FAV, 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_FW, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(SW_DEF, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(SW_DLT, 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)

#Interrupt events
def eSW_PREV(channel):
   subprocess.call(['mpc', 'prev' ])
#   print str(datetime.datetime.now())[:19] + " previous"               # for testing only

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

def eSW_FAV(channel):
   NAMEN = subprocess.check_output("mpc -f %file% current", shell=True)[:-1]
   NAME = NAMEN.replace("\'","\\'\\'\'")                               # for the sigle quotes in echo
   PFAD = "echo 'playlistadd " + PLFAV + " \"" + NAME + "\"' | netcat -q 0 localhost 6600"  # or "-w 1" instead of "-q 0" if not saving reliably?
   os.system(PFAD)
   print "Zu " + PLFAV + ": " + NAMEN

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

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

def eSW_FW(channel):
   subprocess.call(['mpc', 'seek', '+'+str(SPRING)+'%' ])
#   print str(datetime.datetime.now())[:19] + " forward"                # for testing only
       

def eSW_DEF(channel):
   subprocess.call(['mpc','clear' ])
   subprocess.call(['mpc','load',PLDEF ])
   subprocess.call(['mpc','play' ])
#   print str(datetime.datetime.now())[:19] + " default playlist"       # for testing only

def eSW_DLT(channel):
   NAMEN = subprocess.check_output("mpc -f %file% current", shell=True)[:-1]
   NAME = NAMEN.replace("\'","\\'\\'\'")                               # for the sigle quotes in echo
   PFAD = "echo 'playlistadd " + PLDLT + " \"" + NAME + "\"' | netcat -q 0 localhost 6600"  # or "-w 1" instead of "-q 0" if not saving reliably?
   os.system(PFAD)
   print "Zur Löschliste " + PLDLT + ": " + NAMEN

# 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(SW_PREV, GPIO.FALLING, callback = eSW_PREV, bouncetime = PRELL)
GPIO.add_event_detect(SW_NEXT, GPIO.FALLING, callback = eSW_NEXT, bouncetime = PRELL)
GPIO.add_event_detect(SW_FAV, GPIO.FALLING, callback = eSW_FAV, bouncetime = PRELLL)
GPIO.add_event_detect(SW_POWEROFF, GPIO.FALLING, callback = eSW_POWEROFF, bouncetime = PRELL)
GPIO.add_event_detect(SW_PLAY, GPIO.FALLING, callback = eSW_PLAY, bouncetime = PRELL)
GPIO.add_event_detect(SW_FW, GPIO.FALLING, callback = eSW_FW, bouncetime = PRELL)
GPIO.add_event_detect(SW_DEF, GPIO.FALLING, callback = eSW_DEF, bouncetime = PRELL)
GPIO.add_event_detect(SW_DLT, GPIO.FALLING, callback = eSW_DLT, bouncetime = PRELLL)
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(SW_PREV)) + " SW_PREV " + str(SW_PREV) + "   |    " +  \
   str(GPIO.input(SW_NEXT)) + " SW_NEXT " + str(SW_NEXT) + "   |    " +  \
   str(GPIO.input(SW_POWEROFF)) + " SW_POWEROFF " + str(SW_POWEROFF) + "   |    " +  \
   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
'''
Reply
#33
Hello!
For use one button power on/off this
[img][Image: 08e97fa6a57f097a6c6b697fd8908c71.png][/img]
Use pnp transistor
Reply
#34
Hello Tim,
I absolute like Moode audio !
And the GPIO Config screen is working for me close to perfection.
How can I config a Button to :
MPC clear MPC Load Playlist MPC play in one row ?

regards
Guido
Raspi 3 B +
Iqaudio AMP pro
IQaudio cosmic controller with OLED Display and Rotary Encoder
All powered by Moode Audio 5.3  :heart:
Reply
#35
(05-20-2019, 11:27 AM)fedormil Wrote: Hello!
For use one button power on/off this
[img][Image: 08e97fa6a57f097a6c6b697fd8908c71.png][/img]
Use pnp transistor

Hi. You don't need to install a particular script for this to work?
Remy
Reply
#36
(07-09-2019, 07:07 AM)remy1961 Wrote:
(05-20-2019, 11:27 AM)fedormil Wrote: Hello!
For use one button power on/off this
[img][Image: 08e97fa6a57f097a6c6b697fd8908c71.png][/img]
Use pnp transistor

Hi. You don't need to install a particular script for this to work?
Remy

Hi, I use standart script for button, only just added 2 lines:

Code:
GPIO.setup(16, GPIO.OUT)
GPIO.output (16, GPIO.HIGH)

It uses the principle of blocking voltage. When the script is running, the transistor is closed, and the button starts the shutdown or reboot command. When MK is turned off, the script stops and the transistor opens. When you press a button, the ground closes on contact P6, and the raspberry wakes up.
Pins can be used any.)
Reply
#37
(07-14-2019, 07:29 PM)fedormil Wrote:
(07-09-2019, 07:07 AM)remy1961 Wrote:
(05-20-2019, 11:27 AM)fedormil Wrote: Hello!
For use one button power on/off this
[img][Image: 08e97fa6a57f097a6c6b697fd8908c71.png][/img]
Use pnp transistor

Hi. You don't need to install a particular script for this to work?
Remy

Hi, I use standart script for button, only just added 2 lines:

Code:
GPIO.setup(16, GPIO.OUT)
GPIO.output (16, GPIO.HIGH)

It uses the principle of blocking voltage. When the script is running, the transistor is closed, and the button starts the shutdown or reboot command. When MK is turned off, the script stops and the transistor opens. When you press a button, the ground closes on contact P6, and the raspberry wakes up.
Pins can be used any.)
Thanx. Remy.
Reply
#38
hello,
Sorry to bother you, but I have the same problem as gschmitz .
When I use "load playlist" fonction in the gpio handler config, the playlist load after.
I used gpio buttons before it was build in, and the load fonction used to clear load and play.
I tried few method like put a one line command in the config but nothing happened( it worked in SSH )
Do anyone have an idea?
I hope I have been understandable.
Thanks
Reply
#39
Hi,

Multiple commands have to be placed in a script file. You would enter the script file path as the CMD in GPIO button config.

Example:

1. Create the script file

Code:
pi@rp3:~ $ sudo nano test.sh

pi@rp3:~ $ cat test.sh
#!/bin/bash
mpc stop && mpc play 5

pi@rp3:~ $ sudo chmod +x test.sh

2. In GPIO button config set CMD = /home/pi/test.sh

-Tim
Enjoy the Music!
moodeaudio.org | Mastodon Feed | GitHub
Reply
#40
Hello,

with the help of Cyanoazemins' script I added two rotary encoders to my Raspberry (volume, loading a certain playlist and navigate through it).
As I am also running an OLED display via I2C it would be really great to choose a certain folder/file to play and use it as a stand-alone device without using the webinterface. Is there any chance to do so?

Bernd
Reply


Forum Jump: