RPi-Jukebox-RFID icon indicating copy to clipboard operation
RPi-Jukebox-RFID copied to clipboard

πŸš€ | Play when button is pressed and pause when button is released

Open jorgemiar opened this issue 4 years ago β€’ 3 comments

Similar to #1146, I'm trying to get a gpio button to play the music whilst it is pressed and pause the music when it is released.

So instead of using the functionCallPlayerPause function which toggles between play and pause I would like to use functionCallPlayerPlay whilst the button is pressed and functionCallPlayerPauseForce when the button is released.

Any tips on how I might do this?

I tried editing simple_button.py so that it triggers pause when the GPIO exits its looping state but it didn't work too well...

def holdAndRepeatHandler(self, *args):
       logger.info('{}: holdAndRepeatHandler'.format(self.name))
        # Rise volume as requested
        self.when_pressed(*args)
        # Detect holding of button
        while checkGpioStaysInState(self.hold_time, self.pin, GPIO.LOW):
            self.when_pressed(*args)
        **self.when_pressed(functionCallPlayerPauseForce)**
[Play]
enabled: True
Type: Button
Pin: 27
pull_up: True
hold_repeat = True
hold_time: 0.3
functionCall: functionCallPlayerPlay

Alternatively, I also tried duplicating the same button in gpio_settings.ini and added a different function depending on the edge parameter but it doesn't always work (don't know if it's actually doing what I want). I'm not sure if I'm confusing the software by duplicating the button. Whenever I do any changes I reset the gpio service to make sure they are applied.

[Play]
enabled: True
Type: Button
Pin: 27
pull_up: True
edge: falling
hold_repeat = False
hold_time: 0.3
functionCall: functionCallPlayerPlay

[Pause]
enabled: True
Type: Button
Pin: 27
edge: rising
hold_repeat = False
pull_up: True
hold_time: 0.3
functionCall: functionCallPlayerPauseForce

Lastly, when keeping the play button held down the music seems to be a bit choppy, I don't know if this is because of the hold_time causing small delays because the button is pressed down? I have set hold_repeat to false though and this issue happens.

Any help would be greatly appreciated thanks :)

jorgemiar avatar Feb 27 '21 19:02 jorgemiar

I tried creating a new GPIO Device called Long Button which is a modification of Simple Button but takes two actions and uses edge=BOTH but seems that the GPIO service doesn't work... There must be an error somewhere or I'm doing something wrong. Here are the changes I made:

Config file:

[Play]
enabled: True
Type:LongButton
Pin: 27
pull_up: True
hold_repeat: False
hold_time: 0.3
functionCallp: functionCallPlayerPlay
functionCallr: functionCallPlayerPauseForce

New file long_button.py, shown below are the changes vs simple_button.py. I basically tried to modify the callbackFunctionHandler so that it plays action 1 when the button is pressed and action 2 when the button is released but I don't know if I'm doing this right.

class LongButton:
    def __init__(self, pin, action=lambda *args: None,action2=lambda *args: None,  name=None, bouncetime=500, edge=GPIO.BOTH,
                 hold_time=.1, hold_repeat=False, pull_up_down=GPIO.PUD_UP):
        self.edge = parse_edge_key(edge)
        self.hold_time = hold_time
        self.hold_repeat = hold_repeat
        self.pull_up = True
        self.pull_up_down = parse_pull_up_down(pull_up_down)

        self.pin = pin
        self.name = name
        self.bouncetime = bouncetime
        GPIO.setup(self.pin, GPIO.IN, pull_up_down=self.pull_up_down)
        self._action = action
        self._action2 = action2
        GPIO.add_event_detect(self.pin, edge=self.edge, callback=self.callbackFunctionHandler,
                              bouncetime=self.bouncetime)

    def callbackFunctionHandler(self, *args):
        if (len(args) > 0 and args[0] == self.pin):
            logger.debug('args before: {}'.format(args))
            args = args[1:]
            logger.debug('args after: {}'.format(args))
        
        if GPIO.input(self.pin) == 0:
            return self.when_pressed(*args)
        if GPIO.input(self.pin) == 1:
            return self.when_released(*args)
        #if self.hold_repeat:
        #    return self.holdAndRepeatHandler(*args)
        #logger.info('{}: executre callback'.format(self.name))
        #return self.when_pressed(*args)

    @property
    def when_pressed(self):
        logger.info('{}: action'.format(self.name))
        return self._action

    @when_pressed.setter
    def when_pressed(self, func):
        logger.info('{}: set when_pressed')
        self._action = func

        GPIO.remove_event_detect(self.pin)
        self._action = func
        logger.info('add new action')
        GPIO.add_event_detect(self.pin, edge=self.edge, callback=self.callbackFunctionHandler, bouncetime=self.bouncetime)

    @property
    def when_released(self):
        return self._action2

    @when_released.setter
    def when_released(self, func):
        self._action2 = func

        GPIO.remove_event_detect(self.pin)
        self._action2 = func
        GPIO.add_event_detect(self.pin, edge=self.edge, callback=self.callbackFunctionHandler, bouncetime=self.bouncetime)

As well as adding this to gpio_control.py

    elif device_type == 'LongButton':
        return LongButton(config.getint('Pin'),
                            action=getFunctionCall(config.get('functionCallp')),
                            action2=getFunctionCall(config.get('functionCallr')),
                            name=deviceName,
                            bouncetime=config.getint('bouncetime', fallback=500),
                            edge=config.get('edge', fallback='BOTH'),
                            hold_repeat=config.getboolean('hold_repeat', False),
                            hold_time=config.getfloat('hold_time', fallback=0.3),
                            pull_up_down=config.get('pull_up_down', fallback=GPIO.PUD_UP))

and editing the init file in GPIODevices to include my long_button.py file:

from .rotary_encoder import RotaryEncoder
from .two_button_control import TwoButtonControl
from .shutdown_button import ShutdownButton
from .simple_button import SimpleButton
from .two_button_control import TwoButtonControl
from .VolumeControl import VolumeControl
from .long_button import LongButton
from .led import *

Any ideas what I might be doing wrong/what I should change?

jorgemiar avatar Feb 28 '21 20:02 jorgemiar

I managed to get the terminal to output the errors and it seems that most of the issues had to do with tabs vs spaces when writing the files πŸ€¦β€β™‚οΈ

It actually seems to work now!! The only thing is when releasing the button I sometimes get this warning in the terminal:

/bin/sleep: missing operand
Try '/bin/sleep --help' for more information.
Sports - Panama
[paused]  #6/117   0:11/3:18 (5%)

Is it anything to worry about?

I will clean up the files and link them here in case anyone else is interested.

jorgemiar avatar Feb 28 '21 21:02 jorgemiar

PR #1406 (not merged yet!) adds many functions to GPIO control, maybe it’s also useful for your use case.

s-martin avatar May 14 '21 07:05 s-martin