diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 1a365a93c..f895114ef 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -35,7 +35,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL diff --git a/.github/workflows/docker_bullseye.yml b/.github/workflows/docker_bullseye.yml deleted file mode 100644 index c65fc6219..000000000 --- a/.github/workflows/docker_bullseye.yml +++ /dev/null @@ -1,77 +0,0 @@ -name: Test Install Scripts for Bullseye on Docker - -on: - push: - branches-ignore: - - 'future3/**' - pull_request: - # The branches below must be a subset of the branches above - branches: [ develop ] - -jobs: - - build: - - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v3 - - - name: Set up QEMU - uses: docker/setup-qemu-action@v2.2.0 - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v2.10.0 - - - name: Build Bullseye ARMv7 - uses: docker/build-push-action@v4 - with: - context: . - load: true - push: false - file: ./ci/Dockerfile.bullseye.test_install.armv7 - platforms: linux/arm/v7 - tags: rpi-jukebox-rfid-bullseye:latest - cache-from: type=gha,scope=$GITHUB_REF_NAME-bullseye - cache-to: type=gha,mode=max,scope=$GITHUB_REF_NAME-bullseye - - - name: Run run_installation_tests.sh Bullseye ARMv7 - uses: tj-actions/docker-run@v2 - with: - image: rpi-jukebox-rfid-bullseye:latest - name: bullseye_run_installation_tests.sh - options: --platform linux/arm/v7 - args: | - /code/scripts/installscripts/tests/run_installation_tests.sh - - - name: Run run_installation_tests2.sh Bullseye ARMv7 - uses: tj-actions/docker-run@v2 - with: - image: rpi-jukebox-rfid-bullseye:latest - name: bullseye_run_installation_tests2.sh - options: --platform linux/arm/v7 - args: | - /code/scripts/installscripts/tests/run_installation_tests2.sh - - - name: Run run_installation_tests3.sh Bullseye ARMv7 - uses: tj-actions/docker-run@v2 - with: - image: rpi-jukebox-rfid-bullseye:latest - name: bullseye_run_installation_tests3.sh - options: --platform linux/arm/v7 - args: | - /code/scripts/installscripts/tests/run_installation_tests3.sh - - - - - - - - - - - - - - diff --git a/.github/workflows/docker_bullseye_altuser.yml b/.github/workflows/docker_bullseye_altuser.yml deleted file mode 100644 index 7109b5a07..000000000 --- a/.github/workflows/docker_bullseye_altuser.yml +++ /dev/null @@ -1,65 +0,0 @@ -name: Test Install Scripts for Bullseye (alternative user) on Docker - -on: - schedule: - # run at 5 every sunday - - cron: '* 5 * * 0' - -jobs: - - build: - - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v3 - - - name: Set up QEMU - uses: docker/setup-qemu-action@v2.2.0 - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v2.10.0 - - - name: Build altuser hans Bullseye ARMv7 - uses: docker/build-push-action@v4 - with: - context: . - load: true - push: false - file: ./ci/Dockerfile.bullseye.test_install_altuser.armv7 - platforms: linux/arm/v7 - tags: rpi-jukebox-rfid-bullseye-altuser:latest - cache-from: type=gha,scope=$GITHUB_REF_NAME-bullseye-hans - cache-to: type=gha,mode=max,scope=$GITHUB_REF_NAME-bullseye-hans - - - name: Run run_installation_tests_altuser.sh Bullseye ARMv7 - uses: tj-actions/docker-run@v2 - with: - image: rpi-jukebox-rfid-bullseye-altuser:latest - options: --platform linux/arm/v7 - name: run_installation_tests_altuser.sh - args: | - /code/scripts/installscripts/tests/run_installation_tests_altuser.sh - -# - name: Run run_installation_tests2_altuser.sh Bullseye ARMv7 -# uses: tj-actions/docker-run@v2 -# with: -# image: rpi-jukebox-rfid-bullseye-altuser:latest -# options: --platform linux/arm/v7 -# name: run_installation_tests2_altuser.sh -# args: | -# /code/scripts/installscripts/tests/run_installation_tests2_altuser.sh - - - name: Run run_installation_tests3_altuser.sh Bullseye ARMv7 - uses: tj-actions/docker-run@v2 - with: - image: rpi-jukebox-rfid-bullseye-altuser:latest - options: --platform linux/arm/v7 - name: run_installation_tests3_altuser.sh - args: | - /code/scripts/installscripts/tests/run_installation_tests3_altuser.sh - - - - - diff --git a/.github/workflows/docker_buster.yml b/.github/workflows/docker_buster.yml deleted file mode 100644 index dc96e441a..000000000 --- a/.github/workflows/docker_buster.yml +++ /dev/null @@ -1,64 +0,0 @@ -name: Test Install Scripts for Buster on Docker - -on: - schedule: - # run at 5 every sunday - - cron: '* 5 * * 0' - -jobs: - - build: - - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v3 - - - name: Set up QEMU - uses: docker/setup-qemu-action@v2.2.0 - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v2.10.0 - - - name: Build Buster ARMv7 - uses: docker/build-push-action@v4 - with: - context: . - load: true - push: false - file: ./ci/Dockerfile.buster.test_install.armv7 - platforms: linux/arm/v7 - tags: rpi-jukebox-rfid-buster:latest - cache-from: type=gha,scope=$GITHUB_REF_NAME-buster - cache-to: type=gha,mode=max,scope=$GITHUB_REF_NAME-buster - - - name: Run run_installation_tests.sh Buster ARMv7 - uses: tj-actions/docker-run@v2 - with: - image: rpi-jukebox-rfid-buster:latest - options: --platform linux/arm/v7 - name: run_installation_tests.sh - args: | - /code/scripts/installscripts/tests/run_installation_tests.sh - -# - name: Run run_installation_tests2.sh Buster ARMv7 -# uses: tj-actions/docker-run@v2 -# with: -# image: rpi-jukebox-rfid-buster:latest -# options: --platform linux/arm/v7 -# name: run_installation_tests2.sh -# args: | -# /code/scripts/installscripts/tests/run_installation_tests2.sh - - - name: Run run_installation_tests3.sh Buster ARMv7 - uses: tj-actions/docker-run@v2 - with: - image: rpi-jukebox-rfid-buster:latest - options: --platform linux/arm/v7 - name: run_installation_tests3.sh - args: | - /code/scripts/installscripts/tests/run_installation_tests3.sh - - - - diff --git a/.github/workflows/php.yml b/.github/workflows/php.yml index c9d2ad978..128334e9c 100644 --- a/.github/workflows/php.yml +++ b/.github/workflows/php.yml @@ -15,7 +15,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Setup PHP with XDebug uses: shivammathur/setup-php@v2 diff --git a/.github/workflows/pythonpackage.yml b/.github/workflows/pythonpackage.yml index 42a4632f8..9743408ac 100644 --- a/.github/workflows/pythonpackage.yml +++ b/.github/workflows/pythonpackage.yml @@ -18,7 +18,7 @@ jobs: python-version: ['3.7', '3.8', '3.9', '3.10', '3.11'] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v4 with: diff --git a/.github/workflows/pythonpackage_future3.yml b/.github/workflows/pythonpackage_future3.yml deleted file mode 100644 index cf5005fd2..000000000 --- a/.github/workflows/pythonpackage_future3.yml +++ /dev/null @@ -1,58 +0,0 @@ -name: Python + Docs Checks and Tests - -on: - push: - branches: - - 'future3/**' - paths: - - '**.py' - - '**.py.*' - - 'docs/sphinx/**' - pull_request: - branches: - - 'future3/**' - paths: - - '**.py' - - '**.py.*' - - 'docs/sphinx/**' - -jobs: - build: - - runs-on: ubuntu-latest - strategy: - max-parallel: 4 - matrix: - python-version: [3.7, 3.8] - - steps: - - uses: actions/checkout@v3 - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v4 - with: - python-version: ${{ matrix.python-version }} - - name: Install dependencies - run: | - sudo apt-get update - sudo apt-get install -y libasound2-dev - python -m pip install --upgrade pip - pip install wheel - pip install spidev - pip install -r requirements.txt - # For operation of the Jukebox, ZMQ must be compiled from sources due to Websocket support - # When just building the docs, the regular ZMQ package is sufficient - pip install -r docs/sphinx/requirements_pyzmq.txt - pip install -r docs/sphinx/requirements.txt - # Also install all optional dependencies - pip install -r src/jukebox/components/rfid/fake_reader_gui/requirements.txt - - name: Lint with flake8 - run: | - pip install flake8 - # Stop the build if linting fails - ./run_flake8.sh - - name: Build the docs - working-directory: ./docs/sphinx - run: | - # Stop the build if documentation cannot be built - # Treat all warnings as errors - sphinx-build -W --keep-going -T -a -E -b html . _build diff --git a/.github/workflows/test_docker_debian.yml b/.github/workflows/test_docker_debian.yml new file mode 100644 index 000000000..ab0b9ec8a --- /dev/null +++ b/.github/workflows/test_docker_debian.yml @@ -0,0 +1,37 @@ +name: Test Install Scripts Debian + +on: + schedule: + # run at 5:00 every sunday + - cron: '0 5 * * 0' + push: + branches-ignore: + - 'future3/**' + pull_request: + # The branches below must be a subset of the branches above + branches: [ develop ] + +# let only one instance run the test so cache is not corrupted. +# cancel already running instances as only the last run will be relevant +concurrency: + group: ${{ github.ref }}-test-debian + cancel-in-progress: true + +jobs: + + # Build container and run tests + run: + name: ${{ matrix.debian_version_name }} + strategy: + fail-fast: false + matrix: + debian_version_name: ['bullseye', 'buster'] + uses: ./.github/workflows/test_docker_debian_versionname_sub.yml + with: + runs_on: ubuntu-latest + platform: linux/arm/v7 + docker_image_name: rpi-jukebox-rfid + cache_scope: ${{ github.ref }}-test-debian + matrix_usernames: "['pi', 'hans']" + matrix_test_scripts: "['run_installation_tests.sh', 'run_installation_tests2.sh', 'run_installation_tests3.sh']" + debian_version_name: ${{ matrix.debian_version_name }} diff --git a/.github/workflows/test_docker_debian_versionname_sub.yml b/.github/workflows/test_docker_debian_versionname_sub.yml new file mode 100644 index 000000000..24be6ef74 --- /dev/null +++ b/.github/workflows/test_docker_debian_versionname_sub.yml @@ -0,0 +1,172 @@ +name: Subworkflow Test Install Scripts Debian + +on: + workflow_call: + inputs: + runs_on: + required: true + type: string + platform: + required: true + type: string + debian_version_name: + required: true + type: string + cache_scope: + required: true + type: string + docker_image_name: + required: true + type: string + matrix_usernames: + required: true + type: string + matrix_test_scripts: + required: true + type: string + local_registry_port: + required: false + type: number + default: 5000 + +# let only one instance run the test so cache is not corrupted. +# cancel already running instances as only the last run will be relevant +concurrency: + group: ${{ inputs.cache_scope }}-${{ inputs.debian_version_name }} + cancel-in-progress: true + +jobs: + + # Build container for test execution + build: + runs-on: ${{ inputs.runs_on }} + + outputs: + cache_key: ${{ steps.vars.outputs.cache_key }} + image_file_path: ${{ steps.vars.outputs.image_file_path }} + image_tag_name: ${{ steps.vars.outputs.image_tag_name }} + + # create local docker registry to use locally build images + services: + registry: + image: registry:2 + ports: + - ${{ inputs.local_registry_port }}:5000 + + steps: + - uses: actions/checkout@v4 + + - name: Set up QEMU + uses: docker/setup-qemu-action@v3.0.0 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3.0.0 + with: + # network=host driver-opt needed to push to local registry + driver-opts: network=host + + - name: Set Output pre-vars + id: pre-vars + env: + DEBIAN_VERSION_NAME: ${{ inputs.debian_version_name }} + DOCKER_IMAGE_NAME: ${{ inputs.docker_image_name }} + CACHE_SCOPE: ${{ inputs.cache_scope }} + run: | + echo "image_tag_name=${{ env.DOCKER_IMAGE_NAME }}:${{ env.DEBIAN_VERSION_NAME }}-test" >> $GITHUB_OUTPUT + echo "cache_scope=${{ env.CACHE_SCOPE }}-${{ env.DEBIAN_VERSION_NAME }}" >> $GITHUB_OUTPUT + + - name: Set Output vars + id: vars + env: + DEBIAN_VERSION_NAME: ${{ inputs.debian_version_name }} + DOCKER_IMAGE_NAME: ${{ inputs.docker_image_name }} + LOCAL_REGISTRY_PORT: ${{ inputs.local_registry_port }} + run: | + echo "image_tag_name=${{ steps.pre-vars.outputs.image_tag_name }}" >> $GITHUB_OUTPUT + echo "image_tag_name_local_base=localhost:${{ env.LOCAL_REGISTRY_PORT }}/${{ steps.pre-vars.outputs.image_tag_name }}-base" >> $GITHUB_OUTPUT + echo "image_file_path=./${{ env.DOCKER_IMAGE_NAME }}-${{ env.DEBIAN_VERSION_NAME }}.tar" >> $GITHUB_OUTPUT + echo "cache_scope=${{ steps.pre-vars.outputs.cache_scope }}" >> $GITHUB_OUTPUT + echo "cache_key=${{ steps.pre-vars.outputs.cache_scope }}-${{ github.sha }}#${{ github.run_attempt }}" >> $GITHUB_OUTPUT + + # 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 + with: + context: . + load: false + push: true + file: ./ci/Dockerfile.debian + target: test-code + platforms: ${{ inputs.platform }} + tags: ${{ steps.vars.outputs.image_tag_name_local_base }} + cache-from: type=gha,scope=${{ steps.vars.outputs.cache_scope }} + cache-to: type=gha,mode=max,scope=${{ steps.vars.outputs.cache_scope }} + build-args: | + DEBIAN_VERSION_NAME=${{ inputs.debian_version_name }} + GIT_BRANCH=${{ github.head_ref || github.ref_name }} + GIT_URL=${{ github.server_url }}/${{ github.event.pull_request.head.repo.full_name || github.repository }} + + # 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 + with: + context: . + load: false + push: false + file: ./ci/Dockerfile.debian + target: test-update + platforms: ${{ inputs.platform }} + tags: ${{ steps.vars.outputs.image_tag_name }} + cache-from: type=gha,scope=${{ steps.vars.outputs.cache_scope }} + # DON'T use 'cache-to' here as the layer is then cached and this build would be useless + outputs: type=docker,dest=${{ steps.vars.outputs.image_file_path }} + build-args: | + BASE_TEST_IMAGE=${{ steps.vars.outputs.image_tag_name_local_base }} + + # Cache image file for next jobs + - name: Cache Save Docker Image + uses: actions/cache/save@v3 + with: + key: ${{ steps.vars.outputs.cache_key }} + path: ${{ steps.vars.outputs.image_file_path }} + + + # Run tests with build image + test: + needs: [build] + runs-on: ${{ inputs.runs_on }} + + strategy: + fail-fast: false + matrix: + username: ${{ fromJSON(inputs.matrix_usernames) }} + test_script: ${{ fromJSON(inputs.matrix_test_scripts) }} + + steps: + - name: Set up QEMU + uses: docker/setup-qemu-action@v3.0.0 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3.0.0 + + # Load cached image file + - name: Cache Restore Docker Image + uses: actions/cache/restore@v3 + with: + key: ${{ needs.build.outputs.cache_key }} + path: ${{ needs.build.outputs.image_file_path }} + fail-on-cache-miss: true + + - name: Load Docker Image + run: | + docker load --input ${{ needs.build.outputs.image_file_path }} + + # Run test + - name: Run Test ${{ inputs.debian_version_name }}-${{ matrix.username }}-${{ matrix.test_script }} + uses: tj-actions/docker-run@v2 + with: + image: ${{ needs.build.outputs.image_tag_name }} + options: --platform ${{inputs.platform }} --user ${{ matrix.username }} + name: ${{ matrix.test_script }} + args: | + ./${{ matrix.test_script }} diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index 85f2622fd..dfd857be8 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -38,7 +38,7 @@ This Code of Conduct applies both within project spaces and in public spaces whe ## Enforcement -Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at micz.flor@web.de. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. +Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at . The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. diff --git a/README.md b/README.md index 7383c4391..8d444231e 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ ![GitHub last commit (branch)](https://img.shields.io/github/last-commit/MiczFlor/RPi-Jukebox-RFID/develop) -[![Python Checks and Tests](https://github.com/MiczFlor/RPi-Jukebox-RFID/actions/workflows/pythonpackage.yml/badge.svg)](https://github.com/MiczFlor/RPi-Jukebox-RFID/actions/workflows/pythonpackage.yml) [![Test Install Scripts for Bullseye on Docker](https://github.com/MiczFlor/RPi-Jukebox-RFID/actions/workflows/docker_bullseye.yml/badge.svg)](https://github.com/MiczFlor/RPi-Jukebox-RFID/actions/workflows/docker_bullseye.yml) [![CodeQL](https://github.com/MiczFlor/RPi-Jukebox-RFID/actions/workflows/codeql-analysis.yml/badge.svg)](https://github.com/MiczFlor/RPi-Jukebox-RFID/actions/workflows/codeql-analysis.yml) [![PHP Tests](https://github.com/MiczFlor/RPi-Jukebox-RFID/actions/workflows/php.yml/badge.svg)](https://github.com/MiczFlor/RPi-Jukebox-RFID/actions/workflows/php.yml) +[![Python Checks and Tests](https://github.com/MiczFlor/RPi-Jukebox-RFID/actions/workflows/pythonpackage.yml/badge.svg)](https://github.com/MiczFlor/RPi-Jukebox-RFID/actions/workflows/pythonpackage.yml) [![Test Install Scripts Debian](https://github.com/MiczFlor/RPi-Jukebox-RFID/actions/workflows/test_docker_debian.yml/badge.svg)](https://github.com/MiczFlor/RPi-Jukebox-RFID/actions/workflows/test_docker_debian.yml) [![CodeQL](https://github.com/MiczFlor/RPi-Jukebox-RFID/actions/workflows/codeql-analysis.yml/badge.svg)](https://github.com/MiczFlor/RPi-Jukebox-RFID/actions/workflows/codeql-analysis.yml) [![PHP Tests](https://github.com/MiczFlor/RPi-Jukebox-RFID/actions/workflows/php.yml/badge.svg)](https://github.com/MiczFlor/RPi-Jukebox-RFID/actions/workflows/php.yml) [![Coverage Status](https://coveralls.io/repos/github/MiczFlor/RPi-Jukebox-RFID/badge.svg?branch=develop)](https://coveralls.io/github/MiczFlor/RPi-Jukebox-RFID?branch=develop) @@ -229,7 +229,7 @@ Special hardware is now organised in the folder [`components`](components/). If If you like your Phoniebox, consider to [buy me a coffee](https://www.buymeacoffee.com/MiczFlor) -or donate via [PayPal](https://www.paypal.com) to micz.flor@web.de using the *friends* option. +or donate via [PayPal](https://www.paypal.com) to using the *friends* option. ## Media @@ -249,7 +249,7 @@ A new video screencast about **What makes this Phoniebox easy to install and use:** -* Runs on all Raspberry Pi models (1, 2 and 3) and [Raspberry Zero](https://github.com/MiczFlor/RPi-Jukebox-RFID/issues/15). (jump to the [install instructions](#install)) +* Runs on all Raspberry Pi models (1, 2 and 3) and [Raspberry Zero](https://github.com/MiczFlor/RPi-Jukebox-RFID/issues/15). * Just plug and play using USB, no soldering iron needed. * Once the Phoniebox is up and running, add music from any computer on your home network. * Register new RFID cards easily without having to connect to the RPi. diff --git a/ci/Dockerfile.bullseye.test_install.amd64 b/ci/Dockerfile.bullseye.test_install.amd64 deleted file mode 100644 index 09ce6fdcb..000000000 --- a/ci/Dockerfile.bullseye.test_install.amd64 +++ /dev/null @@ -1,34 +0,0 @@ -FROM debian:bullseye -ENV DOCKER_RUNNING=true - -COPY . /code -WORKDIR /code - -RUN groupadd --gid 1000 pi ;\ - useradd -u 1000 -g 1000 -G sudo -d /home/pi -m -s /bin/bash -p '$1$iV7TOwOe$6ojkJQXyEA9bHd/SqNLNj0' pi ;\ - chown -R 1000:1000 /code /home/pi ;\ - chmod +x /code/scripts/installscripts/buster-install-default.sh ;\ - chmod +x /code/scripts/installscripts/tests/run_installation_tests.sh ;\ - chmod +x /code/scripts/installscripts/tests/run_installation_tests2.sh ;\ - chmod +x /code/scripts/installscripts/tests/run_installation_tests3.sh - -RUN export DEBIAN_FRONTEND=noninteractive ;\ - apt-get update ;\ - apt-get -y install curl gnupg sudo nano systemd apt-utils;\ - echo 'deb http://raspbian.raspberrypi.org/raspbian/ bullseye main contrib non-free rpi' > /etc/apt/sources.list.d/raspi.list ;\ - echo 'deb http://archive.raspberrypi.org/debian/ bullseye main' >> /etc/apt/sources.list.d/raspi.list ;\ - curl http://raspbian.raspberrypi.org/raspbian.public.key | apt-key add - ;\ - curl http://archive.raspberrypi.org/debian/raspberrypi.gpg.key | apt-key add - ;\ - echo 'pi ALL=(ALL) NOPASSWD: ALL' > /etc/sudoers.d/pi ;\ - apt-get clean ;\ - rm -rf /var/cache/apt/* /var/lib/apt/lists/* - -RUN export DEBIAN_FRONTEND=noninteractive ;\ - apt-get update ;\ - apt-get -y dist-upgrade --auto-remove --purge ;\ - apt-get -y install wget build-essential git iw locales wpasupplicant;\ - apt-get clean ;\ - touch /boot/cmdlinetxt ;\ - rm -rf /var/cache/apt/* /var/lib/apt/lists/* - -USER pi diff --git a/ci/Dockerfile.bullseye.test_install.armv7 b/ci/Dockerfile.bullseye.test_install.armv7 deleted file mode 100644 index 8f1a591df..000000000 --- a/ci/Dockerfile.bullseye.test_install.armv7 +++ /dev/null @@ -1,39 +0,0 @@ -FROM --platform=linux/arm/v7 arm32v7/debian:bullseye-slim -ENV DOCKER_RUNNING=true - -COPY . /code -WORKDIR /code - -RUN groupadd --gid 1000 pi ;\ - useradd -u 1000 -g 1000 -G sudo -d /home/pi -m -s /bin/bash -p '$1$iV7TOwOe$6ojkJQXyEA9bHd/SqNLNj0' pi ;\ - chown -R 1000:1000 /code /home/pi ;\ - chmod +x /code/scripts/installscripts/buster-install-default.sh ;\ - chmod +x /code/scripts/installscripts/tests/run_installation_tests.sh ;\ - chmod +x /code/scripts/installscripts/tests/run_installation_tests2.sh ;\ - chmod +x /code/scripts/installscripts/tests/run_installation_tests3.sh - -RUN export DEBIAN_FRONTEND=noninteractive ;\ - apt-get update ;\ - apt-get -y install curl gnupg sudo nano systemd apt-utils;\ - echo 'deb http://raspbian.raspberrypi.org/raspbian/ bullseye main contrib non-free rpi' > /etc/apt/sources.list.d/raspi.list ;\ - echo 'deb http://archive.raspberrypi.org/debian/ bullseye main' >> /etc/apt/sources.list.d/raspi.list ;\ - curl http://raspbian.raspberrypi.org/raspbian.public.key | apt-key add - ;\ - curl http://archive.raspberrypi.org/debian/raspberrypi.gpg.key | apt-key add - ;\ - echo 'pi ALL=(ALL) NOPASSWD: ALL' > /etc/sudoers.d/pi ;\ - apt-get clean ;\ - rm -rf /var/cache/apt/* /var/lib/apt/lists/* - -RUN export DEBIAN_FRONTEND=noninteractive ;\ - apt-get update ;\ - # install here to speed up GitHub Action - apt-get -y install raspberrypi-kernel raspberrypi-kernel-headers;\ - apt-get -y dist-upgrade --auto-remove --purge ;\ - apt-get -y install wget build-essential git iw locales wpasupplicant;\ - apt-get clean ;\ - touch /boot/cmdlinetxt ;\ - rm -rf /var/cache/apt/* /var/lib/apt/lists/* - -USER pi - - - diff --git a/ci/Dockerfile.bullseye.test_install_altuser.armv7 b/ci/Dockerfile.bullseye.test_install_altuser.armv7 deleted file mode 100644 index 4aa67ada3..000000000 --- a/ci/Dockerfile.bullseye.test_install_altuser.armv7 +++ /dev/null @@ -1,36 +0,0 @@ -FROM --platform=linux/arm/v7 arm32v7/debian:bullseye-slim -ENV DOCKER_RUNNING=true - -COPY . /code -WORKDIR /code - -RUN groupadd --gid 1000 wurst ;\ - useradd -u 1000 -g 1000 -G sudo -d /home/hans -m -s /bin/bash -p '$1$iV7TOwOe$6ojkJQXyEA9bHd/SqNLNj0' hans ;\ - chown -R 1000:1000 /code /home/hans ;\ - chmod +x /code/scripts/installscripts/buster-install-default.sh ;\ - chmod +x /code/scripts/installscripts/tests/run_installation_tests_altuser.sh ;\ - chmod +x /code/scripts/installscripts/tests/run_installation_tests2_altuser.sh ;\ - chmod +x /code/scripts/installscripts/tests/run_installation_tests3_altuser.sh - -RUN export DEBIAN_FRONTEND=noninteractive ;\ - apt-get update ;\ - apt-get -y install curl gnupg sudo nano systemd apt-utils;\ - # install here to speed up GitHub Action - apt-get -y install raspberrypi-kernel-headers;\ - echo 'deb http://raspbian.raspberrypi.org/raspbian/ bullseye main contrib non-free rpi' > /etc/apt/sources.list.d/raspi.list ;\ - echo 'deb http://archive.raspberrypi.org/debian/ bullseye main' >> /etc/apt/sources.list.d/raspi.list ;\ - curl http://raspbian.raspberrypi.org/raspbian.public.key | apt-key add - ;\ - curl http://archive.raspberrypi.org/debian/raspberrypi.gpg.key | apt-key add - ;\ - echo 'hans ALL=(ALL) NOPASSWD: ALL' > /etc/sudoers.d/hans ;\ - apt-get clean ;\ - rm -rf /var/cache/apt/* /var/lib/apt/lists/* - -RUN export DEBIAN_FRONTEND=noninteractive ;\ - apt-get update ;\ - apt-get -y dist-upgrade --auto-remove --purge ;\ - apt-get -y install wget build-essential git iw locales wpasupplicant;\ - apt-get clean ;\ - touch /boot/cmdlinetxt ;\ - rm -rf /var/cache/apt/* /var/lib/apt/lists/* - -USER hans diff --git a/ci/Dockerfile.buster.amd64 b/ci/Dockerfile.buster.amd64 deleted file mode 100644 index 3aa9c5b27..000000000 --- a/ci/Dockerfile.buster.amd64 +++ /dev/null @@ -1,31 +0,0 @@ -FROM debian:buster -ENV DOCKER_RUNNING=true - -COPY . /code -WORKDIR /code - -RUN groupadd --gid 1000 pi ;\ - useradd -u 1000 -g 1000 -G sudo -d /home/pi -m -s /bin/bash -p '$1$iV7TOwOe$6ojkJQXyEA9bHd/SqNLNj0' pi ;\ - chown -R 1000:1000 /code /home/pi ;\ - chmod +x /code/scripts/installscripts/buster-install-default.sh - -RUN export DEBIAN_FRONTEND=noninteractive ;\ - apt-get update ;\ - apt-get -y install curl gnupg sudo nano;\ - echo 'deb http://raspbian.raspberrypi.org/raspbian/ buster main contrib non-free rpi' > /etc/apt/sources.list.d/raspi.list ;\ - echo 'deb http://archive.raspberrypi.org/debian/ buster main' >> /etc/apt/sources.list.d/raspi.list ;\ - curl http://raspbian.raspberrypi.org/raspbian.public.key | apt-key add - ;\ - curl http://archive.raspberrypi.org/debian/raspberrypi.gpg.key | apt-key add - ;\ - echo 'pi ALL=(ALL) NOPASSWD: ALL' > /etc/sudoers.d/pi ;\ - apt-get clean ;\ - rm -rf /var/cache/apt/* /var/lib/apt/lists/* - -RUN export DEBIAN_FRONTEND=noninteractive ;\ - apt-get update ;\ - apt-get -y dist-upgrade --auto-remove --purge ;\ - apt-get -y install wget build-essential git iw locales wpasupplicant;\ - apt-get clean ;\ - touch /boot/cmdline.txt /etc/sysctl.conf ;\ - rm -rf /var/cache/apt/* /var/lib/apt/lists/* - -USER pi diff --git a/ci/Dockerfile.buster.armv7 b/ci/Dockerfile.buster.armv7 deleted file mode 100644 index d03c5a734..000000000 --- a/ci/Dockerfile.buster.armv7 +++ /dev/null @@ -1,31 +0,0 @@ -FROM arm32v7/debian:buster-slim -ENV DOCKER_RUNNING=true - -COPY . /code -WORKDIR /code - -RUN groupadd --gid 1000 pi ;\ - useradd -u 1000 -g 1000 -G sudo -d /home/pi -m -s /bin/bash -p '$1$iV7TOwOe$6ojkJQXyEA9bHd/SqNLNj0' pi ;\ - chown -R 1000:1000 /code /home/pi ;\ - chmod +x /code/scripts/installscripts/buster-install-default.sh - -RUN export DEBIAN_FRONTEND=noninteractive ;\ - apt-get update ;\ - apt-get -y install curl gnupg sudo nano;\ - echo 'deb http://raspbian.raspberrypi.org/raspbian/ buster main contrib non-free rpi' >> /etc/apt/sources.list.d/raspi.list ;\ - echo 'deb http://archive.raspberrypi.org/debian/ buster main' > /etc/apt/sources.list.d/raspi.list ;\ - curl http://raspbian.raspberrypi.org/raspbian.public.key | apt-key add - ;\ - curl http://archive.raspberrypi.org/debian/raspberrypi.gpg.key | apt-key add - ;\ - echo 'pi ALL=(ALL) NOPASSWD: ALL' > /etc/sudoers.d/pi ;\ - apt-get clean ;\ - rm -rf /var/cache/apt/* /var/lib/apt/lists/* - -RUN export DEBIAN_FRONTEND=noninteractive ;\ - apt-get update ;\ - apt-get -y dist-upgrade --auto-remove --purge ;\ - apt-get -y install wget build-essential git iw locales wpasupplicant ;\ - apt-get clean ;\ - touch /boot/cmdline.txt /etc/sysctl.conf ;\ - rm -rf /var/cache/apt/* /var/lib/apt/lists/* - -USER pi diff --git a/ci/Dockerfile.buster.test_install.armv7 b/ci/Dockerfile.buster.test_install.armv7 deleted file mode 100644 index cd777a450..000000000 --- a/ci/Dockerfile.buster.test_install.armv7 +++ /dev/null @@ -1,36 +0,0 @@ -FROM --platform=linux/arm/v7 arm32v7/debian:buster-slim -ENV DOCKER_RUNNING=true - -COPY . /code -WORKDIR /code - -RUN groupadd --gid 1000 pi ;\ - useradd -u 1000 -g 1000 -G sudo -d /home/pi -m -s /bin/bash -p '$1$iV7TOwOe$6ojkJQXyEA9bHd/SqNLNj0' pi ;\ - chown -R 1000:1000 /code /home/pi ;\ - chmod +x /code/scripts/installscripts/buster-install-default.sh ;\ - chmod +x /code/scripts/installscripts/tests/run_installation_tests.sh ;\ - chmod +x /code/scripts/installscripts/tests/run_installation_tests2.sh ;\ - chmod +x /code/scripts/installscripts/tests/run_installation_tests3.sh - -RUN export DEBIAN_FRONTEND=noninteractive ;\ - apt-get update ;\ - apt-get -y install curl gnupg sudo nano systemd apt-utils;\ - # install here to speed up GitHub Action - apt-get -y install raspberrypi-kernel-headers;\ - echo 'deb http://raspbian.raspberrypi.org/raspbian/ buster main contrib non-free rpi' > /etc/apt/sources.list.d/raspi.list ;\ - echo 'deb http://archive.raspberrypi.org/debian/ buster main' >> /etc/apt/sources.list.d/raspi.list ;\ - curl http://raspbian.raspberrypi.org/raspbian.public.key | apt-key add - ;\ - curl http://archive.raspberrypi.org/debian/raspberrypi.gpg.key | apt-key add - ;\ - echo 'pi ALL=(ALL) NOPASSWD: ALL' > /etc/sudoers.d/pi ;\ - apt-get clean ;\ - rm -rf /var/cache/apt/* /var/lib/apt/lists/* - -RUN export DEBIAN_FRONTEND=noninteractive ;\ - apt-get update ;\ - apt-get -y dist-upgrade --auto-remove --purge ;\ - apt-get -y install wget build-essential git iw locales wpasupplicant;\ - apt-get clean ;\ - touch /boot/cmdlinetxt ;\ - rm -rf /var/cache/apt/* /var/lib/apt/lists/* - -USER pi diff --git a/ci/Dockerfile.debian b/ci/Dockerfile.debian new file mode 100644 index 000000000..ecfca4460 --- /dev/null +++ b/ci/Dockerfile.debian @@ -0,0 +1,101 @@ +# Base Target to build and install all needed base configuration and packages. Specifie the needed platform with the docker '--platform XXX' option +ARG DEBIAN_VERSION_NAME=bullseye +ARG BASE_TEST_IMAGE=test-code +FROM debian:${DEBIAN_VERSION_NAME}-slim as base +ARG DEBIAN_VERSION_NAME + +ENV DOCKER_RUNNING=true +RUN touch /boot/cmdlinetxt + +RUN export DEBIAN_FRONTEND=noninteractive \ + && apt-get update \ + && apt-get -y install \ + apt-utils \ + curl \ + gnupg \ + && curl -fsSL http://raspbian.raspberrypi.org/raspbian.public.key | gpg --dearmor > /usr/share/keyrings/raspberrypi-raspbian-keyring.gpg \ + && curl -fsSL http://archive.raspberrypi.org/debian/raspberrypi.gpg.key | gpg --dearmor > /usr/share/keyrings/raspberrypi-archive-debian-keyring.gpg \ + && echo "deb [signed-by=/usr/share/keyrings/raspberrypi-raspbian-keyring.gpg] http://raspbian.raspberrypi.org/raspbian/ ${DEBIAN_VERSION_NAME} main contrib non-free rpi" > /etc/apt/sources.list.d/raspi.list \ + && echo "deb [signed-by=/usr/share/keyrings/raspberrypi-archive-debian-keyring.gpg] http://archive.raspberrypi.org/debian/ ${DEBIAN_VERSION_NAME} main" >> /etc/apt/sources.list.d/raspi.list \ + && apt-get update \ + && apt-get -y upgrade \ + && apt-get -y install \ + build-essential \ + git \ + iw \ + locales \ + sudo \ + systemd \ + wget \ + wpasupplicant \ + # install internally used packages here to speed up GitHub Action + raspberrypi-kernel \ + raspberrypi-kernel-headers \ + && rm -rf /var/lib/apt/lists/* +# ------ + +# Base Target for setting up the default user. user can be selected with the docker '--user YYY' option +FROM base as user +ARG USER=pi +ARG USER_GROUP=$USER + +ENV USER=$USER USER_GROUP=$USER_GROUP + +RUN groupadd --gid 1000 $USER_GROUP \ + && useradd -u 1000 -g $USER_GROUP -G sudo -d /home/$USER -m -s /bin/bash -p '$1$iV7TOwOe$6ojkJQXyEA9bHd/SqNLNj0' $USER \ + && echo "$USER ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers.d/$USER +# ------ + + + +####### Code Targets ####### + +# Target for adding code from the repo. Set Default User +FROM user as code + +COPY --chown=$USER:$USER_GROUP --chmod=770 . /code +WORKDIR /code + +USER $USER +# ------ + + + +####### Test Targets ####### + +# Target for setting up an alternativ user 'hans:wurst'. user can be selected with the docker '--user YYY' option +FROM user as test-user + +ENV TEST_USER_GROUP=test + +RUN groupadd --gid 1002 $TEST_USER_GROUP \ + && usermod -a -G $TEST_USER_GROUP $USER + +RUN export USER_ALT=hans \ + && export USER_ALT_GROUP=wurst \ + && groupadd --gid 1001 $USER_ALT_GROUP \ + && useradd -u 1001 -g $USER_ALT_GROUP -G sudo,$TEST_USER_GROUP -d /home/$USER_ALT -m -s /bin/bash -p '$1$iV7TOwOe$6ojkJQXyEA9bHd/SqNLNj0' $USER_ALT \ + && echo "$USER_ALT ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers.d/$USER_ALT +# ------ + + +# Target for adding envs and scripts from the repo to test installation +FROM test-user as test-code +ARG GIT_BRANCH +ARG GIT_URL + +ENV GIT_BRANCH=$GIT_BRANCH GIT_URL=$GIT_URL + +COPY --chown=root:$TEST_USER_GROUP --chmod=770 scripts/installscripts/buster-install-default.sh . +WORKDIR /tests +COPY --chown=root:$TEST_USER_GROUP --chmod=770 scripts/installscripts/tests/*.sh . +# ------ + + +# Target for applying latest updates (should not be cached!) +FROM $BASE_TEST_IMAGE as test-update +RUN export DEBIAN_FRONTEND=noninteractive \ + && apt-get update \ + && apt-get -y upgrade \ + && rm -rf /var/lib/apt/lists/* +# ------ diff --git a/ci/README.md b/ci/README.md index 867fe1607..4ed2910e7 100644 --- a/ci/README.md +++ b/ci/README.md @@ -19,28 +19,33 @@ This is a work in progress so expect things to fail or being flaky. sudo reboot ``` * login to your RPi -* clone this repo and cd into its local clone: +* clone the repo and cd into its local clone: ```bash + cd /home/pi/ + # optional: change to your fork appropriately git clone https://github.com/MiczFlor/RPi-Jukebox-RFID.git - cd /home/pi/RPi-Jukebox-RFID/ + cd RPi-Jukebox-RFID/ + # optional: switch to another branch + git checkout ``` * build the docker image: - * **on normal PCs:** - ```bash - docker build -t rpi-jukebox-rfid-buster:latest -f ci/Dockerfile.buster.amd64 . - ``` + ```bash + docker build -t rpi-jukebox-rfid:buster-latest -f ci/Dockerfile.debian --platform=linux/arm/v7 --target=code --build-arg="DEBIAN_VERSION_NAME=buster" . + ``` + * 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 change `--build-arg="DEBIAN_VERSION_NAME=buster"` appropriately. - * **on a raspberry pi:** - ```bash - docker build -t rpi-jukebox-rfid-buster:latest -f ci/Dockerfile.buster.armv7 . - ``` * 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-buster:latest /bin/bash + docker run --rm -ti rpi-jukebox-rfid:buster-latest /bin/bash cd /home/pi/ cp /code/scripts/installscripts/buster-install-default.sh /home/pi/ - bash buster-install-default.sh + # set GIT_URL and GIT_BRANCH appropriately to your checkout + bash GIT_URL=https://github.com/MiczFlor/RPi-Jukebox-RFID.git GIT_BRANCH=main buster-install-default.sh ``` NOTE: Get familiar with docker and its flags - `--rm` for example will remove the @@ -48,19 +53,7 @@ This is a work in progress so expect things to fail or being flaky. ### 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: - -```bash - git clone https://github.com/MiczFlor/RPi-Jukebox-RFID.git - cd /home/pi/RPi-Jukebox-RFID/ - docker build -t rpi-jukebox-rfid-buster:latest -f ci/Dockerfile . - docker run --rm -ti -w /code -v $PWD:/code rpi-jukebox-rfid-buster:latest /bin/bash - - cd /home/pi/ - cp /code/scripts/installscripts/buster-install-default.sh /home/pi/ - bash buster-install-default.sh -``` +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/audio/PirateAudioHAT/README.md b/components/audio/PirateAudioHAT/README.md index 3450dd120..82a02396b 100644 --- a/components/audio/PirateAudioHAT/README.md +++ b/components/audio/PirateAudioHAT/README.md @@ -80,8 +80,8 @@ NOTE: changes to the installation should find their way into the script `setup_p enabled = true display = st7789 ``` - **Attention:** Early revisions of PirateAudio HAT used bcm20 for Volume up, later revisions use bcm24. see also https://github.com/pimoroni/pirate-audio/issues/63#issuecomment-916860634 - + + **Attention:** Early revisions of PirateAudio HAT used bcm20 for Volume up, later revisions use bcm24. see also 12. Enable access for modipy user `sudo usermod -a -G spi,i2c,gpio,video mopidy` diff --git a/components/bluetooth-sink-switch/README.md b/components/bluetooth-sink-switch/README.md index 16fabde10..5f216ebc7 100644 --- a/components/bluetooth-sink-switch/README.md +++ b/components/bluetooth-sink-switch/README.md @@ -4,7 +4,7 @@ This component provides a mechanism to toggle between both audio sinks through all the usual user interfaces (i.e. GPIO, RFID Card Swipe, Web Interface). The current status is reflected in the Web Interface and through an optional LED. -**Convinced? So, what is the vision?** +## Convinced? So, what is the vision? When a user powers on their Bluetooth headphones, they connect automatically to the Phoniebox. At the switch of the button (or card swipe, etc) the (already running) audio playback is transferred from the speakers to the headphones. This happens almost seamlessly. Parents feel an instant wave of relief at not having to listen to the 500th iteration of this month favourite song. The small user feels instantly proud at having working headphones much like the mom/dad always uses while doing home-office online meetings. If no Bluetooth headphones are connected, the audio sink toggle request defaults to speakers. An LED indicates the currently active audio sink. @@ -14,15 +14,15 @@ If no bluetooth device is connected, the output defaults back to speakers. After ![Web Interface Add-on in settings.php](webif.png "Web Interface Add-on in settings.php") -**Limitations** +### Limitations This feature only works for the *Classic* Edition. Why? It relies on the mpd multiple output channels feature to switch between outputs. This is no available in mopidy, which is used in the Spotify Edition. -### Installation +## Installation This looks lengthy, but I the major deal is setting up your audio output devices. I have been rather explicit to avoid confusion. -#### Step 1) Setting up asound.conf +### Step 1) Setting up asound.conf You need to set up both audio sinks and make sure they work. This is pretty much a prerequisite for everything that follows. @@ -58,7 +58,7 @@ $ aplay -D btheadphone /usr/share/sounds/alsa/Front_Center.wav $ aplay -D hifiberry /usr/share/sounds/alsa/Front_Center.wav ~~~ -#### Step 2) Setting up mpd.conf +### Step 2) Setting up mpd.conf You need to set up two audio_output sections. **The order is important**: the first entry must relate to the soundcard setup, the second entry must relate to the bluetooth setup. Give meaningful names, as they will show up in the Web Interface. @@ -98,7 +98,7 @@ Output 2 (Gesas Headphones) is enabled You may switch with `$ mpc enable only 1` and `$ mpc enable only 2`. Play some music and use these commands to check you mpd configuration. You should be able to switch the audio output between the two devices. -#### Step 3) Run the installer +### Step 3) Run the installer This sets up the appropriate user rights and registers the component with global settings etc. @@ -107,9 +107,9 @@ $ cd components/bluetooth-sink-switch $ ./install-bt-sink-switch.sh ~~~ -#### Step 4) Fine-tuning +### Step 4) Fine-tuning -**Status LED** +#### Status LED An optional status LED will be turned on if the audio sink is set to bluetooth. If a toggle command is issued, but no bluetooth device is connected, the LED will blink three times. Looks very neat, if you have a button with integrated LED. Add these lines to your `RPi-Jukebox-RFID/settings/gpio_settings.ini`, to use GPIO 13 as LED signal. It is `led_pin` the BCM number of the GPIO pin (i.e. 'led_pin = 13' means GPIO13) and defaults to None. Create the file, if it does not exist. @@ -121,7 +121,7 @@ enabled: True led_pin: 13 ~~~ -**GPIO control** +#### GPIO control If you want to toggle from a GPIO button (e.g. on GPIO5), add these lines to your `RPi-Jukebox-RFID/settings/gpio_settings.ini`. Create it, if it does not exist. @@ -135,7 +135,7 @@ hold_time: 0.3 functionCall: functionCallBluetoothToggle ~~~ -**RFID Card** +#### RFID Card If you want to toggle by RFID card swipe, set the card id in `rfid_trigger_play.conf`, e.g.: @@ -144,7 +144,7 @@ If you want to toggle by RFID card swipe, set the card id in `rfid_trigger_play. CMDBLUETOOTHTOGGLE="1364237231134" ~~~ -**Volume attenuation** +#### Volume attenuation Speakers and Headphones can have very different maximum volume levels. This sometimes leads to very strong volume level changes when switching between speakers and headphones. Restricting the maximum volume with the Phoniebox-integrated max-volume setting does no yield the desired effect, as this is a single setting and does not differentiate between different audio sinks. diff --git a/components/controls/buttons_usb_encoder/README.md b/components/controls/buttons_usb_encoder/README.md index 7a74cb01d..586850e8a 100644 --- a/components/controls/buttons_usb_encoder/README.md +++ b/components/controls/buttons_usb_encoder/README.md @@ -16,39 +16,38 @@ Tested Devices: 2. Navigate to your RPi-Jukebox home directory and run the script `setup-buttons-usb-encoder.sh` to set up your USB Encoder. Then choose the device and map the buttons. `cd ~/RPi-Jukebox-RFID` - + `./components/controls/buttons_usb_encoder/setup-buttons-usb-encoder.sh` - + If you make a mistake at the first install you can "remap" the buttons: -- Stop the service: `sudo systemctl stop phoniebox-buttons-usb-encoder.service` -- Run the installation script again: `./components/controls/buttons_usb_encoder/setup-buttons-usb-encoder.sh` -- Restart the service: `sudo systemctl start phoniebox-buttons-usb-encoder.service` +* Stop the service: `sudo systemctl stop phoniebox-buttons-usb-encoder.service` +* Run the installation script again: `./components/controls/buttons_usb_encoder/setup-buttons-usb-encoder.sh` +* Restart the service: `sudo systemctl start phoniebox-buttons-usb-encoder.service` ### Possible Button Mappings -- 'BluetoothToggle': Turn bluetooth on or off -- 'PlayerNext': Play Next -- 'PlayerPause': Pause -- 'PlayerPauseForce': Force Pause? -- 'PlayerPrev': Previous track -- 'PlayerRandomCard': Activate (play?) random card? -- 'PlayerRandomFolder': Play random folder -- 'PlayerRandomTrack': Play random track -- 'PlayerSeekBack': Seek backwards on playing track (x seconds) -- 'PlayerSeekFarBack': Seek backwards on playing track (x seconds) -- 'PlayerSeekFarFwd': Seek forwards on playing track (x seconds) -- 'PlayerSeekFwd': Seek forwards on playing track (x seconds) -- 'PlayerStop': Stop playing -- 'RecordPlayLatest': Play latest recording -- 'RecordStart': Start recording -- 'RecordStop': Stop recording -- 'Shutdown': Shut down the Phoniebox -- 'ToggleWifi': Turn Wifi on or off -- 'Vol0': Volume mute? -- 'VolD': Volume down -- 'VolU': Volume up - +* 'BluetoothToggle': Turn bluetooth on or off +* 'PlayerNext': Play Next +* 'PlayerPause': Pause +* 'PlayerPauseForce': Force Pause? +* 'PlayerPrev': Previous track +* 'PlayerRandomCard': Activate (play?) random card? +* 'PlayerRandomFolder': Play random folder +* 'PlayerRandomTrack': Play random track +* 'PlayerSeekBack': Seek backwards on playing track (x seconds) +* 'PlayerSeekFarBack': Seek backwards on playing track (x seconds) +* 'PlayerSeekFarFwd': Seek forwards on playing track (x seconds) +* 'PlayerSeekFwd': Seek forwards on playing track (x seconds) +* 'PlayerStop': Stop playing +* 'RecordPlayLatest': Play latest recording +* 'RecordStart': Start recording +* 'RecordStop': Stop recording +* 'Shutdown': Shut down the Phoniebox +* 'ToggleWifi': Turn Wifi on or off +* 'Vol0': Volume mute? +* 'VolD': Volume down +* 'VolU': Volume up ## Schematics @@ -56,10 +55,5 @@ If you make a mistake at the first install you can "remap" the buttons: ## Issues & Discussions -- https://github.com/MiczFlor/RPi-Jukebox-RFID/issues/1156 -- https://github.com/MiczFlor/RPi-Jukebox-RFID/discussions/2013 - - - - - +* +* diff --git a/components/controls/buttons_usb_encoder/buttons_usb_encoder.py b/components/controls/buttons_usb_encoder/buttons_usb_encoder.py index e5b56acfb..33d13657c 100644 --- a/components/controls/buttons_usb_encoder/buttons_usb_encoder.py +++ b/components/controls/buttons_usb_encoder/buttons_usb_encoder.py @@ -2,7 +2,7 @@ import sys -sys.path.append(".") # This command should be before imports of components +sys.path.append(".") # This command should be before imports of components import logging from evdev import categorize, ecodes, KeyEvent 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 40b094135..6cf0bcb28 100644 --- a/components/controls/buttons_usb_encoder/map_buttons_usb_encoder.py +++ b/components/controls/buttons_usb_encoder/map_buttons_usb_encoder.py @@ -2,7 +2,7 @@ import sys -sys.path.append(".") # This command should be before imports of components +sys.path.append(".") # This command should be before imports of components from evdev import categorize, ecodes, KeyEvent from io_buttons_usb_encoder import current_device, write_button_map diff --git a/components/displays/HD44780-i2c/README.md b/components/displays/HD44780-i2c/README.md index 17b6a719a..fce87d0c4 100755 --- a/components/displays/HD44780-i2c/README.md +++ b/components/displays/HD44780-i2c/README.md @@ -5,17 +5,17 @@ The following files allow using LCD displays based on HD44780 connected via i2c bus for this project. The following displays have been used for testing: -- 2x16 display -- 4x20 display (recommended as more information can be displayed) +* 2x16 display +* 4x20 display (recommended as more information can be displayed) Various informations such as artist, album, track_number, track_title, track_time and many more can be displayed see main script for more display options. The required files are: -- components/displays/HD44780-i2c/i2c_lcd.py -- components/displays/HD44780-i2c/i2c_lcd_driver.py -- components/displays/HD44780-i2c/i2c-lcd.service.default.sample -- components/displays/HD44780-i2c/README.md +* components/displays/HD44780-i2c/i2c_lcd.py +* components/displays/HD44780-i2c/i2c_lcd_driver.py +* components/displays/HD44780-i2c/i2c-lcd.service.default.sample +* components/displays/HD44780-i2c/README.md The first file is the main LCD script that makes use of I2C_LCD_driver.py. @@ -25,7 +25,7 @@ The third is used as sample service file that runs the i2c_lcd.py main script at The fourth file is this file which describes the features, usage and installation of the code. -### Installation +## Installation * You need to install additional python libraries. Run the following two command in the command line: diff --git a/components/displays/HD44780-i2c/i2c_lcd_driver.py b/components/displays/HD44780-i2c/i2c_lcd_driver.py index bbf5b5090..d9c244e79 100755 --- a/components/displays/HD44780-i2c/i2c_lcd_driver.py +++ b/components/displays/HD44780-i2c/i2c_lcd_driver.py @@ -25,6 +25,7 @@ import smbus from time import sleep + class i2c_device: def __init__(self, addr, port=I2CBUS): self.addr = addr @@ -100,12 +101,13 @@ def read_block_data(self, cmd): LCD_BACKLIGHT = 0x08 LCD_NOBACKLIGHT = 0x00 -En = 0b00000100 # Enable bit -Rw = 0b00000010 # Read/Write bit -Rs = 0b00000001 # Register select bit +En = 0b00000100 # Enable bit +Rw = 0b00000010 # Read/Write bit +Rs = 0b00000001 # Register select bit + class lcd: - #initializes objects and lcd + # initializes objects and lcd def __init__(self): self.lcd_device = i2c_device(ADDRESS) @@ -120,7 +122,6 @@ def __init__(self): self.lcd_write(LCD_ENTRYMODESET | LCD_ENTRYLEFT) sleep(0.2) - # clocks EN to latch command def lcd_strobe(self, data): self.lcd_device.write_cmd(data | En | LCD_BACKLIGHT) @@ -165,7 +166,7 @@ def lcd_clear(self): self.lcd_write(LCD_RETURNHOME) # define backlight on/off (lcd.backlight(1); off= lcd.backlight(0) - def backlight(self, state): # for state, 1 = on, 0 = off + def backlight(self, state): # for state, 1 = on, 0 = off if state == 1: self.lcd_device.write_cmd(LCD_BACKLIGHT) elif state == 0: @@ -173,8 +174,7 @@ def backlight(self, state): # for state, 1 = on, 0 = off # add custom characters (0 - 7) def lcd_load_custom_chars(self, fontdata): - self.lcd_write(0x40); + self.lcd_write(0x40) for char in fontdata: for line in char: self.lcd_write_char(line) - diff --git a/components/gpio_control/GPIODevices/led.py b/components/gpio_control/GPIODevices/led.py index aff6dbc45..01d2d34ef 100644 --- a/components/gpio_control/GPIODevices/led.py +++ b/components/gpio_control/GPIODevices/led.py @@ -41,4 +41,3 @@ def __init__(self, pin, name='StatusLED'): time.sleep(1) self.logger.info('phoniebox-startup-scripts service active') self.on() - diff --git a/components/gpio_control/GPIODevices/shutdown_button.py b/components/gpio_control/GPIODevices/shutdown_button.py index ee8cb1e98..3f9eec341 100644 --- a/components/gpio_control/GPIODevices/shutdown_button.py +++ b/components/gpio_control/GPIODevices/shutdown_button.py @@ -34,30 +34,30 @@ def set_led(self, status): logger.debug('cannot set LED to {}: no LED pin defined'.format(status)) def callbackFunctionHandler(self, *args): - if self.is_pressed: # Should not be necessary, but handler gets called on rising edge too - logger.debug('ShutdownButton pressed, ensuring long press for {} seconds, checking each {}s'.format( - self.hold_time, self.iteration_time - )) - t_passed = 0 - led_state = True - while t_passed < self.hold_time: - self.set_led(led_state) - time.sleep(self.iteration_time) - t_passed += self.iteration_time - led_state = not led_state - if not self.is_pressed: - break - if t_passed >= self.hold_time: - # trippel off period to indicate command accepted - self.set_led(GPIO.HIGH) - time.sleep(.6) - # leave it on for the moment, it will be off when the system is down - self.when_pressed(*args) - else: - # switch off LED if pressing was cancelled early (during flashing) - self.set_led(GPIO.LOW) + if self.is_pressed: # Should not be necessary, but handler gets called on rising edge too + logger.debug('ShutdownButton pressed, ensuring long press for {} seconds, checking each {}s'.format( + self.hold_time, self.iteration_time + )) + t_passed = 0 + led_state = True + while t_passed < self.hold_time: + self.set_led(led_state) + time.sleep(self.iteration_time) + t_passed += self.iteration_time + led_state = not led_state + if not self.is_pressed: + break + if t_passed >= self.hold_time: + # trippel off period to indicate command accepted + self.set_led(GPIO.HIGH) + time.sleep(.6) + # leave it on for the moment, it will be off when the system is down + self.when_pressed(*args) + else: + # switch off LED if pressing was cancelled early (during flashing) + self.set_led(GPIO.LOW) def __repr__(self): return ''.format( - self.name, self.pin, self.hold_time, self.iteration_time, self.led_pin, print_edge_key(self.edge), self.bouncetime,self.antibouncehack, print_pull_up_down(self.pull_up_down) + self.name, self.pin, self.hold_time, self.iteration_time, self.led_pin, print_edge_key(self.edge), self.bouncetime, self.antibouncehack, print_pull_up_down(self.pull_up_down) ) diff --git a/components/gpio_control/GPIODevices/simple_button.py b/components/gpio_control/GPIODevices/simple_button.py index 69b6e3407..4b7149e7e 100644 --- a/components/gpio_control/GPIODevices/simple_button.py +++ b/components/gpio_control/GPIODevices/simple_button.py @@ -6,10 +6,11 @@ logger = logging.getLogger(__name__) -map_edge_parse = {'falling':GPIO.FALLING, 'rising':GPIO.RISING, 'both':GPIO.BOTH} -map_pull_parse = {'pull_up':GPIO.PUD_UP, 'pull_down':GPIO.PUD_DOWN, 'pull_off':GPIO.PUD_OFF} +map_edge_parse = {'falling': GPIO.FALLING, 'rising': GPIO.RISING, 'both': GPIO.BOTH} +map_pull_parse = {'pull_up': GPIO.PUD_UP, 'pull_down': GPIO.PUD_DOWN, 'pull_off': GPIO.PUD_OFF} map_edge_print = {GPIO.FALLING: 'falling', GPIO.RISING: 'rising', GPIO.BOTH: 'both'} -map_pull_print = {GPIO.PUD_UP:'pull_up', GPIO.PUD_DOWN: 'pull_down', GPIO.PUD_OFF: 'pull_off'} +map_pull_print = {GPIO.PUD_UP: 'pull_up', GPIO.PUD_DOWN: 'pull_down', GPIO.PUD_OFF: 'pull_off'} + def parse_edge_key(edge): if edge in [GPIO.FALLING, GPIO.RISING, GPIO.BOTH]: @@ -21,6 +22,7 @@ def parse_edge_key(edge): raise KeyError('Unknown Edge type {edge}'.format(edge=edge)) return result + def parse_pull_up_down(pull_up_down): if pull_up_down in [GPIO.PUD_UP, GPIO.PUD_DOWN, GPIO.PUD_OFF]: return pull_up_down @@ -31,6 +33,7 @@ def parse_pull_up_down(pull_up_down): raise KeyError('Unknown Pull Up/Down type {pull_up_down}'.format(pull_up_down=pull_up_down)) return result + def print_edge_key(edge): try: result = map_edge_print[edge] @@ -38,6 +41,7 @@ def print_edge_key(edge): result = edge return result + def print_pull_up_down(pull_up_down): try: result = map_pull_print[pull_up_down] @@ -45,6 +49,7 @@ def print_pull_up_down(pull_up_down): result = pull_up_down return result + # This function takes a holding time (fractional seconds), a channel, a GPIO state and an action reference (function). # It checks if the GPIO is in the state since the function was called. If the state # changes it return False. If the time is over the function returns True. @@ -93,7 +98,7 @@ def callbackFunctionHandler(self, *args): args = args[1:] logger.debug('args after: {}'.format(args)) - if self.antibouncehack: + if self.antibouncehack: time.sleep(0.1) inval = GPIO.input(self.pin) if inval != GPIO.LOW: @@ -132,32 +137,32 @@ def longPressHandler(self, *args): # instant action (except Postpone mode) if self.hold_mode != "Postpone": self.when_pressed(*args) - + # action(s) after hold_time if self.hold_mode == "Repeat": # Repeated call of main action (multiple times 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) if checkGpioStaysInState(self.hold_time, self.pin, GPIO.LOW): self.when_pressed(*args) while checkGpioStaysInState(self.hold_time, self.pin, GPIO.LOW): pass - + elif self.hold_mode == "SecondFunc": # Call of secondary action (once) if checkGpioStaysInState(self.hold_time, self.pin, GPIO.LOW): self.when_held(*args) while checkGpioStaysInState(self.hold_time, self.pin, GPIO.LOW): pass - + 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): self.when_held(*args) - + def __del__(self): logger.debug('remove event detection') GPIO.remove_event_detect(self.pin) @@ -170,7 +175,7 @@ def is_pressed(self): def __repr__(self): return ''.format( - self.name, self.pin, print_edge_key(self.edge), self.hold_mode, self.hold_time, self.bouncetime,self.antibouncehack,print_pull_up_down(self.pull_up_down) + self.name, self.pin, print_edge_key(self.edge), self.hold_mode, self.hold_time, self.bouncetime, self.antibouncehack, print_pull_up_down(self.pull_up_down) ) diff --git a/components/gpio_control/GPIODevices/two_button_control.py b/components/gpio_control/GPIODevices/two_button_control.py index d4ceb0a11..e93584cd1 100644 --- a/components/gpio_control/GPIODevices/two_button_control.py +++ b/components/gpio_control/GPIODevices/two_button_control.py @@ -63,20 +63,20 @@ def __init__(self, hold_mode=None, hold_time=0.3, bouncetime=500, - antibouncehack=False, - edge='falling', + antibouncehack=False, + edge='falling', name='TwoButtonControl'): self.bcmPin1 = bcmPin1 self.bcmPin2 = bcmPin2 self.functionCallBtn1 = functionCallBtn1 self.functionCallBtn2 = functionCallBtn2 self.functionCallTwoBtns = functionCallTwoBtns - self.pull_up_down=pull_up_down - self.hold_mode=hold_mode - self.hold_time=hold_time - self.bouncetime=bouncetime - self.antibouncehack=antibouncehack - self.edge=edge + self.pull_up_down = pull_up_down + self.hold_mode = hold_mode + self.hold_time = hold_time + self.bouncetime = bouncetime + self.antibouncehack = antibouncehack + self.edge = edge self.btn1 = SimpleButton( pin=bcmPin1, name=name + 'Btn1', diff --git a/components/gpio_control/README.md b/components/gpio_control/README.md index 0c92ca6f5..229d120a8 100644 --- a/components/gpio_control/README.md +++ b/components/gpio_control/README.md @@ -38,11 +38,11 @@ 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 +## 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`. -## Button +### Button At the most basic level, a button can be created using an `ini` entry like this: @@ -86,7 +86,7 @@ However, a button has more parameters than these. In the following comprehensive Note: If you prefer, you may also use `Type: SimpleButton` instead of `Type: Button` - this makes no difference. -## ShutdownButton +### ShutdownButton An extended ShutdownButton can be created using an `ini` entry like these: @@ -127,9 +127,9 @@ hold_time: 3.0 functionCall: functionCallShutdown ``` -## TwoButtonControl +### TwoButtonControl -A TwoButtonControl can be created using an `ini` entry like this: +A TwoButtonControl can be created using an `ini` entry like this: ```bash [PrevNextStop] @@ -163,9 +163,9 @@ In this example, the volume will be in-/decreased step-wise using intervals of 0 Furthermore, the following settings can be used as described for the [regular buttons](#doc_button): **pull_up_down**, **edge**, **bouncetime**, **antibouncehack** -## RotaryEncoder +### RotaryEncoder -A RotaryEncoder can be created using an `ini` entry like this: +A RotaryEncoder can be created using an `ini` entry like this: ```bash [VolumeControl] @@ -181,9 +181,9 @@ functionCall2: functionCallVolD Pin1 and FunctionCall1 correspond to rotary direction "up", while Pin2 and FunctionCall2 correspond to "down". Note that the old configuration entries PinUp/PinDown and functionCallUp/functionCallDown are deprecated and might stop working in future. -## StatusLED +### StatusLED -A StatusLED can be created using an `ini` entry like this: +A StatusLED can be created using an `ini` entry like this: ```bash [StatusLED] @@ -196,11 +196,11 @@ Pin: 14 Note: If you prefer, you may also use `Type: MPDStatusLED` instead of `Type: StatusLED` - this makes no difference. -## Further examples +### Further examples By tapping the potential of the features presented above, you can create buttons like this: -### Play random tracks or folders +#### Play random tracks or folders If you have buttons to navigate to the next/previous track it might be a good idea to define that holding these buttons for a certain time (e.g. 2 seconds) will activate a random (surpise!) track or even folder/card. This might look like this @@ -226,7 +226,7 @@ functionCall: functionCallPlayerPrev functionCall2: functionCallPlayerRandomFolder ``` -### Short and long jumps +#### Short and long jumps If you are using two buttons to jump backwards or forwards within the current track, you can use the repeated hold action to allow larger jumps: @@ -245,7 +245,7 @@ functionCall2: functionCallPlayerSeekFarFwd In this example, a short press initiates a short jump forward by 10 seconds (functionCallPlayerSeekFwd) while holding the button will cause further, longer jumps. In this case it will cause a jump of 1 minute forward (functionCallPlayerSeekFarFwd) every 5 seconds. If you wish, you can adjust these values in `components/gpio_control/function_calls.py`. For jumping backwards, this can be done equivalently (see [function list below](#doc_funcs)). -## Functions +### Functions The available functions are defined/implemented in `components/gpio_control/function_calls.py`: @@ -270,7 +270,7 @@ The available functions are defined/implemented in `components/gpio_control/func * **functionCallPlayerRandomCard**: Activate a random card * **functionCallPlayerRandomFolder**: Play a random folder -## Troubleshooting +### Troubleshooting If you encounter bouncing effects with your buttons like unrequested/double actions after releasing a button, you can try to set `antibouncehack` to True: diff --git a/components/gpio_control/config_compatibility.py b/components/gpio_control/config_compatibility.py index 62922c299..9c2e92f5d 100644 --- a/components/gpio_control/config_compatibility.py +++ b/components/gpio_control/config_compatibility.py @@ -3,6 +3,7 @@ import os from shutil import copyfile + def Ini_CheckAndUpgrade(config): has_changed = False for section in config.sections(): @@ -37,8 +38,8 @@ def Ini_CheckAndUpgrade(config): has_changed = True if not config.has_option(section, 'hold_time'): config.set(section, 'hold_time', str(v)) - #PinUp: --> Pin1 - #PinDown: --> Pin2 + # PinUp: --> Pin1 + # PinDown: --> Pin2 if config.has_option(section, 'PinUp'): v = config.getint(section, 'PinUp') config.remove_option(section, 'PinUp') @@ -67,17 +68,17 @@ def Ini_CheckAndUpgrade(config): config.set(section, 'functionCall2', v) return has_changed - - + + def ConfigCompatibilityChecks(config, config_path): # Check for deprecated settings in gpio_settings.ini if not Ini_CheckAndUpgrade(config): return - + # If we reach here, gpio_settings.ini needed some patching... # Try creating a backup of the previous ini file - backup_path = config_path+'.bak' + backup_path = config_path + '.bak' if os.path.isfile(backup_path): return copyfile(config_path, backup_path) diff --git a/components/gpio_control/gpio_control.py b/components/gpio_control/gpio_control.py index 44ad68df1..113850431 100755 --- a/components/gpio_control/gpio_control.py +++ b/components/gpio_control/gpio_control.py @@ -118,7 +118,7 @@ def gpio_loop(self): config = configparser.ConfigParser(inline_comment_prefixes=";", delimiters=(':', '=')) config_path = os.path.expanduser('/home/pi/RPi-Jukebox-RFID/settings/gpio_settings.ini') config.read(config_path) - + ConfigCompatibilityChecks(config, config_path) phoniebox_function_calls = function_calls.phoniebox_function_calls() diff --git a/components/rfid-reader/RC522/requirements.txt b/components/rfid-reader/RC522/requirements.txt index 6643d6123..312014b2c 100644 --- a/components/rfid-reader/RC522/requirements.txt +++ b/components/rfid-reader/RC522/requirements.txt @@ -1,5 +1,4 @@ # RC522 related requirements # You need to install these with `sudo python3 -m pip install --upgrade --force-reinstall -q -r requirements.txt` -# pi-rc522 use latest version from Github -git+https://github.com/ondryaso/pi-rc522.git#egg=pi-rc522 +pi-rc522==2.3.0 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 b99b89eab..6ffe2e1ad 100644 --- a/components/smart-home-automation/MQTT-protocol/daemon_mqtt_client.py +++ b/components/smart-home-automation/MQTT-protocol/daemon_mqtt_client.py @@ -452,6 +452,7 @@ def regex(needle, hay, exception="-"): else: return exception + def getDuration(status): """ Find the duration of the track in the output from mpd status""" @@ -463,9 +464,10 @@ def getDuration(status): # this attribute value is split into two parts by ":" # first is the elapsed time and the second part is the duration duration = regex("\ntime: .*:(.*)\n", status, "0") - + return int(float(duration)) + REPEAT_MODE_OFF = "off" REPEAT_MODE_SINGLE = "single" REPEAT_MODE_PLAYLIST = "playlist" diff --git a/components/synchronisation/sync-shared/README.md b/components/synchronisation/sync-shared/README.md index d55b61b0c..5bf9818aa 100644 --- a/components/synchronisation/sync-shared/README.md +++ b/components/synchronisation/sync-shared/README.md @@ -17,9 +17,10 @@ To access the files on the server two modes are supported: SSH or MOUNT. Please make sure you have the correct access rights for the source and use key-based authentication for SSH. ### RFID scan sync + If the feature "RFID scan sync" is activated, there will be a check on every RFID scan against the server if a matching shortcut and audiofolder is found and the changes will be transfered. The playback will be delayed for the time the data are transfered (see "SYNCSHAREDFULL" to use a full-sync if a lot of new files have been added). -If the server is not reachable the check will be aborted after the timeout. So an unreachable server will cause a delay (see command "SYNCSHAREDONRFIDSCANTOGGLE" to toggle activation state). +If the server is not reachable the check will be aborted after the timeout. So an unreachable server will cause a delay (see command "SYNCSHAREDONRFIDSCANTOGGLE" to toggle activation state). Deleted shortcuts / audiofolders (not the contained items) will not be purged locally if deleted on remote. This is also true for changed shortcuts (the old audiofolder / -files will remain). To also delete not existing items us a "full-sync". ## Installation @@ -27,19 +28,17 @@ Deleted shortcuts / audiofolders (not the contained items) will not be purged lo Run the 'install-sync-shared.sh' script. This will install all required packages and rights. Please configure all settings according to your setup. - ## Configuration If your configuration has changed, run the script 'change_configuration.sh' to update the settings. This lets you also deactivate this feature. You may also change the settings in the according files directly. -### Settings: +### Settings **{INSTALLATION_ROOT}/settings/sync-shared-enabled** Holds the activation state of this feature. Values are "TRUE" or "FALSE" - **{INSTALLATION_ROOT}/settings/sync-shared.conf** SYNCSHAREDMODE: The mode to access the server files. SSH or MOUNT @@ -56,6 +55,6 @@ SYNCSHAREDREMOTEPATH: The path to the shared files to sync (without trailing sla SYNCSHAREDONRFIDSCAN: Holds the activation state of the optional feature "RFID scan sync". Values are "TRUE" or "FALSE" - ## Special Thanks -inspired by [splitti - phoniebox_rsync](https://github.com/splitti/phoniebox_rsync) + +Inspired by [splitti - phoniebox_rsync](https://github.com/splitti/phoniebox_rsync) diff --git a/composer.lock b/composer.lock index 8c765dd0a..172aa3a0b 100644 --- a/composer.lock +++ b/composer.lock @@ -564,16 +564,16 @@ }, { "name": "phpunit/php-code-coverage", - "version": "9.2.27", + "version": "9.2.29", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "b0a88255cb70d52653d80c890bd7f38740ea50d1" + "reference": "6a3a87ac2bbe33b25042753df8195ba4aa534c76" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/b0a88255cb70d52653d80c890bd7f38740ea50d1", - "reference": "b0a88255cb70d52653d80c890bd7f38740ea50d1", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/6a3a87ac2bbe33b25042753df8195ba4aa534c76", + "reference": "6a3a87ac2bbe33b25042753df8195ba4aa534c76", "shasum": "" }, "require": { @@ -630,7 +630,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy", - "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.27" + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.29" }, "funding": [ { @@ -638,7 +638,7 @@ "type": "github" } ], - "time": "2023-07-26T13:44:30+00:00" + "time": "2023-09-19T04:57:46+00:00" }, { "name": "phpunit/php-file-iterator", @@ -883,16 +883,16 @@ }, { "name": "phpunit/phpunit", - "version": "9.6.11", + "version": "9.6.13", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "810500e92855eba8a7a5319ae913be2da6f957b0" + "reference": "f3d767f7f9e191eab4189abe41ab37797e30b1be" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/810500e92855eba8a7a5319ae913be2da6f957b0", - "reference": "810500e92855eba8a7a5319ae913be2da6f957b0", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/f3d767f7f9e191eab4189abe41ab37797e30b1be", + "reference": "f3d767f7f9e191eab4189abe41ab37797e30b1be", "shasum": "" }, "require": { @@ -907,7 +907,7 @@ "phar-io/manifest": "^2.0.3", "phar-io/version": "^3.0.2", "php": ">=7.3", - "phpunit/php-code-coverage": "^9.2.13", + "phpunit/php-code-coverage": "^9.2.28", "phpunit/php-file-iterator": "^3.0.5", "phpunit/php-invoker": "^3.1.1", "phpunit/php-text-template": "^2.0.3", @@ -966,7 +966,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", "security": "https://github.com/sebastianbergmann/phpunit/security/policy", - "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.11" + "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.13" }, "funding": [ { @@ -982,7 +982,7 @@ "type": "tidelift" } ], - "time": "2023-08-19T07:10:56+00:00" + "time": "2023-09-19T05:39:22+00:00" }, { "name": "sebastian/cli-parser", diff --git a/scripts/Reader.py.pcsc b/scripts/Reader.py.pcsc index dac10de7c..e0d2cc374 100644 --- a/scripts/Reader.py.pcsc +++ b/scripts/Reader.py.pcsc @@ -63,7 +63,7 @@ class Reader: 'Failed to release context: ' + \ SCardGetErrorMessage(hresult)) - return(toHexString(response, PACK)) + return (toHexString(response, PACK)) except error as e: print(e) diff --git a/scripts/helperscripts/organizeFiles.py b/scripts/helperscripts/organizeFiles.py index 596ee4839..06c372633 100644 --- a/scripts/helperscripts/organizeFiles.py +++ b/scripts/helperscripts/organizeFiles.py @@ -52,7 +52,7 @@ def readFolders(audioDir, relpath=None, isFirst=True): elif os.path.isdir(absf): childResult = readFolders(audioDir=absf, relpath=os.path.join(relpath, f), isFirst=False) for k, v in childResult.items(): - assert(k not in result) + assert (k not in result) result[k] = v if hasAudioFiles: result[relpath] = os.path.exists(os.path.join(audioDir, "folder.conf")) diff --git a/scripts/installscripts/buster-install-default-with-autohotspot.sh b/scripts/installscripts/buster-install-default-with-autohotspot.sh index c00e92241..948b3ebbe 100644 --- a/scripts/installscripts/buster-install-default-with-autohotspot.sh +++ b/scripts/installscripts/buster-install-default-with-autohotspot.sh @@ -28,7 +28,10 @@ DATETIME=$(date +"%Y%m%d_%H%M%S") SCRIPTNAME="$(basename $0)" JOB="${SCRIPTNAME}" -HOME_DIR=$(echo $HOME) +CURRENT_USER="${SUDO_USER:-$(whoami)}" +HOME_DIR=$(getent passwd "$CURRENT_USER" | cut -d: -f6) +echo "Current User: $CURRENT_USER" +echo "User home dir: $HOME_DIR" JUKEBOX_HOME_DIR="${HOME_DIR}/RPi-Jukebox-RFID" LOGDIR="${HOME_DIR}"/phoniebox_logs @@ -90,6 +93,25 @@ log_close() { fi } +checkPrerequisite() { + #currently the user 'pi' is mandatory + #https://github.com/MiczFlor/RPi-Jukebox-RFID/issues/1785 + if [ "${CURRENT_USER}" != "pi" ]; then + echo + echo "ERROR: User must be 'pi'!" + echo " Other usernames are currently not supported." + echo " Please check the wiki for further information" + exit 2 + fi + + if [ "${HOME_DIR}" != "/home/pi" ]; then + echo + echo "ERROR: HomeDir must be '/home/pi'!" + echo " Other usernames are currently not supported." + echo " Please check the wiki for further information" + exit 2 + fi +} welcome() { clear @@ -1396,6 +1418,8 @@ finish_installation() { # Main # ######## main() { + checkPrerequisite + if [[ ${INTERACTIVE} == "true" ]]; then welcome #reset_install_config_file diff --git a/scripts/installscripts/buster-install-default.sh b/scripts/installscripts/buster-install-default.sh index 45817b998..c7ca7bbd2 100644 --- a/scripts/installscripts/buster-install-default.sh +++ b/scripts/installscripts/buster-install-default.sh @@ -27,7 +27,10 @@ DATETIME=$(date +"%Y%m%d_%H%M%S") SCRIPTNAME="$(basename $0)" JOB="${SCRIPTNAME}" -HOME_DIR=$(echo $HOME) +CURRENT_USER="${SUDO_USER:-$(whoami)}" +HOME_DIR=$(getent passwd "$CURRENT_USER" | cut -d: -f6) +echo "Current User: $CURRENT_USER" +echo "User home dir: $HOME_DIR" JUKEBOX_HOME_DIR="${HOME_DIR}/RPi-Jukebox-RFID" LOGDIR="${HOME_DIR}"/phoniebox_logs @@ -89,6 +92,25 @@ log_close() { fi } +checkPrerequisite() { + #currently the user 'pi' is mandatory + #https://github.com/MiczFlor/RPi-Jukebox-RFID/issues/1785 + if [ "${CURRENT_USER}" != "pi" ]; then + echo + echo "ERROR: User must be 'pi'!" + echo " Other usernames are currently not supported." + echo " Please check the wiki for further information" + exit 2 + fi + + if [ "${HOME_DIR}" != "/home/pi" ]; then + echo + echo "ERROR: HomeDir must be '/home/pi'!" + echo " Other usernames are currently not supported." + echo " Please check the wiki for further information" + exit 2 + fi +} welcome() { clear @@ -1394,6 +1416,8 @@ EOF # Main # ######## main() { + checkPrerequisite + # Skip interactive Samba WINS config dialog echo "samba-common samba-common/dhcp boolean false" | sudo debconf-set-selections diff --git a/scripts/installscripts/tests/run_installation_tests.sh b/scripts/installscripts/tests/run_installation_tests.sh index 259e89432..fb711048b 100644 --- a/scripts/installscripts/tests/run_installation_tests.sh +++ b/scripts/installscripts/tests/run_installation_tests.sh @@ -13,6 +13,7 @@ echo $PWD echo "samba-common samba-common/dhcp boolean false" | sudo debconf-set-selections # No interactive frontend export DEBIAN_FRONTEND=noninteractive +echo 'debconf debconf/frontend select Noninteractive' | sudo debconf-set-selections # Run installation (in interactive mode) # y confirm interactive @@ -21,12 +22,12 @@ export DEBIAN_FRONTEND=noninteractive # n no spotify # y configure mpd # y audio default location -# y config gpio +# y config gpio # n no RFID registration # n No reboot -# TODO check, how this behaves on branches other than develop -GIT_BRANCH=develop bash ./scripts/installscripts/buster-install-default.sh <<< $'y\nn\n\ny\n\nn\n\ny\n\ny\n\ny\n\ny\nn\nn\n' +./../buster-install-default.sh <<< $'y\nn\n\ny\n\nn\n\ny\n\ny\n\ny\n\ny\nn\nn\n' +INSTALLATION_EXITCODE=$? # Test installation -./scripts/installscripts/tests/test_installation.sh +./test_installation.sh $INSTALLATION_EXITCODE diff --git a/scripts/installscripts/tests/run_installation_tests2.sh b/scripts/installscripts/tests/run_installation_tests2.sh index b00f4a078..58c2a378d 100644 --- a/scripts/installscripts/tests/run_installation_tests2.sh +++ b/scripts/installscripts/tests/run_installation_tests2.sh @@ -13,6 +13,7 @@ echo $PWD echo "samba-common samba-common/dhcp boolean false" | sudo debconf-set-selections # No interactive frontend export DEBIAN_FRONTEND=noninteractive +echo 'debconf debconf/frontend select Noninteractive' | sudo debconf-set-selections # Run installation (in interactive mode) # y confirm interactive @@ -27,8 +28,8 @@ export DEBIAN_FRONTEND=noninteractive # yes, reader is connected # n No reboot -# TODO check, how this behaves on branches other than develop -GIT_BRANCH=develop bash ./scripts/installscripts/buster-install-default.sh <<< $'y\nn\n\ny\n\nn\n\ny\n\ny\n\ny\n\ny\ny\n2\ny\nn\n' +./../buster-install-default.sh <<< $'y\nn\n\ny\n\nn\n\ny\n\ny\n\ny\n\ny\ny\n2\ny\nn\n' +INSTALLATION_EXITCODE=$? # Test installation -./scripts/installscripts/tests/test_installation.sh +./test_installation.sh $INSTALLATION_EXITCODE diff --git a/scripts/installscripts/tests/run_installation_tests2_altuser.sh b/scripts/installscripts/tests/run_installation_tests2_altuser.sh deleted file mode 100644 index 03bce2af7..000000000 --- a/scripts/installscripts/tests/run_installation_tests2_altuser.sh +++ /dev/null @@ -1,34 +0,0 @@ -#!/usr/bin/env bash - -# Install Phoniebox and test it -# Used e.g. for tests on Docker - -# Objective: Test installation with script using a RC522 reader - -# Print current path -echo $PWD - -# Preparations -# Skip interactive Samba WINS config dialog -echo "samba-common samba-common/dhcp boolean false" | sudo debconf-set-selections -# No interactive frontend -export DEBIAN_FRONTEND=noninteractive - -# Run installation (in interactive mode) -# y confirm interactive -# n dont configure wifi -# y PCM as iface -# n no spotify -# y configure mpd -# y audio default location -# y use gpio -# y RFID registration -# 2 use RC522 reader -# yes, reader is connected -# n No reboot - -# TODO check, how this behaves on branches other than develop -GIT_BRANCH=develop bash ./scripts/installscripts/buster-install-default.sh <<< $'y\nn\n\ny\n\nn\n\ny\n\ny\n\ny\n\ny\ny\n2\ny\nn\n' - -# Test installation -./scripts/installscripts/tests/test_installation_altuser.sh diff --git a/scripts/installscripts/tests/run_installation_tests3.sh b/scripts/installscripts/tests/run_installation_tests3.sh index 46e2586f9..e130da595 100644 --- a/scripts/installscripts/tests/run_installation_tests3.sh +++ b/scripts/installscripts/tests/run_installation_tests3.sh @@ -13,6 +13,7 @@ echo $PWD echo "samba-common samba-common/dhcp boolean false" | sudo debconf-set-selections # No interactive frontend export DEBIAN_FRONTEND=noninteractive +echo 'debconf debconf/frontend select Noninteractive' | sudo debconf-set-selections # Run installation (in interactive mode) # y confirm interactive mode @@ -23,29 +24,12 @@ export DEBIAN_FRONTEND=noninteractive # y configure mpd (extra ENTER) # y audio default location (extra ENTER) # y config gpio (extra ENTER) -# n start installation +# y start installation +# n no RFID registration +# n No reboot -# TODO check, how this behaves on branches other than develop -GIT_BRANCH=develop bash ./scripts/installscripts/buster-install-default.sh <<< "y -n - -y - -y -myuser -mypassword -myclient_id -myclient_secret -y - -y - -y - -y -n -n -" +./../buster-install-default.sh <<< $'y\nn\n\ny\n\ny\nmyuser\nmypassword\nmyclient_id\nmyclient_secret\ny\n\ny\n\ny\n\ny\n\ny\nn\nn\n' +INSTALLATION_EXITCODE=$? # Test installation -./scripts/installscripts/tests/test_installation.sh +./test_installation.sh $INSTALLATION_EXITCODE diff --git a/scripts/installscripts/tests/run_installation_tests3_altuser.sh b/scripts/installscripts/tests/run_installation_tests3_altuser.sh deleted file mode 100644 index 2db9b991f..000000000 --- a/scripts/installscripts/tests/run_installation_tests3_altuser.sh +++ /dev/null @@ -1,32 +0,0 @@ -#!/usr/bin/env bash - -# Install Phoniebox and test it -# Used e.g. for tests on Docker - -# Objective: Test installation with script using a configuration with mopidy - -# Print current path -echo $PWD - -# Preparations -# Skip interactive Samba WINS config dialog -echo "samba-common samba-common/dhcp boolean false" | sudo debconf-set-selections -# No interactive frontend -export DEBIAN_FRONTEND=noninteractive - -# Run installation (in interactive mode) -# y confirm interactive -# n dont configure wifi -# y Headphone as iface -# y spotify with myuser, mypassword, myclient_id, myclient_secret -# y configure mpd -# y audio default location -# y config gpio -# n no RFID registration -# n No reboot - -# TODO check, how this behaves on branches other than develop -GIT_BRANCH=develop bash ./scripts/installscripts/buster-install-default.sh <<< $'y\nn\n\ny\n\ny\nmyuser\nmypassword\nmyclient_id\nmyclient_secret\n\ny\n\ny\n\ny\n\ny\nn\nn\n' - -# Test installation -./scripts/installscripts/tests/test_installation_altuser.sh diff --git a/scripts/installscripts/tests/run_installation_tests_altuser.sh b/scripts/installscripts/tests/run_installation_tests_altuser.sh deleted file mode 100644 index d06aac742..000000000 --- a/scripts/installscripts/tests/run_installation_tests_altuser.sh +++ /dev/null @@ -1,32 +0,0 @@ -#!/usr/bin/env bash - -# Install Phoniebox and test it -# Used e.g. for tests on Docker - -# Objective: Test installation with script using a simple configuration - -# Print current path -echo $PWD - -# Preparations -# Skip interactive Samba WINS config dialog -echo "samba-common samba-common/dhcp boolean false" | sudo debconf-set-selections -# No interactive frontend -export DEBIAN_FRONTEND=noninteractive - -# Run installation (in interactive mode) -# y confirm interactive -# n dont configure wifi -# y Headphone as iface -# n no spotify -# y configure mpd -# y audio default location -# y config gpio -# n no RFID registration -# n No reboot - -# TODO check, how this behaves on branches other than develop -GIT_BRANCH=develop bash ./scripts/installscripts/buster-install-default.sh <<< $'y\nn\n\ny\n\nn\n\ny\n\ny\n\ny\n\ny\nn\nn\n' - -# Test installation -./scripts/installscripts/tests/test_installation_altuser.sh diff --git a/scripts/installscripts/tests/test_installation.sh b/scripts/installscripts/tests/test_installation.sh index e9f4345ca..332cfb8cb 100755 --- a/scripts/installscripts/tests/test_installation.sh +++ b/scripts/installscripts/tests/test_installation.sh @@ -4,8 +4,11 @@ # This script needs to be adapted, if new packages, etc are added to the install script # The absolute path to the folder which contains this script +INSTALLATION_EXITCODE="${1:-0}" + PATHDATA="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" -HOME_DIR="/home/pi" +USER_NAME="$(whoami)" +HOME_DIR=$(getent passwd "$USER_NAME" | cut -d: -f6) tests=0 failed_tests=0 @@ -74,6 +77,19 @@ check_variable() { } # Verify functions +verify_installation_exitcode() { + if [ "${INSTALLATION_EXITCODE}" -eq 0 ]; then + echo "Installation successfull." + echo "Performing further checks..." + elif [ "${INSTALLATION_EXITCODE}" -eq 2 ]; then + echo "ABORT: Installation aborted due to prerequisite." + echo "Further checks skipped." + exit 0 + else + echo "ERROR: Installation exited with errorcode '${INSTALLATION_EXITCODE}'" + exit 1 + fi +} verify_conf_file() { local install_conf="${HOME_DIR}/PhonieboxInstall.conf" @@ -300,9 +316,9 @@ verify_folder_access() { printf "\nTESTING folder access...\n\n" # check owner and permissions - check_chmod_chown 775 pi www-data "${jukebox_dir}" "playlists shared htdocs settings" + check_chmod_chown 775 "$USER_NAME" www-data "${jukebox_dir}" "playlists shared htdocs settings" # ${DIRaudioFolders} => "testing" "audiofolders" - check_chmod_chown 775 pi www-data "${DIRaudioFolders}/.." "audiofolders" + check_chmod_chown 775 "$USER_NAME" www-data "${DIRaudioFolders}/.." "audiofolders" #find .sh and .py scripts that are NOT executable local count=$(find . -maxdepth 1 -type f \( -name "*.sh" -o -name "*.py" \) ! -executable | wc -l) @@ -316,6 +332,7 @@ verify_folder_access() { main() { printf "\nTesting installation:\n" + verify_installation_exitcode verify_conf_file if [[ "$WIFIconfig" == "YES" ]]; then verify_wifi_settings diff --git a/scripts/installscripts/tests/test_installation_altuser.sh b/scripts/installscripts/tests/test_installation_altuser.sh deleted file mode 100755 index d66a00a47..000000000 --- a/scripts/installscripts/tests/test_installation_altuser.sh +++ /dev/null @@ -1,349 +0,0 @@ -#!/usr/bin/env bash - -# Test to verify that the installation script works as expected. -# This script needs to be adapted, if new packages, etc are added to the install script - -# The absolute path to the folder which contains this script -PATHDATA="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" -HOME_DIR="/home/hans" - -tests=0 -failed_tests=0 - -# Tool functions - -check_chmod_chown() { - local mod_expected=$1 - local user_expected=$2 - local group_expected=$3 - local dir=$4 - local files=$5 - - for file in ${files}; - do - mod_actual=$(stat --format '%a' "${dir}/${file}") - user_actual=$(stat -c '%U' "${dir}/${file}") - group_actual=$(stat -c '%G' "${dir}/${file}") - test ! "${mod_expected}" -eq "${mod_actual}" && echo " ERROR: ${file} actual mod (${mod_actual}) differs from expected (${mod_expected})!" - test ! "${user_expected}" == "${user_actual}" && echo " ERROR: ${file} actual owner (${user_actual}) differs from expected (${user_expected})!" - test ! "${group_expected}" == "${group_actual}" && echo " ERROR: ${file} actual group (${group_actual}) differs from expected (${group_expected})!" - done -} - -check_file_contains_string() { - local string="$1" - local file="$2" - - # sudo is required for checking /etc/mopidy/mopidy.conf - if [[ ! $(sudo grep -iw "${string}" "${file}") ]]; then - echo " ERROR: '${string}' not found in ${file}" - ((failed_tests++)) - fi - ((tests++)) -} - -check_service_state() { - local service="$1" - local desired_state="$2" - - local actual_state=$(systemctl show -p ActiveState --value "${service}") - if [[ ! "${actual_state}" == "${desired_state}" ]]; then - echo " ERROR: service ${service} is not ${desired_state} (state: ${actual_state})." - ((failed_tests++)) - fi - ((tests++)) -} - -check_service_enablement() { - local service="$1" - local desired_enablement="$2" - - local actual_enablement=$(systemctl is-enabled "${service}") - if [[ ! "${actual_enablement}" == "${desired_enablement}" ]]; then - echo " ERROR: service ${service} is not ${desired_enablement} (state: ${actual_enablement})." - ((failed_tests++)) - fi - ((tests++)) -} - -check_variable() { - local variable=${1} - # check if variable exist and if it's empty - test -z "${!variable+x}" && echo "ERROR: \$${variable} is missing!" && fail=true && return - test "${!variable}" == "" && echo "ERROR: \$${variable} is empty!" && fail=true -} - -# Verify functions - -verify_conf_file() { - local install_conf="${HOME_DIR}/PhonieboxInstall.conf" - printf "\nTESTING PhonieboxInstall.conf file...\n\n" - # check that PhonieboxInstall.conf exists and is not empty - - # check if config file exists - if [[ -f "${install_conf}" ]]; then - # Source config file - source "${install_conf}" - cat "${install_conf}" - echo "" - else - echo "ERROR: ${install_conf} does not exist!" - exit 1 - fi - - fail=false - if [[ -z "${WIFIconfig+x}" ]]; then - echo " ERROR: \$WIFIconfig is missing or not set!" && fail=true - else - echo "\$WIFIconfig is set to '$WIFIconfig'" - if [[ "$WIFIconfig" == "YES" ]]; then - check_variable "WIFIcountryCode" - check_variable "WIFIssid" - check_variable "WIFIpass" - check_variable "WIFIip" - check_variable "WIFIipRouter" - fi - fi - check_variable "EXISTINGuse" - check_variable "AUDIOiFace" - - if [[ -z "${SPOTinstall+x}" ]]; then - echo " ERROR: \$SPOTinstall is missing or not set!" && fail=true - else - echo "\$SPOTinstall is set to '$SPOTinstall'" - if [ "$SPOTinstall" == "YES" ]; then - check_variable "SPOTIuser" - check_variable "SPOTIpass" - check_variable "SPOTIclientid" - check_variable "SPOTIclientsecret" - fi - fi - check_variable "MPDconfig" - check_variable "DIRaudioFolders" - - if [ "${fail}" == "true" ]; then - exit 1 - fi - - echo "" -} - -verify_wifi_settings() { - local dhcpcd_conf="/etc/dhcpcd.conf" - local wpa_supplicant_conf="/etc/wpa_supplicant/wpa_supplicant.conf" - printf "\nTESTING WiFi settings...\n" - - # check conf files - check_file_contains_string "static ip_address=${WIFIip}/24" "${dhcpcd_conf}" - check_file_contains_string "static routers=${WIFIipRouter}" "${dhcpcd_conf}" - check_file_contains_string "static domain_name_servers=8.8.8.8 ${WIFIipRouter}" "${dhcpcd_conf}" - - check_file_contains_string "country=${WIFIcountryCode}" "${wpa_supplicant_conf}" - check_file_contains_string "ssid=\"${WIFIssid}\"" "${wpa_supplicant_conf}" - check_file_contains_string "psk=\"${WIFIpass}\"" "${wpa_supplicant_conf}" - - # check owner and permissions - check_chmod_chown 664 root netdev "/etc" "dhcpcd.conf" - check_chmod_chown 664 root netdev "/etc/wpa_supplicant" "wpa_supplicant.conf" - - # check that dhcpcd service is enabled and started - check_service_state dhcpcd active - check_service_enablement dhcpcd enabled -} - -verify_apt_packages(){ - local phpver="$(ls -1 /etc/php)" - local packages="samba -samba-common-bin gcc lighttpd php${phpver}-common php${phpver}-cgi php${phpver} at mpd mpc mpg123 git ffmpeg -resolvconf spi-tools python3 python3-dev python3-pip python3-setuptools python3-wheel python3-mutagen python3-gpiozero -python3-spidev netcat alsa-utils" - local packages_raspberrypi="raspberrypi-kernel-headers" - local packages_spotify="libspotify-dev mopidy mopidy-mpd mopidy-local mopidy-spotify libspotify12 -python3-cffi python3-ply python3-pycparser python3-spotify" - - printf "\nTESTING installed packages...\n\n" - - # also check for spotify packages if it has been installed - if [[ "${SPOTinstall}" == "YES" ]]; then - packages="${packages} ${packages_spotify}" - fi - - # check for raspberry pi packages only on raspberry pi's but not on test docker containers running on x86_64 machines - if [[ $(uname -m) =~ ^armv.+$ ]]; then - packages="${packages} ${packages_raspberrypi}" - fi - - for package in ${packages} - do - if [[ $(apt -qq list "${package}" 2>/dev/null | grep 'installed') ]]; then - echo " ${package} is installed" - else - echo " ERROR: ${package} is not installed" - ((failed_tests++)) - fi - ((tests++)) - done -} - -verify_pip_packages() { - local modules="evdev spi-py youtube_dl pyserial RPi.GPIO" - local modules_spotify="Mopidy-Iris" - local modules_pn532="py532lib" - local modules_rc522="pi-rc522" - local deviceName="${JUKEBOX_HOME_DIR}"/scripts/deviceName.txt - - printf "\nTESTING installed pip modules...\n\n" - - # also check for spotify pip modules if it has been installed - if [[ "${SPOTinstall}" == "YES" ]]; then - modules="${modules} ${modules_spotify}" - fi - - if [[ -f "${deviceName}" ]]; then - # RC522 reader is used - if grep -Fxq "${deviceName}" MFRC522 - then - modules="${modules} ${modules_rc522}" - fi - - # PN532 reader is used - if grep -Fxq "${deviceName}" PN532 - then - modules="${modules} ${modules_pn532}" - fi - fi - - for module in ${modules} - do - if [[ $(pip3 show "${module}") ]]; then - echo " ${module} is installed" - else - echo " ERROR: pip module ${module} is not installed" - ((failed_tests++)) - fi - ((tests++)) - done -} - -verify_samba_config() { - printf "\nTESTING samba config...\n\n" - check_chmod_chown 644 root root "/etc/samba" "smb.conf" - - check_file_contains_string "path=${DIRaudioFolders}" "/etc/samba/smb.conf" -} - -verify_webserver_config() { - printf "\nTESTING webserver config...\n\n" - check_chmod_chown 644 root root "/etc/lighttpd" "lighttpd.conf" - check_chmod_chown 644 root root "/etc/lighttpd/conf-available" "15-fastcgi-php.conf" - check_chmod_chown 644 root root "/etc/php/7.3/cgi" "php.ini" - check_chmod_chown 440 root root "/etc" "sudoers" - - # Bonus TODO: check that fastcgi and fastcgi-php mods are enabled -} - -verify_systemd_services() { - printf "\nTESTING systemd services...\n\n" - # check that services exist - check_chmod_chown 644 root root "/etc/systemd/system" "phoniebox-rfid-reader.service phoniebox-startup-scripts.service phoniebox-gpio-control.service phoniebox-idle-watchdog.service" - - # check that phoniebox services are enabled - check_service_enablement phoniebox-idle-watchdog enabled - check_service_enablement phoniebox-rfid-reader enabled - check_service_enablement phoniebox-startup-scripts enabled - check_service_enablement phoniebox-gpio-control enabled -} - -verify_spotify_config() { - local etc_mopidy_conf="/etc/mopidy/mopidy.conf" - local mopidy_conf="${HOME_DIR}/.config/mopidy/mopidy.conf" - - printf "\nTESTING spotify config...\n\n" - - check_file_contains_string "username = ${SPOTIuser}" "${etc_mopidy_conf}" - check_file_contains_string "password = ${SPOTIpass}" "${etc_mopidy_conf}" - check_file_contains_string "client_id = ${SPOTIclientid}" "${etc_mopidy_conf}" - check_file_contains_string "client_secret = ${SPOTIclientsecret}" "${etc_mopidy_conf}" - check_file_contains_string "media_dir = ${DIRaudioFolders}" "${etc_mopidy_conf}" - - check_file_contains_string "username = ${SPOTIuser}" "${mopidy_conf}" - check_file_contains_string "password = ${SPOTIpass}" "${mopidy_conf}" - check_file_contains_string "client_id = ${SPOTIclientid}" "${mopidy_conf}" - check_file_contains_string "client_secret = ${SPOTIclientsecret}" "${mopidy_conf}" - check_file_contains_string "media_dir = ${DIRaudioFolders}" "${mopidy_conf}" - - # check that mopidy service is enabled - check_service_enablement mopidy enabled - # check that mpd service is disabled - check_service_enablement mpd disabled -} - -verify_mpd_config() { - local mpd_conf="/etc/mpd.conf" - - printf "\nTESTING mpd config...\n\n" - - check_file_contains_string "^[[:blank:]]\+mixer_control[[:blank:]]\+\"${AUDIOiFace}\"" "${mpd_conf}" - check_file_contains_string "^music_directory[[:blank:]]\+\"${DIRaudioFolders}\"" "${mpd_conf}" - - check_chmod_chown 640 mpd audio "/etc" "mpd.conf" - - # check that mpd service is enabled, when Spotify support is not installed - if [[ "${SPOTinstall}" == "NO" ]]; then - check_service_enablement mpd enabled - fi -} - -verify_folder_access() { - local jukebox_dir="${HOME_DIR}/RPi-Jukebox-RFID" - printf "\nTESTING folder access...\n\n" - - # check owner and permissions - check_chmod_chown 775 hans www-data "${jukebox_dir}" "playlists shared htdocs settings" - # ${DIRaudioFolders} => "testing" "audiofolders" - check_chmod_chown 775 hans www-data "${DIRaudioFolders}/.." "audiofolders" - - #find .sh and .py scripts that are NOT executable - local count=$(find . -maxdepth 1 -type f \( -name "*.sh" -o -name "*.py" \) ! -executable | wc -l) - if [[ "${count}" -gt 0 ]]; then - echo " ERROR: found ${count} '*.sh' and/or '*.py' files that are NOT executable:" - find . -maxdepth 1 -type f \( -name "*.sh" -o -name "*.py" \) ! -executable - ((failed_tests++)) - fi - ((tests++)) -} - -main() { - printf "\nTesting installation:\n" - verify_conf_file - if [[ "$WIFIconfig" == "YES" ]]; then - verify_wifi_settings - fi - verify_apt_packages - verify_pip_packages - verify_samba_config - verify_webserver_config - verify_systemd_services - if [[ "${SPOTinstall}" == "YES" ]]; then - verify_spotify_config - fi - verify_mpd_config - verify_folder_access -} - -start=$(date +%s) -main -end=$(date +%s) - -runtime=$((end-start)) -((h=${runtime}/3600)) -((m=($runtime%3600)/60)) -((s=$runtime%60)) - -if [[ "${failed_tests}" -gt 0 ]]; then - echo "${failed_tests} Test(s) failed (of ${tests} tests) (in ${h}h ${m}m ${s}s)." - exit 1 -else - echo "${tests} tests done in ${h}h ${m}m ${s}s." -fi -