Skip to content

Commit

Permalink
Fix button function call (#2355)
Browse files Browse the repository at this point in the history
* fix: handle args for rotaryEncoder

don't pass args to callback if 'None'.
reorder args for callback to pass functionCallArgs first, if definied.
added functionCallArgs to rotaryEncoder definition, to support other functionCalls then volume.

* doc: update docs. removed duplicate / obsolete examples

Merged wiki page "Audio-RotaryKnobVolume"

* fix: fix tests

* Apply suggestions from code review

Co-authored-by: s-martin <[email protected]>

* Update codeblock type

Co-authored-by: s-martin <[email protected]>

---------

Co-authored-by: s-martin <[email protected]>
  • Loading branch information
AlvinSchiller and s-martin authored Apr 26, 2024
1 parent 4626e5d commit 8069179
Show file tree
Hide file tree
Showing 10 changed files with 148 additions and 134 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ Check out the following references.
* [PN532](components/rfid-reader/PN532/README.md)
* PC/SC
* also [multiple readers](https://github.com/MiczFlor/RPi-Jukebox-RFID/pull/1012#issue-434052529) simultaneously
* [**GPIO** control](components/gpio_control/README.md) for [buttons](https://github.com/MiczFlor/RPi-Jukebox-RFID/wiki/Using-GPIO-hardware-buttons), [knobs / dials](https://github.com/MiczFlor/RPi-Jukebox-RFID/wiki/Audio-RotaryKnobVolume) and much more to control your Phoniebox via GPIO.
* [**GPIO** control](components/gpio_control/README.md) for [buttons](https://github.com/MiczFlor/RPi-Jukebox-RFID/wiki/Using-GPIO-hardware-buttons) and much more to control your Phoniebox via GPIO.
* Control via smooth [**Web App**](https://github.com/MiczFlor/RPi-Jukebox-RFID/wiki/MANUAL#webapp) running on ajax from your phone, tablet or PC. You can play, upload, move files, assign new RFID cards, control playout, settings, etc.
* Support for files with embedded chapters metadata (like m4a)
* Customizable poweroff command
Expand Down
76 changes: 65 additions & 11 deletions components/gpio_control/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,20 +24,18 @@ Up to now the following input devices are implemented:
* **ShutdownButton**:
A specialized implementation for a shutdown button with integrated (but optional) LED support. It initializes a shutdown if the button is pressed more than `time_pressed` seconds and a (optional) LED on GPIO `led_pin` is flashing until that time is reached. For additional information, see [extended documentation below](#shutdownbutton).

* **RotaryEncoder**:
Control of a rotary encoder, for example KY040, see also in [Wiki](https://github.com/MiczFlor/RPi-Jukebox-RFID/wiki/Audio-RotaryKnobVolume).
It can be configured using `pinUp` and `PiNDown` (use GPIO numbers here), `functionCallUp`, `functionCallDown`, and `timeBase` see [extended documentation below](#rotaryencoder).

* **TwoButtonControl**:
This Device uses two Buttons and implements a third action if both buttons are pressed together. See [extended documentation below](#twobuttoncontrol).

* **RotaryEncoder**:
Control of a rotary encoder, for example KY040.
It can be configured using `Pin1` and `Pin2` (use GPIO numbers here), `functionCall1`, `functionCall2` see [extended documentation below](#rotaryencoder).

* **StatusLED**:
A LED which will light up once the Phoniebox has fully booted up and is ready to be used. For additional information, see [extended documentation below](#statusled).

Each section needs to be activated by setting `enabled: True`.

Many example files are located in `~/RPi-Jukebox-RFID/components/gpio_control/example_configs/`.

## Extended documentation

This section provides some extended documentation and guideline. Especially some exemplary configurations are introduced showing how these controls can be set up in the configuration file `~/RPi-Jukebox-RFID/settings/gpio_settings.ini`.
Expand Down Expand Up @@ -172,19 +170,75 @@ Furthermore, the following settings can be used as described for the [regular bu
A RotaryEncoder can be created using an `ini` entry like this:

```bash
[VolumeControl]
[RotaryVolumeControl]
enabled: True
Type: RotaryEncoder
Pin1: 7
Pin2: 8
timeBase: 0.02
Pin1: 22
Pin2: 23
timeBase: 0.1
functionCall1: functionCallVolU
functionCall2: functionCallVolD
```

Pin1 and FunctionCall1 correspond to rotary direction "up", while Pin2 and FunctionCall2 correspond to "down".
* **enabled**: This needs to be `True` for the rotary encoder to work.
* **Pin1**: GPIO number corresponding to rotary direction "clockwise" ('CLK')
* **Pin2**: GPIO number corresponding to rotary direction "counter clockwise" ('DT')
* **functionCall1**: function called for every rotation step corresponding to rotary direction "clockwise". See below for passed arguments. See [function documentation below](#functions).
* **functionCall2**: function called for every rotation step corresponding to rotary direction "counter clockwise". See below for passed arguments. See [function documentation below](#functions).
* **timeBase**: Factor used for calculating the rotation value base on rotation speed, defaults to `0.1`. Use `0` for deactivating rotation speed influence.
Example:
* a single rotation step leads to the value 1 passed to the function.
* steady rotation of two to or more steps, leads to the value 1 for the first call and the value 2 for all further calls.
* speeding up rotation of two to or more steps, leads to the value 1 for the first call, the value 2 for the second, the value 3 for the third and so on.
* **functionCall1Args**: Arguments for `functionCall1`, defaults to `None`. If defined takes precedence over rotation value. Arguments are ignored, if `functionCall1` does not take any.
* **functionCall2Args**: Arguments for `functionCall2`, defaults to `None`. If defined takes precedence over rotation value. Arguments are ignored, if `functionCall1` does not take any.

To also use the push button of the encoder just a button definition:
```bash
[Mute]
enabled: True
Type: Button
Pin: 27
functionCall: functionCallVol0
```

Note that the old configuration entries PinUp/PinDown and functionCallUp/functionCallDown are deprecated and might stop working in future.


```bash
[RotarySeekingControl]
enabled: True
Type: RotaryEncoder
Pin1: 22
Pin2: 23
timeBase: 0.1
functionCall1: functionCallPlayerSeekFwd
functionCall1Args: 5
functionCall2: functionCallPlayerSeekBack
functionCall2Args: 5
```

In this example, the encoder will be used to seek for- and backwards by 5 seconds on every rotation step. The rotation value will **NOT** be used in this case as the function args are defined!


#### Circuit diagram
```text
.---------------. .---------------.
| | | |
| CLK |----------------------| GPIO 22 |
| | | |
| DT |----------------------| GPIO 23 |
| | | |
| SW |----------------------| GPIO 27 |
| | | |
| + |----------------------| 3.3V |
| | | |
| GND |----------------------| GND |
| | | |
'---------------' '---------------'
KY-040 Raspberry
```

### StatusLED

A StatusLED can be created using an `ini` entry like this:
Expand Down

This file was deleted.

18 changes: 15 additions & 3 deletions components/gpio_control/example_configs/gpio_settings.ini
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,28 @@ antibouncehack: False

[VolumeControl]
enabled: False
Type: TwoButtonControl ;or RotaryEncoder
Type: TwoButtonControl
Pin1: 5
Pin2: 6
pull_up_down: pull_up
hold_time: 0.3
hold_mode: Repeat
timeBase: 0.1 ;only for RotaryEncoder
functionCall1: functionCallVolU
functionCall2: functionCallVolD
functionCallTwoButtons: functionCallVol0 ;only for TwoButtonControl
functionCallTwoButtons: functionCallVol0
;functionCall1Args: 1
;functionCall2Args: 1
;functionCallTwoButtonsArgs: x

[RotaryVolumeControl]
enabled: False
Type: RotaryEncoder
Pin1: 22
Pin2: 23
timeBase: 0.1
functionCall1: functionCallVolU
functionCall2: functionCallVolD

[PrevNextControl]
enabled: False
Type: TwoButtonControl
Expand Down Expand Up @@ -143,3 +151,7 @@ pull_up_down: pull_up
functionCall: functionCallTriggerPlayFolder
functionCallArgs: someRelativeFolderName

[StatusLED]
enabled: False
Type: StatusLED
Pin: 14

This file was deleted.

This file was deleted.

18 changes: 9 additions & 9 deletions components/gpio_control/function_calls.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,15 @@ def __init__(self):
def functionCallShutdown(self, *args):
function_call("{command} -c=shutdown".format(command=self.playout_control), shell=True)

def functionCallVolU(self, steps=None):
def functionCallVolU(self, steps=None, *args):
if steps is None:
function_call("{command} -c=volumeup".format(command=self.playout_control), shell=True)
else:
function_call("{command} -c=volumeup -v={value}".format(value=steps,
command=self.playout_control),
shell=True)

def functionCallVolD(self, steps=None):
def functionCallVolD(self, steps=None, *args):
if steps is None:
function_call("{command} -c=volumedown".format(command=self.playout_control), shell=True)
else:
Expand Down Expand Up @@ -65,22 +65,22 @@ def functionCallPlayerStop(self, *args):
function_call("{command} -c=playerstop".format(command=self.playout_control),
shell=True)

def functionCallPlayerSeekFwd(self, seconds=None):
def functionCallPlayerSeekFwd(self, seconds=None, *args):
if seconds is None:
seconds = 10
function_call("{command} -c=playerseek -v=+{value}".format(command=self.playout_control, value=seconds), shell=True)

def functionCallPlayerSeekBack(self, seconds=None):
def functionCallPlayerSeekBack(self, seconds=None, *args):
if seconds is None:
seconds = 10
function_call("{command} -c=playerseek -v=-{value}".format(command=self.playout_control, value=seconds), shell=True)

def functionCallPlayerSeekFarFwd(self, seconds=None):
def functionCallPlayerSeekFarFwd(self, seconds=None, *args):
if seconds is None:
seconds = 60
function_call("{command} -c=playerseek -v=+{value}".format(command=self.playout_control, value=seconds), shell=True)

def functionCallPlayerSeekFarBack(self, seconds=None):
def functionCallPlayerSeekFarBack(self, seconds=None, *args):
if seconds is None:
seconds = 60
function_call("{command} -c=playerseek -v=-{value}".format(command=self.playout_control, value=seconds), shell=True)
Expand All @@ -94,15 +94,15 @@ def functionCallPlayerRandomCard(self, *args):
def functionCallPlayerRandomFolder(self, *args):
function_call("{command} -c=randomfolder".format(command=self.playout_control), shell=True)

def functionCallBluetoothToggle(self, mode=None):
def functionCallBluetoothToggle(self, mode=None, *args):
if mode is None:
mode = 'toggle'
function_call("{command} -c=bluetoothtoggle -v={value}".format(command=self.playout_control, value=mode), shell=True)

def functionCallTriggerPlayCardId(self, cardid):
def functionCallTriggerPlayCardId(self, cardid, *args):
function_call("{command} --cardid={value}".format(command=self.rfid_trigger, value = cardid), shell=True)

def functionCallTriggerPlayFolder(self, folder):
def functionCallTriggerPlayFolder(self, folder, *args):
function_call("{command} --dir={value}".format(command=self.rfid_trigger, value = folder), shell=True)

def getFunctionCall(self, functionName):
Expand Down
9 changes: 6 additions & 3 deletions components/gpio_control/gpio_control.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,10 @@ def getFunctionCall(self, function_name, function_args):
try:
if function_name is not None and function_name != 'None':
functionCall = getattr(self.function_calls, function_name)
return (lambda *args: functionCall(*args, function_args))
if function_args is not None and function_args != 'None':
return (lambda *args: functionCall(function_args, *args))
else:
return (lambda *args: functionCall(*args))
except AttributeError:
self.logger.error('Could not find FunctionCall {function_name}'.format(function_name=function_name))
return lambda *args: None
Expand Down Expand Up @@ -77,8 +80,8 @@ def generate_device(self, config, deviceName):
elif device_type == 'RotaryEncoder':
return RotaryEncoder(config.getint('Pin1'),
config.getint('Pin2'),
self.getFunctionCall(config.get('functionCall1'), None),
self.getFunctionCall(config.get('functionCall2'), None),
self.getFunctionCall(config.get('functionCall1'), config.get('functionCall1Args', fallback=None)),
self.getFunctionCall(config.get('functionCall2'), config.get('functionCall2Args', fallback=None)),
config.getfloat('timeBase', fallback=0.1),
name=deviceName)
elif device_type == 'ShutdownButton':
Expand Down
Loading

0 comments on commit 8069179

Please sign in to comment.