From ef130103cd1ccc80bd10d5aa4b110ebb75ab1457 Mon Sep 17 00:00:00 2001 From: Alvin Schiller <103769832+AlvinSchiller@users.noreply.github.com> Date: Fri, 26 Apr 2024 20:49:09 +0200 Subject: [PATCH 01/18] Bump version to 2.8.0-alpha --- settings/version-number | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/settings/version-number b/settings/version-number index 24ba9a38d..c338ba7ef 100644 --- a/settings/version-number +++ b/settings/version-number @@ -1 +1 @@ -2.7.0 +2.8.0-alpha From cffa96c86b73a0d5c119f8caf1f75262125cceba Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 2 May 2024 20:42:26 +0200 Subject: [PATCH 02/18] Bump docker/setup-buildx-action from 3.2.0 to 3.3.0 (#2362) Bumps [docker/setup-buildx-action](https://github.com/docker/setup-buildx-action) from 3.2.0 to 3.3.0. - [Release notes](https://github.com/docker/setup-buildx-action/releases) - [Commits](https://github.com/docker/setup-buildx-action/compare/v3.2.0...v3.3.0) --- updated-dependencies: - dependency-name: docker/setup-buildx-action dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/test_docker_debian_codename_sub.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test_docker_debian_codename_sub.yml b/.github/workflows/test_docker_debian_codename_sub.yml index 00ef4efd7..7aa1cd41e 100644 --- a/.github/workflows/test_docker_debian_codename_sub.yml +++ b/.github/workflows/test_docker_debian_codename_sub.yml @@ -58,7 +58,7 @@ jobs: uses: docker/setup-qemu-action@v3.0.0 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3.2.0 + uses: docker/setup-buildx-action@v3.3.0 with: # network=host driver-opt needed to push to local registry driver-opts: network=host @@ -155,7 +155,7 @@ jobs: uses: docker/setup-qemu-action@v3.0.0 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3.2.0 + uses: docker/setup-buildx-action@v3.3.0 - name: Artifact Download Docker Image uses: actions/download-artifact@v4 From f3b4b2065261b37cc14ecaf7dcf4304a68a15523 Mon Sep 17 00:00:00 2001 From: Alvin Schiller <103769832+AlvinSchiller@users.noreply.github.com> Date: Thu, 9 May 2024 00:20:30 +0200 Subject: [PATCH 03/18] Fix button SecondFunc trigger (#2367) * fix instant execution of main action on holding * simplify holdMode callback handling * Update test_SimpleButton.py * update docs * fix: only go into while loop if further held * docs: update comments * docs: add alert for behavior change * docs: fix typo --- .../gpio_control/GPIODevices/simple_button.py | 41 +++++++++++-------- components/gpio_control/README.md | 15 ++++--- .../gpio_control/test/test_SimpleButton.py | 4 +- 3 files changed, 34 insertions(+), 26 deletions(-) diff --git a/components/gpio_control/GPIODevices/simple_button.py b/components/gpio_control/GPIODevices/simple_button.py index a022a812f..920358acf 100644 --- a/components/gpio_control/GPIODevices/simple_button.py +++ b/components/gpio_control/GPIODevices/simple_button.py @@ -106,11 +106,7 @@ def callbackFunctionHandler(self, *args): if inval != GPIO.LOW: return None - if self.hold_mode in ('Repeat', 'Postpone', 'SecondFunc', 'SecondFuncRepeat'): - return self.longPressHandler(*args) - else: - logger.info('{}: execute callback'.format(self.name)) - return self.when_pressed(*args) + return self._handleCallbackFunction(*args) @property def when_pressed(self): @@ -136,36 +132,45 @@ def when_pressed(self, func): def set_callbackFunction(self, callbackFunction): self.when_pressed = callbackFunction - def longPressHandler(self, *args): - logger.info('{}: longPressHandler, mode: {}'.format(self.name, self.hold_mode)) - # instant action (except Postpone mode) - if self.hold_mode != "Postpone": - self.when_pressed(*args) + def _handleCallbackFunction(self, *args): + logger.info('{}: handleCallbackFunction, mode: {}'.format(self.name, self.hold_mode)) - # action(s) after hold_time if self.hold_mode == "Repeat": - # Repeated call of main action (multiple times if button is held long enough) + # Instantly call primary action + self.when_pressed(*args) + # Repeated call of primary action if button is held long enough while checkGpioStaysInState(self.hold_time, self.pin, GPIO.LOW): self.when_pressed(*args) elif self.hold_mode == "Postpone": - # Postponed call of main action (once) + # Postponed call of primary action (once) if checkGpioStaysInState(self.hold_time, self.pin, GPIO.LOW): self.when_pressed(*args) - while checkGpioStaysInState(self.hold_time, self.pin, GPIO.LOW): - pass + while checkGpioStaysInState(self.hold_time, self.pin, GPIO.LOW): + pass elif self.hold_mode == "SecondFunc": # Call of secondary action (once) + # execute primary action if not held past hold_time if checkGpioStaysInState(self.hold_time, self.pin, GPIO.LOW): self.when_held(*args) - while checkGpioStaysInState(self.hold_time, self.pin, GPIO.LOW): - pass + while checkGpioStaysInState(self.hold_time, self.pin, GPIO.LOW): + pass + else: + self.when_pressed(*args) elif self.hold_mode == "SecondFuncRepeat": # Repeated call of secondary action (multiple times if button is held long enough) - while checkGpioStaysInState(self.hold_time, self.pin, GPIO.LOW): + # execute primary action if not held past hold_time + if checkGpioStaysInState(self.hold_time, self.pin, GPIO.LOW): self.when_held(*args) + while checkGpioStaysInState(self.hold_time, self.pin, GPIO.LOW): + self.when_held(*args) + else: + self.when_pressed(*args) + + else: + self.when_pressed(*args) def __del__(self): logger.debug('remove event detection') diff --git a/components/gpio_control/README.md b/components/gpio_control/README.md index bae060400..3b53d26d0 100644 --- a/components/gpio_control/README.md +++ b/components/gpio_control/README.md @@ -59,15 +59,18 @@ functionCall: functionCallPlayerPause However, a button has more parameters than these. In the following comprehensive list you can also find the default values which are used automatically if you leave out these settings: * **functionCallArgs**: Arguments for primary function, defaults to `None`. Arguments are ignored, if `functionCall` does not take any. + +> [!IMPORTANT] +> Since v2.8.0 the behavior of `hold_mode` `SecondFunc` and `SecondFuncRepeat` has changed. The secondary function is no longer triggered additionally to the primary function. +> Now its called exclusively if `hold_time` is reached. The primary function will only be triggered if the button is pressed shorter then `hold_time`! +> Existing configurations may need to adapt to this. * **hold_mode**: Specifies what shall happen if the button is held pressed for longer than `hold_time`: * `None` (Default): Nothing special will happen. - * `Repeat`: The configured `functionCall` is repeated after each `hold_time` interval. + * `Repeat`: The configured `functionCall` is instantly called and repeatedly after each `hold_time` interval. * `Postpone`: The function will not be called before `hold_time`, i.e. the button needs to be pressed this long to activate the function - * `SecondFunc`: Holding the button for at least `hold_time` will additionally execute the function `functionCall2` with `functionCall2Args`. + * `SecondFunc`: Pressing the button (shorter than `hold_time`) will execute the function `functionCall` with `functionCallArgs`. Holding the button for at least `hold_time` will execute the function `functionCall2` with `functionCall2Args`. * `SecondFuncRepeat`: Like SecondFunc, but `functionCall2` is repeated after each `hold_time` interval. - In every `hold_mode` except `Postpone`, the main action `functionCall` gets executed instantly. - Holding the button even longer than `hold_time` will cause no further action unless you are in the `Repeat` or `SecondFuncRepeat` mode. * **hold_time**: Reference time for this buttons `hold_mode` feature in seconds. Default is `0.3`. This setting is ignored if `hold_mode` is unset or `None` @@ -79,10 +82,10 @@ However, a button has more parameters than these. In the following comprehensive * `pull_off`. Use this to deactivate internal pull-up/pulldown resistors. This is useful if your wiring includes your own (external) pull up / down resistors. * **edge**: Configures the events in which the GPIO library shall trigger the callback function. Valid settings: * `falling` (Default). Triggers if the GPIO voltage goes down. - * `rising`. Trigegrs only if the GPIO voltage goes up. + * `rising`. Triggers only if the GPIO voltage goes up. * `both`. Triggers in both cases. * **bouncetime**: This is a setting of the GPIO library to limit bouncing effects during button usage. Default is `500` ms. -* **antibouncehack**: Despite the integrated bounce reduction of the GPIO library some users may notice false triggers of their buttons (e.g. unrequested / double actions when releasing the button). If you encounter such problems, try setting this setting to `True` to activate an additional countermeasure. +* **antibouncehack**: Despite the integrated bounce reduction of the GPIO library some users may notice false triggers of their buttons (e.g. unrequested / double actions when releasing the button). If you encounter such problems, try setting this to `True` to activate an additional countermeasure. Note: If you prefer, you may also use `Type: SimpleButton` instead of `Type: Button` - this makes no difference. diff --git a/components/gpio_control/test/test_SimpleButton.py b/components/gpio_control/test/test_SimpleButton.py index d6f03acd3..b0b933e09 100644 --- a/components/gpio_control/test/test_SimpleButton.py +++ b/components/gpio_control/test/test_SimpleButton.py @@ -150,7 +150,7 @@ def test_hold_SecondFunc_longer_holdtime(self, simple_button): simple_button.hold_mode = 'SecondFunc' calls = mockedSecAction.call_count simple_button.callbackFunctionHandler(simple_button.pin) - mockedAction.assert_called_once() + mockedAction.assert_not_called() assert mockedSecAction.call_count - calls == 1 def test_hold_SecondFunc_shorter_holdtime(self, simple_button): @@ -170,7 +170,7 @@ def test_hold_SecondFuncRepeat_longer_holdtime(self, simple_button): simple_button.hold_mode = 'SecondFuncRepeat' calls = mockedSecAction.call_count simple_button.callbackFunctionHandler(simple_button.pin) - mockedAction.assert_called_once() + mockedAction.assert_not_called() assert mockedSecAction.call_count - calls == 3 def test_hold_SecondFuncRepeat_shorter_holdtime(self, simple_button): From a889ba7e8156306bd574c5330c65611fa9e6c9ba Mon Sep 17 00:00:00 2001 From: s-martin Date: Sun, 12 May 2024 09:18:54 +0200 Subject: [PATCH 04/18] Add markdownlint config and action for V2 (#2369) * fix markdown errors * add markdownlint action and config * fix action * rename config file * fix ignore paths * fix warnings * disable MD033 and MD045 locally --- .github/workflows/markdown.yml | 29 ++++++++++ .markdownlint-cli2.yaml | 56 +++++++++++++++++++ README.md | 7 ++- ci/README.md | 33 +++++++---- .../buttons-bluetooth-headphone/README.md | 18 +++--- components/gpio_control/README.md | 32 ++++++----- .../synchronisation/sync-shared/README.md | 4 +- scripts/helperscripts/README.md | 24 ++++---- 8 files changed, 154 insertions(+), 49 deletions(-) create mode 100644 .github/workflows/markdown.yml create mode 100644 .markdownlint-cli2.yaml diff --git a/.github/workflows/markdown.yml b/.github/workflows/markdown.yml new file mode 100644 index 000000000..fa251ed9f --- /dev/null +++ b/.github/workflows/markdown.yml @@ -0,0 +1,29 @@ +name: Markdown Linting + +on: + push: + branches-ignore: + - 'future3/**' + paths: + - '**.md' + pull_request: + branches: + - develop + - master + paths: + - '**.md' + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Linting markdown + uses: DavidAnson/markdownlint-cli2-action@v15 + with: + config: .markdownlint-cli2.yaml + #continue-on-error: true diff --git a/.markdownlint-cli2.yaml b/.markdownlint-cli2.yaml new file mode 100644 index 000000000..4e30f537c --- /dev/null +++ b/.markdownlint-cli2.yaml @@ -0,0 +1,56 @@ +# +# markdownlint-cli2 configuration, see https://github.com/DavidAnson/markdownlint-cli2?tab=readme-ov-file#configuration +# + +# rules, see https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md +config: + line-length: false + # ignore dollar signs + commands-show-output: false + no-trailing-punctuation: false + no-duplicate-heading: + siblings_only: true + # allow some tags we use for formatting + no-inline-html: + allowed_elements: [ "details", "summary" ] + +# Include a custom rule package +#customRules: +# - markdownlint-rule-titlecase + +# Fix no fixable errors +fix: false + +# Define a custom front matter pattern +#frontMatter: "[^]*<\/head>" + +# Define glob expressions to use (only valid at root) +globs: + - "**.md" + +# Define glob expressions to ignore +ignores: + - "htdocs/**" + +# Use a plugin to recognize math +#markdownItPlugins: +# - +# - "@iktakahiro/markdown-it-katex" + +# Additional paths to resolve module locations from +#modulePaths: +# - "./modules" + +# Enable inline config comments +noInlineConfig: false + +# Disable progress on stdout (only valid at root) +noProgress: true + +# Use a specific formatter (only valid at root) +#outputFormatters: +# - +# - markdownlint-cli2-formatter-default + +# Show found files on stdout (only valid at root) +showFound: true \ No newline at end of file diff --git a/README.md b/README.md index ebaada654..0398ff707 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ Phoniebox is a contactless jukebox for the Raspberry Pi, playing audio files, pl Another bunch of wonderful designs! -To share your design or see all previous calendars and designs of the community visit the [Phoniebox Gallery](https://github.com/MiczFlor/RPi-Jukebox-RFID/wiki/GALLERY). +To share your design or see all previous calendars and designs of the community visit the [Phoniebox Gallery](https://github.com/MiczFlor/RPi-Jukebox-RFID/wiki/GALLERY). ![The Phoniebox Calendar](https://raw.githubusercontent.com/wiki/MiczFlor/RPi-Jukebox-RFID/img/gallery/calendar/latest-Phoniebox-Calendar.jpg "The Phoniebox Calendar") @@ -189,6 +189,8 @@ These are links to additional items, which will add an individual flavour to you Special hardware is now organised in the folder [`components`](components/). If you have new hardware attached to your Phoniebox, please add to this library! It currently contains soundcards, displays, GPIO controls, RFID reader, smarthome integration. ## Support Phoniebox + + @@ -211,6 +213,8 @@ See the Phoniebox code in action, watch this video and read the blog post from [ A new video screencast about + + **What makes this Phoniebox easy to install and use:** * Runs on all Raspberry Pi models (1, 2, 3 and 4) and [Raspberry Zero](https://github.com/MiczFlor/RPi-Jukebox-RFID/issues/15). @@ -243,7 +247,6 @@ See innovation, upcycling and creativity in the [Phoniebox Gallery](https://gith ![Caption](https://raw.githubusercontent.com/wiki/MiczFlor/RPi-Jukebox-RFID/img/gallery/KingKahn-20180101-Jukebox-01-h90.jpg) ![Caption](https://raw.githubusercontent.com/wiki/MiczFlor/RPi-Jukebox-RFID/img/gallery/hailogugo-20171222-h90-01.jpg) - ## Sustainability You might be surprised how easy and affordable you can get a RaspberryPi or an "appropriate" housing for your Phoniebox **second hand**. Think about the planet before you buy a new one. diff --git a/ci/README.md b/ci/README.md index 674dedd64..b522afb4f 100644 --- a/ci/README.md +++ b/ci/README.md @@ -11,35 +11,42 @@ This is a work in progress so expect things to fail or being flaky. * Flash its sd card with **Raspberry Pi OS lite** * use raspi-config to resize the filesystem to the whole sd card (menu: 7 -> A1) * install some tools and reboot: -```bash + + ```bash sudo apt-get update sudo apt-get -y dist-upgrade sudo apt-get -y install docker.io git sudo gpasswd -a pi docker sudo reboot -``` + ``` + * login to your RPi * clone the repo and cd into its local clone: -```bash + + ```bash cd /home/pi/ # optional: change to your fork appropriately git clone https://github.com/MiczFlor/RPi-Jukebox-RFID.git cd RPi-Jukebox-RFID/ # optional: switch to another branch git checkout -``` + ``` + * build the docker image: + ```bash docker build -t rpi-jukebox-rfid:debian-latest -f ci/Dockerfile.debian --platform=linux/arm/v7 --target=code . ``` - * additional arguments - * for builds - - on normal PCs use `--platform=linux/amd64` - - on a raspberry pi use `--platform=linux/arm/v7` - * to use a different debian version as base add parameter `--build-arg="DEBIAN_CODENAME="` ( = e.g. buster, bullseye, ...). + + * additional arguments + * for builds + * on normal PCs use `--platform=linux/amd64` + * on a raspberry pi use `--platform=linux/arm/v7` + * to use a different debian version as base add parameter `--build-arg="DEBIAN_CODENAME="` ( = e.g. buster, bullseye, ...). * get something to drink or eat * run the freshly built docker image and start testing. For example: + ```bash docker run --rm -ti rpi-jukebox-rfid:debian-latest /bin/bash cd /home/pi/ @@ -48,12 +55,14 @@ This is a work in progress so expect things to fail or being flaky. bash GIT_URL=https://github.com/MiczFlor/RPi-Jukebox-RFID.git GIT_BRANCH=main install-jukebox.sh ``` - NOTE: Get familiar with docker and its flags - `--rm` for example will remove the - container after you log out of it and all changes will be lost. + > [!NOTE] + > Get familiar with docker and its flags - `--rm` for + > example will remove the + > container after you log out of it and all changes will be lost. ### mount hosts code as volume -The created image now contains all the code in the directory `/code` - if you do not want to rebuild the image after each code-change you can 'mount' the RPi's code version into the container. +The created image now contains all the code in the directory `/code` - if you do not want to rebuild the image after each code-change you can 'mount' the RPi's code version into the container. Add `-w /code -v $PWD:/code` to the `docker run` parameter. In that way every change to the code in the container will be available on the RPi as well as vice versa. diff --git a/components/controls/buttons-bluetooth-headphone/README.md b/components/controls/buttons-bluetooth-headphone/README.md index 6cedd1207..c13e48f57 100644 --- a/components/controls/buttons-bluetooth-headphone/README.md +++ b/components/controls/buttons-bluetooth-headphone/README.md @@ -1,15 +1,15 @@ -## Control Phoniebox via Buttons from Bluetooth Headset +# Control Phoniebox via Buttons from Bluetooth Headset Many bluetooth headsets or bluetooth speaker sets have buttons for controlling the music stream. **Let's make use of them!** This component provides support for controlling your Phoniebox through these buttons on your bluetooth headset (or speaker set). -### Installation +## Installation 1. Make sure your bluetooth headset is connected to the Phoniebox. Follow the instructions in the [Wiki](https://github.com/MiczFlor/RPi-Jukebox-RFID/wiki/Connecting_Bluetooth_device_to_Phoniebox). 2. Execute `$ ./install-bt-buttons.sh. It will ask you to identify your headset and set up appropriate user rights, and registers the script as a service. It should work immediatly. In case of doubt, reboot. - If later changing the headset, re-run `$ ./register-device.py`. Reboot or restart the service with `sudo systemctl restart phoniebox-bt-buttons.service` -### Supported Buttons +## Supported Buttons Out-of-the box support is included for the following buttons @@ -21,7 +21,7 @@ Key codes are standarized and so it should also work with your headphones. If yo *Note:* Volume up/down is inherently supported by the bluetooth protocol. There is no need to handle these by this script. -### On Connect / On Disconnect +## On Connect / On Disconnect If the feature [bluetooth-sink-switch](../../bluetooth-sink-switch) is enabled, the script automatically switches the audio stream to headphones / regular speakers on bluetooth connect / disconnect respectivly. Playback state (play/pause) is retained. @@ -34,16 +34,16 @@ You can **customize** the behaviour by editing the functions where `mpd_support` indicates wether the bt-sink-switch-feature is enabled. -### Troubleshooting +## Troubleshooting This feature has been tested with PowerLocus Buddy and Sennheiser Momentum M2 AEBT headphones. -#### Preparation +### Preparation - Stop the service `$ sudo systemctl stop phoniebox-bt-buttons.service` - Start the script in a command line with debug option `$ ./bt-buttons.py debug` -#### Check that correct bluetooth device is found +### Check that correct bluetooth device is found - Run the [preparatory steps](#preparation) - Check headset is connected and listed as input event device with `$ cat /proc/bus/input/devices`. Note the device name. @@ -57,7 +57,7 @@ This feature has been tested with PowerLocus Buddy and Sennheiser Momentum M2 AE - If you see discrepancies, re-run `$ ./register-device.py`(see above) -#### Add key codes / change actions +### Add key codes / change actions - Run the [preparatory steps](#preparation) - Press the buttons on the headset and check for these debug outputs. Note down the keycode. The **163** is the keycode, you are looking for. Go through all the buttons. Also try short/long press. On my headphones, they result in different keycodes @@ -78,7 +78,7 @@ This feature has been tested with PowerLocus Buddy and Sennheiser Momentum M2 AE ~~~ -#### Still having trouble? +### Still having trouble? Check the basics: test the event input. Make sure the headphones are connected beforehand. Replace event*X* with the event number obtained from `$ cat /proc/bus/input/devices`. diff --git a/components/gpio_control/README.md b/components/gpio_control/README.md index 3b53d26d0..986526092 100644 --- a/components/gpio_control/README.md +++ b/components/gpio_control/README.md @@ -62,8 +62,9 @@ However, a button has more parameters than these. In the following comprehensive > [!IMPORTANT] > Since v2.8.0 the behavior of `hold_mode` `SecondFunc` and `SecondFuncRepeat` has changed. The secondary function is no longer triggered additionally to the primary function. -> Now its called exclusively if `hold_time` is reached. The primary function will only be triggered if the button is pressed shorter then `hold_time`! +> Now its called exclusively if `hold_time` is reached. The primary function will only be triggered if the button is pressed shorter then `hold_time`! > Existing configurations may need to adapt to this. + * **hold_mode**: Specifies what shall happen if the button is held pressed for longer than `hold_time`: * `None` (Default): Nothing special will happen. * `Repeat`: The configured `functionCall` is instantly called and repeatedly after each `hold_time` interval. @@ -87,7 +88,8 @@ However, a button has more parameters than these. In the following comprehensive * **bouncetime**: This is a setting of the GPIO library to limit bouncing effects during button usage. Default is `500` ms. * **antibouncehack**: Despite the integrated bounce reduction of the GPIO library some users may notice false triggers of their buttons (e.g. unrequested / double actions when releasing the button). If you encounter such problems, try setting this to `True` to activate an additional countermeasure. -Note: If you prefer, you may also use `Type: SimpleButton` instead of `Type: Button` - this makes no difference. +> [!NOTE] +> If you prefer, you may also use `Type: SimpleButton` instead of `Type: Button` - this makes no difference. ### ShutdownButton @@ -116,7 +118,7 @@ Again, there are more parameters than these. In the following comprehensive list * **iteration_time**: This parameter determines the flashing speed of the LED indicator. Default value is `0.2` seconds. * **functionCall**: While the default action is `functionCallShutdown`, you might use this button type even with other functions than system shutdown (again, see [function documentation below](#functions) for a list of available functions). -Furthermore, the following settings can be used as described for the [regular buttons](#doc_button): **pull_up_down**, **edge**, **bouncetime**, **antibouncehack**, **functionCallArgs** +Furthermore, the following settings can be used as described for the [regular buttons](#button): **pull_up_down**, **edge**, **bouncetime**, **antibouncehack**, **functionCallArgs** Note that using a ShutdownButton without a LED can also be implemented with a normal button like this: @@ -189,14 +191,16 @@ functionCall2: functionCallVolD * **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. + + 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 @@ -207,7 +211,6 @@ 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 @@ -223,9 +226,9 @@ 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 + +```text .---------------. .---------------. | | | | | CLK |----------------------| GPIO 22 | @@ -255,7 +258,9 @@ Pin: 14 * **Pin**: GPIO number of the LED (mandatory option). Note that you should not attach LEDs to GPIO ports without a matching resistor in line. -Note: If you prefer, you may also use `Type: MPDStatusLED` instead of `Type: StatusLED` - this makes no difference. +> [!NOTE] +> If you prefer, you may also use `Type: MPDStatusLED` instead of +> `Type: StatusLED` - this makes no difference. ### Further examples @@ -309,6 +314,7 @@ In this example, a short press initiates a short jump forward by customized 5 se For jumping backwards, this can be done equivalently (see [function list below](#functions)). #### Use Buttons to start playlists + To use GPIO-Pins to play music, you can emulate a card scan with the function `functionCallTriggerPlayCardId`. Supply the `cardid` as `functionCallArgs`. This behaves like a card scan, so you must link a folder to the id (on first press it will show up in the Web App as new card). diff --git a/components/synchronisation/sync-shared/README.md b/components/synchronisation/sync-shared/README.md index 5bf9818aa..7417ca3fc 100644 --- a/components/synchronisation/sync-shared/README.md +++ b/components/synchronisation/sync-shared/README.md @@ -35,11 +35,11 @@ You may also change the settings in the according files directly. ### Settings -**{INSTALLATION_ROOT}/settings/sync-shared-enabled** +#### {INSTALLATION_ROOT}/settings/sync-shared-enabled Holds the activation state of this feature. Values are "TRUE" or "FALSE" -**{INSTALLATION_ROOT}/settings/sync-shared.conf** +#### {INSTALLATION_ROOT}/settings/sync-shared.conf SYNCSHAREDMODE: The mode to access the server files. SSH or MOUNT diff --git a/scripts/helperscripts/README.md b/scripts/helperscripts/README.md index 7b22ab890..d5d0577cc 100644 --- a/scripts/helperscripts/README.md +++ b/scripts/helperscripts/README.md @@ -24,29 +24,29 @@ The created CSV file starts with the line ## CreatePodcastsKidsDeutsch.sh -Creates sample folders with files and streams +Creates sample folders with files and streams inside the $AUDIOFOLDERSPATH directory ## CreateSampleAudiofoldersStreams.sh -Creates sample folders with files and streams +Creates sample folders with files and streams inside the $AUDIOFOLDERSPATH directory ## DeleteAllConfig.sh -This script will delete all config files +This script will delete all config files including mpd.conf and the like. ## DeleteSampleAudiofoldersStreams.sh -Deletes sample folders with files and streams +Deletes sample folders with files and streams inside the $AUDIOFOLDERSPATH directory ## cli-player.py Command line player to play folders on the Phoniebox. -A command line replacement some functionality of the phoniebox-web-ui, which challenges the raspberry pi zero. +A command line replacement some functionality of the phoniebox-web-ui, which challenges the raspberry pi zero. Using this small script significantly reduces resource usage on the system. ## cli_ReadWifiIp.php @@ -55,11 +55,11 @@ Reads out the IP of the Phoniebox in English language on boot. ## organizeFiles.py -A small script for conveniently organizing audio folders, -linking them to RFID cards, finding audio folders that are currently +A small script for conveniently organizing audio folders, +linking them to RFID cards, finding audio folders that are currently not bound to any RFID card, and fixing broken links. -A command line replacement some functionality of the phoniebox-web-ui, which challenges the raspberry pi zero. +A command line replacement some functionality of the phoniebox-web-ui, which challenges the raspberry pi zero. Using this small script significantly reduces resource usage on the system. ## setup_autohotspot.sh @@ -67,17 +67,19 @@ Using this small script significantly reduces resource usage on the system. Script to setup the autohotspot feature. It automatically sets up a wifi hotspot if no known network is found. This is already included in the main install script, but can also be run manually. Please perform a reboot after you changed the configuration. -usage: +usage: setup_autohotspot.sh \ \ \ \ \ \ ### activate -``` + +```bash chmod +x ./scripts/helperscripts/setup_autohotspot.sh ./scripts/helperscripts/setup_autohotspot.sh . YES phoniebox DE PlayItLoud 10.0.0.5 ``` ### deactivate -``` + +```bash chmod +x ./scripts/helperscripts/setup_autohotspot.sh ./scripts/helperscripts/setup_autohotspot.sh . NO ``` From ca88b70c1321c29228b7081095e463817eefb327 Mon Sep 17 00:00:00 2001 From: s-martin Date: Mon, 13 May 2024 23:29:09 +0200 Subject: [PATCH 05/18] fix formatting (#2371) --- README.md | 3 ++- components/controls/buttons-bluetooth-headphone/README.md | 6 ++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 0398ff707..3b615efb8 100644 --- a/README.md +++ b/README.md @@ -141,7 +141,8 @@ There is a growing section of [troubleshooting](https://github.com/MiczFlor/RPi- Here is a list of equipment needed. You can find a lot second hand online (save money and the planet). The links below lead to Amazon, not at all because I want to support them, but because their PartnerNet program helps to support the Phoniebox maintenance (a little bit...). -Note: depending on individual projects, the hardware requirements vary. +> [!NOTE] +> Depending on individual projects, the hardware requirements vary. ### Raspberry Pi diff --git a/components/controls/buttons-bluetooth-headphone/README.md b/components/controls/buttons-bluetooth-headphone/README.md index c13e48f57..a9256f690 100644 --- a/components/controls/buttons-bluetooth-headphone/README.md +++ b/components/controls/buttons-bluetooth-headphone/README.md @@ -19,13 +19,15 @@ Out-of-the box support is included for the following buttons Key codes are standarized and so it should also work with your headphones. If you want to add more keys or assign a different behaviour see [Troubleshooting](#troubleshooting) -*Note:* Volume up/down is inherently supported by the bluetooth protocol. There is no need to handle these by this script. +> [!NOTE] +> Volume up/down is inherently supported by the bluetooth protocol. There is no need to handle these by this script. ## On Connect / On Disconnect If the feature [bluetooth-sink-switch](../../bluetooth-sink-switch) is enabled, the script automatically switches the audio stream to headphones / regular speakers on bluetooth connect / disconnect respectivly. Playback state (play/pause) is retained. -*Note:* On-connect actions may take up to 4 seconds - please be patient (bluetooth connection is only checked every two seconds, bluetooth stream needs to be buffered, etc...) + > [!NOTE] + > On-connect actions may take up to 4 seconds - please be patient (bluetooth connection is only checked every two seconds, bluetooth stream needs to be buffered, etc...) You can **customize** the behaviour by editing the functions From a18ca342659058f6224a6f53d054137bb6574edf Mon Sep 17 00:00:00 2001 From: s-martin Date: Fri, 17 May 2024 18:00:07 +0200 Subject: [PATCH 06/18] maint: Use flake8 config file (#2338) * Configure flake8 in config file * Use config file * Show source of error * Ignore a file * Extend ignore * Fix exclude * Update .gitignore * ignore some warnings * fix some warnings * annote flake8 warnings in github actions * fix some flake warnings * ignore helper scripts * fix some warnings * ignore and fix some warnings * ignore warnings * ignore and fix warnings * fix warnings * Revert changes * fix flake8 warning * fix flake8 warnings * install dependencies * configure flake8 * suppress warning * fix imports * fix warning * suppress some documentation warnings --- .flake8 | 27 +++++++++++++-- .github/workflows/pythonpackage.yml | 7 ++-- .../bluetooth-sink-switch/bt-sink-switch.py | 33 ++++++++++++------- .../buttons-bluetooth-headphone/bt-buttons.py | 20 +++++------ .../buttons_usb_encoder.py | 7 ++-- .../io_buttons_usb_encoder.py | 2 +- .../map_buttons_usb_encoder.py | 5 +-- .../gpio_control/config_compatibility.py | 4 +-- components/gpio_control/function_calls.py | 4 +-- .../MQTT-protocol/daemon_mqtt_client.py | 3 +- scripts/Reader.py | 2 +- scripts/Reader.py.Multi | 2 +- scripts/Reader.py.experimental | 9 ++--- scripts/Reader.py.experimental.Multi | 12 +++---- scripts/Reader.py.kkmoonRFIDreader | 4 +-- scripts/Reader.py.original | 4 +-- scripts/Reader.py.pcsc | 12 ++----- scripts/RegisterDevice.py.Multi | 2 +- scripts/daemon_rfid_reader.py | 4 +-- scripts/helperscripts/organizeFiles.py | 1 - 20 files changed, 92 insertions(+), 72 deletions(-) diff --git a/.flake8 b/.flake8 index d1b156813..a3c0629ce 100644 --- a/.flake8 +++ b/.flake8 @@ -1,12 +1,33 @@ [flake8] -max-line-length = 120 +max-line-length = 127 ignore = + # continuation line over-indented for hanging indent + E126, # continuation line over-indented for visual indent E127, # continuation line under-indented for visual indent - E128 + E128, + # line break before binary operator + W503, + # We don't always want periods at the end of the first docstring line + D400, + # We dont rephrase to imperative mood + D401 per-file-ignores = # Only in __init__files ignore imported but unused # Not necessary, if __all__ is declared in __init__ file # https://www.python.org/dev/peps/pep-0008/#id48 - __init__.py:F401 + __init__.py:F401, + components/smart-home-automation/MQTT-protocol/daemon_mqtt_client.py:W605, + components/controls/buttons_usb_encoder/*.py:E402 +count = True +max-complexity = 12 +statistics = True +show-source = True +filename = *.py,*.py.* +extend-exclude = + # Ignore dirs and files, which are from external sources + components/displays/HD44780-i2c/ + scripts/Reader.py.pcsc + # Ignore helper scripts + scripts/helperscripts/ diff --git a/.github/workflows/pythonpackage.yml b/.github/workflows/pythonpackage.yml index 6cb871112..b7eab32ef 100644 --- a/.github/workflows/pythonpackage.yml +++ b/.github/workflows/pythonpackage.yml @@ -30,13 +30,12 @@ jobs: pip install spidev pip install -r requirements.txt pip install -r requirements-GPIO.txt + - name: Setup flake8 annotations + uses: rbialon/flake8-annotations@v1 - name: Lint with flake8 run: | pip install flake8 - # stop the build if there are Python syntax errors or undefined names - flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics --filename=*.py,*.py.* - # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide - flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics --filename=*.py,*.py.* + flake8 --config .flake8 - name: Test with pytest run: | pytest --cov --cov-config=.coveragerc --cov-report xml diff --git a/components/bluetooth-sink-switch/bt-sink-switch.py b/components/bluetooth-sink-switch/bt-sink-switch.py index a107703a7..7fe2d918f 100755 --- a/components/bluetooth-sink-switch/bt-sink-switch.py +++ b/components/bluetooth-sink-switch/bt-sink-switch.py @@ -47,13 +47,15 @@ def bt_check_mpc_err() -> None: logger.debug(mpcplay) -def bt_switch(cmd, led_pin=None): +def bt_switch(cmd, led_pin=None): # noqa C901 """ - Set/Toggle between regular speakers and headphone output. If no bluetooth device is connected, always defaults to mpc output 1 + Set/Toggle between regular speakers and headphone output. If no bluetooth device is connected, + always defaults to mpc output 1 To be precise: toggle between mpc output 1 and mpc output 2. - So, set up your /etc/mpd.conf correctly: first audio_output section should be speakers, second audio_output section should be headphones + So, set up your /etc/mpd.conf correctly: first audio_output section should be speakers, + second audio_output section should be headphones To set up bluetooth headphones, follow the wiki Short guide to connect bluetooth (without audio setup) sudo bluetoothctl @@ -71,13 +73,16 @@ def bt_switch(cmd, led_pin=None): sudo apt install bluetooth Attention - The user to runs this script (precisly who runs bluetoothctl) needs proper access rights. Otherwise bluetoothctl will always return "no default controller found" + The user to runs this script (precisly who runs bluetoothctl) needs proper access rights. + Otherwise bluetoothctl will always return "no default controller found" The superuser and users of group "bluetooth" have these. You can check the policy here /etc/dbus-1/system.d/bluetooth.conf Best to check first if the user which later runs this script can execute bluetoothctl and get meaningful results sudo -u www-data bluetoothctl show - E.g. if you want to do bluetooth manipulation from the web interface, you will most likely need to add www-data to the group bluetooth - if you want to test this script from the command line, you will most likely need to add user pi (or whoever you are) to the group bluetooth or run it as superuser + E.g. if you want to do bluetooth manipulation from the web interface, you will most likely need to add www-data + to the group bluetooth + if you want to test this script from the command line, you will most likely need to add user pi + (or whoever you are) to the group bluetooth or run it as superuser sudo usermod -G bluetooth -a www-data Don't forget to reboot for group changes to take effect here @@ -86,14 +91,17 @@ def bt_switch(cmd, led_pin=None): off = speakers, on = headphones LED blinks if no bluetooth device is connected and bluetooth sink is requested, before script default to output 1 - A note for developers: This script is not persistent and only gets called (from various sources) when the output sink is changed/toggled and exits. + A note for developers: This script is not persistent and only gets called (from various sources) + when the output sink is changed/toggled and exits. This is done to make is callable from button press (gpio button handler), rfid card number, web interface - The LED state however should be persistent. With GPIOZero, the LED state gets reset at the end of the script. For that reason GPIO state is manipulated through shell commands + The LED state however should be persistent. With GPIOZero, the LED state gets reset at the end of the script. + For that reason GPIO state is manipulated through shell commands Parameters ---------- :param cmd: string is "toggle" | "speakers" | "headphones" - :param led_pin: integer with GPIO pin number of LED to reflect output status. If None, LED support is disabled (and no GPIO pin is blocked) + :param led_pin: integer with GPIO pin number of LED to reflect output status. If None, LED support is disabled + (and no GPIO pin is blocked) """ # Check for valid command if cmd != "toggle" and cmd != "speakers" and cmd != "headphones": @@ -127,14 +135,15 @@ def bt_switch(cmd, led_pin=None): logger.debug(isSpeakerOn_console.stdout) isSpeakerOn = re.search(b"^Output 1.*enabled", isSpeakerOn_console.stdout) - # Figure out if a bluetooth device is connected (any device will do). Assume here that only speakers/headsets will be connected + # Figure out if a bluetooth device is connected (any device will do). Assume here that only speakers/headsets + # will be connected # -> No need for user to adapt MAC address # -> will actually support multiple speakers/headsets paired to the phoniebox # Alternative: Check for specific bluetooth device only with "bluetoothctl info MACADDRESS" isBtConnected_console = subprocess.run("bluetoothctl info", shell=True, check=False, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) logger.debug(isBtConnected_console.stdout) - isBtConnected = re.search(b"Connected:\s+yes", isBtConnected_console.stdout) + isBtConnected = re.search(b"Connected:\s+yes", isBtConnected_console.stdout) # noqa W605 if (cmd == "toggle" and isSpeakerOn) or (cmd == "headphones"): # Only switch to BT headphones if they are actually connected @@ -207,7 +216,7 @@ def get_led_pin_config(cfg_file): if cfg[section_name].getboolean('enabled', fallback=False): led_pin = cfg[section_name].getint('led_pin', fallback=None) if not led_pin: - logger.warning(f"Could not find 'led_pin' or could not read integer value") + logger.warning("Could not find 'led_pin' or could not read integer value") elif not 1 <= led_pin <= 27: logger.warning(f"Ignoring out of range pin number: {led_pin}.") led_pin = None diff --git a/components/controls/buttons-bluetooth-headphone/bt-buttons.py b/components/controls/buttons-bluetooth-headphone/bt-buttons.py index d079ae510..09dfaf25a 100755 --- a/components/controls/buttons-bluetooth-headphone/bt-buttons.py +++ b/components/controls/buttons-bluetooth-headphone/bt-buttons.py @@ -56,7 +56,7 @@ def bt_on_disconnect(mpd_support=0) -> None: """ logger.info("on disconnect") if mpd_support: - pctproc = subprocess.run(f"{os.path.dirname(os.path.realpath(__file__))}/../../../scripts/playout_controls.sh -c=bluetoothtoggle -v=speakers", shell=True, check=False, + pctproc = subprocess.run(f"{os.path.dirname(os.path.realpath(__file__))}/../../../scripts/playout_controls.sh -c=bluetoothtoggle -v=speakers", shell=True, check=False, # noqa: E501 stdout=subprocess.PIPE, stderr=subprocess.STDOUT) logger.debug(pctproc.stdout) @@ -71,7 +71,7 @@ def bt_on_connect(mpd_support=0) -> None: """ logger.info("on connect") if mpd_support: - pctproc = subprocess.run(f"{os.path.dirname(os.path.realpath(__file__))}/../../../scripts/playout_controls.sh -c=bluetoothtoggle -v=headphones", shell=True, check=False, + pctproc = subprocess.run(f"{os.path.dirname(os.path.realpath(__file__))}/../../../scripts/playout_controls.sh -c=bluetoothtoggle -v=headphones", shell=True, check=False, # noqa: E501 stdout=subprocess.PIPE, stderr=subprocess.STDOUT) logger.debug(pctproc.stdout) @@ -139,17 +139,17 @@ def bt_key_handler(name, mpd_support=0) -> None: # Only act on button press, not button release if event.value == 1: if event.code == bt_keycode_play: - proc = subprocess.run(f"{path}/../../../scripts/playout_controls.sh -c=playerpause", shell=True, check=False, - stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + proc = subprocess.run(f"{path}/../../../scripts/playout_controls.sh -c=playerpause", shell=True, + check=False, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) elif event.code == bt_keycode_pause: - proc = subprocess.run(f"{path}/../../../scripts/playout_controls.sh -c=playerpause", shell=True, check=False, - stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + proc = subprocess.run(f"{path}/../../../scripts/playout_controls.sh -c=playerpause", shell=True, + check=False, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) elif event.code == bt_keycode_next: - proc = subprocess.run(f"{path}/../../../scripts/playout_controls.sh -c=playernext", shell=True, check=False, - stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + proc = subprocess.run(f"{path}/../../../scripts/playout_controls.sh -c=playernext", shell=True, + check=False, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) elif event.code == bt_keycode_prev: - proc = subprocess.run(f"{path}/../../../scripts/playout_controls.sh -c=playerprev", shell=True, check=False, - stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + proc = subprocess.run(f"{path}/../../../scripts/playout_controls.sh -c=playerprev", shell=True, + check=False, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) logger.debug(proc.stdout) if proc.returncode != 0: logger.error("#" * 60) diff --git a/components/controls/buttons_usb_encoder/buttons_usb_encoder.py b/components/controls/buttons_usb_encoder/buttons_usb_encoder.py index e8fa807a9..777278467 100644 --- a/components/controls/buttons_usb_encoder/buttons_usb_encoder.py +++ b/components/controls/buttons_usb_encoder/buttons_usb_encoder.py @@ -28,10 +28,11 @@ function_args = button_map[button_string + "_args"] try: getattr(function_calls, function_name)(function_args) - except: + except Exception: logger.warning( - "Function " + function_name + " not found in function_calls.py (mapped from button: " + button_string + ")") + "Function " + function_name + + " not found in function_calls.py (mapped from button: " + button_string + ")") except KeyError: logger.warning("Button " + button_string + " not mapped to any function.") -except: +except Exception: logger.error("An error with Buttons USB Encoder occurred.") diff --git a/components/controls/buttons_usb_encoder/io_buttons_usb_encoder.py b/components/controls/buttons_usb_encoder/io_buttons_usb_encoder.py index c20e5c366..2f03f8191 100644 --- a/components/controls/buttons_usb_encoder/io_buttons_usb_encoder.py +++ b/components/controls/buttons_usb_encoder/io_buttons_usb_encoder.py @@ -28,7 +28,7 @@ def current_device(): break try: _current_device - except: + except Exception: sys.exit('Could not find the device %s\n. Make sure it is connected' % device_name) return _current_device diff --git a/components/controls/buttons_usb_encoder/map_buttons_usb_encoder.py b/components/controls/buttons_usb_encoder/map_buttons_usb_encoder.py index 394564de6..e832e1c52 100644 --- a/components/controls/buttons_usb_encoder/map_buttons_usb_encoder.py +++ b/components/controls/buttons_usb_encoder/map_buttons_usb_encoder.py @@ -11,7 +11,7 @@ sys.path.append(".") -try: +try: # noqa C901 functions = list( filter(lambda function_name: function_name.startswith("functionCall"), dir(components.gpio_control.function_calls.phoniebox_function_calls))) @@ -43,7 +43,8 @@ button_map[button_string] = function_name button_map[button_string + "_args"] = function_args - print("Button '" + button_string + "' is now mapped to '" + function_name_short + "' with argument '" + str(function_args) + "'") + print("Button '" + button_string + "' is now mapped to '" + function_name_short + + "' with argument '" + str(function_args) + "'") break except KeyboardInterrupt: continue diff --git a/components/gpio_control/config_compatibility.py b/components/gpio_control/config_compatibility.py index 9c2e92f5d..59a32f18d 100644 --- a/components/gpio_control/config_compatibility.py +++ b/components/gpio_control/config_compatibility.py @@ -1,10 +1,10 @@ #!/usr/bin/env python3 -import configparser + import os from shutil import copyfile -def Ini_CheckAndUpgrade(config): +def Ini_CheckAndUpgrade(config): # noqa C901 has_changed = False for section in config.sections(): # enable: True --> enabled: True diff --git a/components/gpio_control/function_calls.py b/components/gpio_control/function_calls.py index c3eda5913..9978a7695 100644 --- a/components/gpio_control/function_calls.py +++ b/components/gpio_control/function_calls.py @@ -100,10 +100,10 @@ def functionCallBluetoothToggle(self, mode=None, *args): function_call("{command} -c=bluetoothtoggle -v={value}".format(command=self.playout_control, value=mode), shell=True) def functionCallTriggerPlayCardId(self, cardid, *args): - function_call("{command} --cardid={value}".format(command=self.rfid_trigger, value = cardid), shell=True) + function_call("{command} --cardid={value}".format(command=self.rfid_trigger, value=cardid), shell=True) def functionCallTriggerPlayFolder(self, folder, *args): - function_call("{command} --dir={value}".format(command=self.rfid_trigger, value = folder), shell=True) + function_call("{command} --dir={value}".format(command=self.rfid_trigger, value=folder), shell=True) def getFunctionCall(self, functionName): self.logger.error('Get FunctionCall: {} {}'.format(functionName, functionName in locals())) diff --git a/components/smart-home-automation/MQTT-protocol/daemon_mqtt_client.py b/components/smart-home-automation/MQTT-protocol/daemon_mqtt_client.py index 583ad0c9b..87a5d070f 100644 --- a/components/smart-home-automation/MQTT-protocol/daemon_mqtt_client.py +++ b/components/smart-home-automation/MQTT-protocol/daemon_mqtt_client.py @@ -3,10 +3,9 @@ import datetime import os import re -import ssl import subprocess import time -from threading import * +from threading import Thread import inotify.adapters import paho.mqtt.client as mqtt diff --git a/scripts/Reader.py b/scripts/Reader.py index d3c09f2b6..b6ec9a4ba 100755 --- a/scripts/Reader.py +++ b/scripts/Reader.py @@ -45,7 +45,7 @@ def __init__(self): break try: self.dev - except: + except Exception: sys.exit('Could not find the device %s\n. Make sure is connected' % deviceName) def readCard(self): diff --git a/scripts/Reader.py.Multi b/scripts/Reader.py.Multi index 5e98b4d0f..1b2ac3d3d 100644 --- a/scripts/Reader.py.Multi +++ b/scripts/Reader.py.Multi @@ -49,7 +49,7 @@ class Reader: for dev in devs: try: dev - except: + except Exception: sys.exit('Could not find the device %s\n. Make sure is connected' % dev.name) str_devs = ','.join([str(x) for x in devs]) diff --git a/scripts/Reader.py.experimental b/scripts/Reader.py.experimental index e3854f629..36429314c 100755 --- a/scripts/Reader.py.experimental +++ b/scripts/Reader.py.experimental @@ -11,7 +11,7 @@ import sys import RPi.GPIO as GPIO import logging -from evdev import InputDevice, categorize, ecodes, list_devices +from evdev import InputDevice, ecodes, list_devices logger = logging.getLogger(__name__) @@ -131,7 +131,7 @@ class Rdm6300Reader: else: return None - def readCard(self): + def readCard(self): # noqa C901 byte_card_id = bytearray() try: @@ -188,7 +188,7 @@ class Pn532Reader: from py532lib.i2c import Pn532_i2c from py532lib.mifare import Mifare from py532lib.mifare import MIFARE_WAIT_FOR_ENTRY - pn532 = Pn532_i2c() + pn532 = Pn532_i2c() # noqa F841 self.device = Mifare() self.device.SAMconfigure() self.device.set_max_retries(MIFARE_WAIT_FOR_ENTRY) @@ -213,7 +213,8 @@ class Reader(object): if device_name == 'MFRC522': self.reader = Mfrc522Reader() elif device_name == 'RDM6300': - # The Rdm6300Reader supports 2 Additional Number Formats which can bee choosen by an optional parameter dictionary: + # The Rdm6300Reader supports 2 Additional Number Formats which can be choosen + # by an optional parameter dictionary: # {'numberformat':'card_id_float'} or {'numberformat':'card_id_dec'} self.reader = Rdm6300Reader() elif device_name == 'PN532': diff --git a/scripts/Reader.py.experimental.Multi b/scripts/Reader.py.experimental.Multi index b7c4fcb5f..a0d518ff7 100644 --- a/scripts/Reader.py.experimental.Multi +++ b/scripts/Reader.py.experimental.Multi @@ -17,13 +17,6 @@ import RPi.GPIO as GPIO import logging from enum import Enum from evdev import InputDevice, ecodes, list_devices -# Workaround: when using RC522 reader with pirc522 pkg the py532lib pkg may not be installed and vice-versa -try: - import pirc522 - from py532lib.i2c import * - from py532lib.mifare import * -except ImportError: - pass logger = logging.getLogger(__name__) @@ -165,7 +158,10 @@ class Rdm6300Reader: class Pn532Reader: def __init__(self): - pn532 = Pn532_i2c() + from py532lib.i2c import Pn532_i2c + from py532lib.mifare import Mifare + from py532lib.mifare import MIFARE_WAIT_FOR_ENTRY + pn532 = Pn532_i2c() # noqa F841 self.device = Mifare() self.device.SAMconfigure() self.device.set_max_retries(MIFARE_WAIT_FOR_ENTRY) diff --git a/scripts/Reader.py.kkmoonRFIDreader b/scripts/Reader.py.kkmoonRFIDreader index 10853b41b..0c55ec060 100755 --- a/scripts/Reader.py.kkmoonRFIDreader +++ b/scripts/Reader.py.kkmoonRFIDreader @@ -9,7 +9,7 @@ import os.path import sys -from evdev import InputDevice, categorize, ecodes, list_devices +from evdev import InputDevice, ecodes, list_devices from select import select @@ -44,7 +44,7 @@ class Reader: break try: self.dev - except: + except Exception: sys.exit('Could not find the device %s\n. Make sure is connected' % deviceName) def readCard(self): diff --git a/scripts/Reader.py.original b/scripts/Reader.py.original index 80a4fabf3..1212155b3 100755 --- a/scripts/Reader.py.original +++ b/scripts/Reader.py.original @@ -19,7 +19,7 @@ import os.path import sys -from evdev import InputDevice, categorize, ecodes, list_devices +from evdev import InputDevice, ecodes, list_devices from select import select import logging logger = logging.getLogger(__name__) @@ -51,7 +51,7 @@ class Reader: break try: self.dev - except: + except Exception: sys.exit('Could not find the device %s\n. Make sure is connected' % deviceName) def readCard(self): diff --git a/scripts/Reader.py.pcsc b/scripts/Reader.py.pcsc index 792b29f01..0cc50cd77 100644 --- a/scripts/Reader.py.pcsc +++ b/scripts/Reader.py.pcsc @@ -22,16 +22,12 @@ class Reader: try: hresult, hcontext = SCardEstablishContext(SCARD_SCOPE_USER) if hresult != SCARD_S_SUCCESS: - raise error( - 'Failed to establish context: ' + \ - SCardGetErrorMessage(hresult)) + raise error('Failed to establish context: ' + SCardGetErrorMessage(hresult)) try: hresult, readers = SCardListReaders(hcontext, []) if hresult != SCARD_S_SUCCESS: - raise error( - 'Failed to list readers: ' + \ - SCardGetErrorMessage(hresult)) + raise error('Failed to list readers: ' + SCardGetErrorMessage(hresult)) readerstates = [] for i in range(len(readers)): @@ -57,9 +53,7 @@ class Reader: finally: hresult = SCardReleaseContext(hcontext) if hresult != SCARD_S_SUCCESS: - raise error( - 'Failed to release context: ' + \ - SCardGetErrorMessage(hresult)) + raise error('Failed to release context: ' + SCardGetErrorMessage(hresult)) return (toHexString(response, PACK)) diff --git a/scripts/RegisterDevice.py.Multi b/scripts/RegisterDevice.py.Multi index 008121496..9e9e40143 100644 --- a/scripts/RegisterDevice.py.Multi +++ b/scripts/RegisterDevice.py.Multi @@ -51,7 +51,7 @@ def setupMFRC522(): runCmd("cp {0}/scripts/Reader.py.experimental.Multi {1}/scripts/Reader.py".format(JUKEBOX_HOME_DIR, JUKEBOX_HOME_DIR)) -from Reader import get_devices, EDevices +from Reader import get_devices, EDevices # noqa E402 list_dev_ids = list() devices = get_devices() diff --git a/scripts/daemon_rfid_reader.py b/scripts/daemon_rfid_reader.py index b37c96bba..a7e5cf78f 100755 --- a/scripts/daemon_rfid_reader.py +++ b/scripts/daemon_rfid_reader.py @@ -57,7 +57,7 @@ # if controlcards delay is deactivated, let the cards pass, otherwise, they have to wait... if sspc_nodelay == "ON": - ids = re.findall("(\d+)", string) + ids = re.findall("(\d+)", string) # noqa W605 else: ids = "" @@ -69,7 +69,7 @@ def handler(signum, frame): # force pause the player script logger.info('Trigger Pause Force') subprocess.call([dir_path + '/playout_controls.sh -c=playerpauseforce -v=0.1'], shell=True) - except OSError as e: + except OSError: logger.info('Execution of Pause failed.') diff --git a/scripts/helperscripts/organizeFiles.py b/scripts/helperscripts/organizeFiles.py index 06c372633..7c387ec0f 100644 --- a/scripts/helperscripts/organizeFiles.py +++ b/scripts/helperscripts/organizeFiles.py @@ -2,7 +2,6 @@ # -*- coding: utf-8 -*- -import sys import os import argparse From 3431ba1a1b8865796fa618b8a0c4a257c842c25f Mon Sep 17 00:00:00 2001 From: s-martin Date: Fri, 17 May 2024 19:40:26 +0200 Subject: [PATCH 07/18] document working cards for rc522 (#2374) --- components/rfid-reader/RC522/README.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/components/rfid-reader/RC522/README.md b/components/rfid-reader/RC522/README.md index 156ce5a09..b84479a07 100644 --- a/components/rfid-reader/RC522/README.md +++ b/components/rfid-reader/RC522/README.md @@ -1,4 +1,6 @@ -# How to setup the RC522 RFID reader +# RC522 Reader + +## How to setup the RC522 RFID reader 1. **You can use the `setup_rc522.sh` script (recommended)** or follow the manual steps: @@ -15,3 +17,7 @@ - `sudo systemctl restart phoniebox-rfid-reader.service` Be aware that unlike a few other installations with this card reader the phoniebox requires the IRQ pin to be connected (on the raspberry pi and zero normaly to GPIO 24 or PIN 18). + +## Working cards/tags + +Cards or tags must support 13.56 MHz. Currently, only cards/tags of the type "NXP Mifare Classic 1k(S50)", "NXP Mifare Classic 4k(S70)" and "NXP Mifare Ultralight (C)" can be used. Type "NXP Mifare NTAG2xx" will not work! From 444897e76862dfe37e700055e1c9d95f434e248f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 3 Jun 2024 17:24:27 +0200 Subject: [PATCH 08/18] Bump DavidAnson/markdownlint-cli2-action from 15 to 16 (#2379) Bumps [DavidAnson/markdownlint-cli2-action](https://github.com/davidanson/markdownlint-cli2-action) from 15 to 16. - [Release notes](https://github.com/davidanson/markdownlint-cli2-action/releases) - [Commits](https://github.com/davidanson/markdownlint-cli2-action/compare/v15...v16) --- updated-dependencies: - dependency-name: DavidAnson/markdownlint-cli2-action dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/markdown.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/markdown.yml b/.github/workflows/markdown.yml index fa251ed9f..923f4ae2b 100644 --- a/.github/workflows/markdown.yml +++ b/.github/workflows/markdown.yml @@ -23,7 +23,7 @@ jobs: uses: actions/checkout@v4 - name: Linting markdown - uses: DavidAnson/markdownlint-cli2-action@v15 + uses: DavidAnson/markdownlint-cli2-action@v16 with: config: .markdownlint-cli2.yaml #continue-on-error: true From 74abc378f8ed471182e0391a68a5187fb7e9f5dd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 4 Jul 2024 08:38:33 +0200 Subject: [PATCH 09/18] Bump docker/build-push-action from 5 to 6 (#2394) Bumps [docker/build-push-action](https://github.com/docker/build-push-action) from 5 to 6. - [Release notes](https://github.com/docker/build-push-action/releases) - [Commits](https://github.com/docker/build-push-action/compare/v5...v6) --- updated-dependencies: - dependency-name: docker/build-push-action dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/test_docker_debian_codename_sub.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test_docker_debian_codename_sub.yml b/.github/workflows/test_docker_debian_codename_sub.yml index 7aa1cd41e..504220e04 100644 --- a/.github/workflows/test_docker_debian_codename_sub.yml +++ b/.github/workflows/test_docker_debian_codename_sub.yml @@ -94,7 +94,7 @@ jobs: # Build base image for debian version name. Layers will be cached and image pushes to local registry - name: Build Image - Base - uses: docker/build-push-action@v5 + uses: docker/build-push-action@v6 with: context: . load: false @@ -112,7 +112,7 @@ jobs: # Build new image with updates packages based on base image. Layers will NOT be chached. Result is written to file. - name: Build Image - Update - uses: docker/build-push-action@v5 + uses: docker/build-push-action@v6 with: context: . load: false From 728d788d6bb5670479418b87d60c2c7c93b2ce5e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 24 Aug 2024 10:49:05 +0200 Subject: [PATCH 10/18] Bump docker/setup-qemu-action from 3.0.0 to 3.2.0 (#2411) Bumps [docker/setup-qemu-action](https://github.com/docker/setup-qemu-action) from 3.0.0 to 3.2.0. - [Release notes](https://github.com/docker/setup-qemu-action/releases) - [Commits](https://github.com/docker/setup-qemu-action/compare/v3.0.0...v3.2.0) --- updated-dependencies: - dependency-name: docker/setup-qemu-action dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/test_docker_debian_codename_sub.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test_docker_debian_codename_sub.yml b/.github/workflows/test_docker_debian_codename_sub.yml index 504220e04..22ab1864f 100644 --- a/.github/workflows/test_docker_debian_codename_sub.yml +++ b/.github/workflows/test_docker_debian_codename_sub.yml @@ -55,7 +55,7 @@ jobs: - uses: actions/checkout@v4 - name: Set up QEMU - uses: docker/setup-qemu-action@v3.0.0 + uses: docker/setup-qemu-action@v3.2.0 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3.3.0 @@ -152,7 +152,7 @@ jobs: steps: - name: Set up QEMU - uses: docker/setup-qemu-action@v3.0.0 + uses: docker/setup-qemu-action@v3.2.0 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3.3.0 From 4ace93dc37d199bf58495e04d3bcfac4e52b2d22 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 24 Aug 2024 10:49:36 +0200 Subject: [PATCH 11/18] Bump docker/setup-buildx-action from 3.3.0 to 3.6.1 (#2410) Bumps [docker/setup-buildx-action](https://github.com/docker/setup-buildx-action) from 3.3.0 to 3.6.1. - [Release notes](https://github.com/docker/setup-buildx-action/releases) - [Commits](https://github.com/docker/setup-buildx-action/compare/v3.3.0...v3.6.1) --- updated-dependencies: - dependency-name: docker/setup-buildx-action dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/test_docker_debian_codename_sub.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test_docker_debian_codename_sub.yml b/.github/workflows/test_docker_debian_codename_sub.yml index 22ab1864f..5198f150a 100644 --- a/.github/workflows/test_docker_debian_codename_sub.yml +++ b/.github/workflows/test_docker_debian_codename_sub.yml @@ -58,7 +58,7 @@ jobs: uses: docker/setup-qemu-action@v3.2.0 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3.3.0 + uses: docker/setup-buildx-action@v3.6.1 with: # network=host driver-opt needed to push to local registry driver-opts: network=host @@ -155,7 +155,7 @@ jobs: uses: docker/setup-qemu-action@v3.2.0 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3.3.0 + uses: docker/setup-buildx-action@v3.6.1 - name: Artifact Download Docker Image uses: actions/download-artifact@v4 From 37aadc479dd74109aa10025128923495f555cf53 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 2 Oct 2024 08:59:30 +0200 Subject: [PATCH 12/18] Bump DavidAnson/markdownlint-cli2-action from 16 to 17 (#2434) Bumps [DavidAnson/markdownlint-cli2-action](https://github.com/davidanson/markdownlint-cli2-action) from 16 to 17. - [Release notes](https://github.com/davidanson/markdownlint-cli2-action/releases) - [Commits](https://github.com/davidanson/markdownlint-cli2-action/compare/v16...v17) --- updated-dependencies: - dependency-name: DavidAnson/markdownlint-cli2-action dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/markdown.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/markdown.yml b/.github/workflows/markdown.yml index 923f4ae2b..68b53005f 100644 --- a/.github/workflows/markdown.yml +++ b/.github/workflows/markdown.yml @@ -23,7 +23,7 @@ jobs: uses: actions/checkout@v4 - name: Linting markdown - uses: DavidAnson/markdownlint-cli2-action@v16 + uses: DavidAnson/markdownlint-cli2-action@v17 with: config: .markdownlint-cli2.yaml #continue-on-error: true From ed052456fa176310c356f305fcb3eacca6bd58f7 Mon Sep 17 00:00:00 2001 From: s-martin Date: Tue, 15 Oct 2024 23:18:28 +0200 Subject: [PATCH 13/18] Add validation and sanitization for email address in `htdocs/inc.setWlanIpMail.php` * Validate email address using `filter_var` with `FILTER_VALIDATE_EMAIL` * Sanitize email address using `htmlspecialchars` * Replace `exec` function with `shell_exec` to prevent command injection Add unit tests in `tests/htdocs/inc/SetWlanIpMailTest.php` * Validate email address using `filter_var` with `FILTER_VALIDATE_EMAIL` * Sanitize email address using `htmlspecialchars` * Ensure `exec` function is replaced with `shell_exec` --- htdocs/inc.setWlanIpMail.php | 15 ++++-- tests/htdocs/inc/SetWlanIpMailTest.php | 69 ++++++++++++++++++++++++++ 2 files changed, 79 insertions(+), 5 deletions(-) mode change 100755 => 100644 htdocs/inc.setWlanIpMail.php create mode 100644 tests/htdocs/inc/SetWlanIpMailTest.php diff --git a/htdocs/inc.setWlanIpMail.php b/htdocs/inc.setWlanIpMail.php old mode 100755 new mode 100644 index d034aa2b3..4feb49bb0 --- a/htdocs/inc.setWlanIpMail.php +++ b/htdocs/inc.setWlanIpMail.php @@ -34,13 +34,18 @@ } // Email address $WlanIpMailAddr = trim($_POST['WlanIpMailAddr']); - $exec = 'echo "'.$WlanIpMailAddr.'" > '.$conf['settings_abs'].'/WlanIpMailAddr'; - if($debug == "true") { - print $exec; + if (filter_var($WlanIpMailAddr, FILTER_VALIDATE_EMAIL)) { + $WlanIpMailAddr = htmlspecialchars($WlanIpMailAddr, ENT_QUOTES, 'UTF-8'); + $exec = 'echo "'.$WlanIpMailAddr.'" > '.$conf['settings_abs'].'/WlanIpMailAddr'; + if($debug == "true") { + print $exec; + } + shell_exec($exec); // P36bd + } else { + echo "Invalid email address."; } - exec($exec); // execute shell to create config file - exec("sudo ".$conf['scripts_abs']."/inc.writeGlobalConfig.sh"); + shell_exec("sudo ".$conf['scripts_abs']."/inc.writeGlobalConfig.sh"); // P36bd } ?> diff --git a/tests/htdocs/inc/SetWlanIpMailTest.php b/tests/htdocs/inc/SetWlanIpMailTest.php new file mode 100644 index 000000000..97c04b97c --- /dev/null +++ b/tests/htdocs/inc/SetWlanIpMailTest.php @@ -0,0 +1,69 @@ +getFunctionMock(__NAMESPACE__, 'parse_ini_file'); + $parse_ini_file->expects($this->atLeastOnce())->willReturn( + array( + "DEBUG_WebApp" => "FALSE", + "DEBUG_WebApp_API" => "FALSE" + )); + $_SERVER['REQUEST_METHOD'] = ''; + require_once 'htdocs/inc.setWlanIpMail.php'; + } + + /** + * @runInSeparateProcess + */ + public function testValidateEmail() { + $filter_var = $this->getFunctionMock(__NAMESPACE__, 'filter_var'); + $filter_var->expects($this->atLeastOnce())->willReturnCallback( + function ($email, $filter) { + $this->assertEquals(FILTER_VALIDATE_EMAIL, $filter); + return filter_var($email, $filter); + } + ); + + $this->assertTrue(filter_var('test@example.com', FILTER_VALIDATE_EMAIL)); + $this->assertFalse(filter_var('invalid-email', FILTER_VALIDATE_EMAIL)); + } + + /** + * @runInSeparateProcess + */ + public function testSanitizeEmail() { + $htmlspecialchars = $this->getFunctionMock(__NAMESPACE__, 'htmlspecialchars'); + $htmlspecialchars->expects($this->atLeastOnce())->willReturnCallback( + function ($string, $flags, $encoding) { + $this->assertEquals(ENT_QUOTES, $flags); + $this->assertEquals('UTF-8', $encoding); + return htmlspecialchars($string, $flags, $encoding); + } + ); + + $this->assertEquals('test@example.com', htmlspecialchars('test@example.com', ENT_QUOTES, 'UTF-8')); + $this->assertEquals('test<script>@example.com', htmlspecialchars('test