RaspberryPi 5, Debian 12 (bookworm), as DLNA renderer with output to a Teufel Cinebar One+ via USB, configured with Ansible
Table of Contents
When I listen to music, the RasPi case is not resting on top of the speaker. It’s in a shelf above my main screen and the Cinebar is attached to the wall about halfway between the top of the screen and the bottom of the shelf.
Introduction
These are my notes on setting up:
- Debian GNU/Linux 12 (bookworm) aka Raspberry Pi OS (64-bit) Lite
- on a Raspberry Pi 5
- housed in a passively cooled KKSB case
- using USB audio to output on a Teufel Cinebar One+
- playing music via DLNA with gmrender-resurrect
Overview
Debian 11 will be EOL this coming July, so it was time to finally modernise my existing setup to Debian 12.
The aim is to use a RasPi, a small µSD card for booting plus a USB attached sound bar to play music using DLNA.
The music files themselves are hosted on one (or more) DLNA servers.
Controlling the music happens via one (or more) DLNA controllers.
This post is a pruned and edited copy of my older, Debian 11, post on this topic.
Pruned because I decided to do this round the KISS way, parts (HW and SW) I do not use will be disabled
(HDMI audio disabled, Bluetoth disabled, WiFi disabled), this has the nice side effect of no longer needing to
mess with alsa device indices because then USB audio is the sole audio output available and thus at the default index 0
that alsa.conf
uses for defaults.ctl.card
and defaults.pcm.card
.
Additionally, because I upgraded to a Raspberry Pi 5, I no longer need proprietary scripts of questionable quality from Argon40 which in turn download more scripts, just to have a functioning power button.
The USB audio at index 1 fiddlings were dropped. A task was added to switch off Bluetooth and WiFi via dtoverlay using a model filter. A packet and a task was added to used the powersave cpufreq governor.
Oh and the Ansible tasks now use FQCN.
tl;dr
- optional: house RasPi 5 in a case
- connect Cinebar via USB to RasPi 5
- write ųSD card using rpi-imager with custom config set as needed (hostname, user, ssh key, …)
- disable HDMi audio
- optional: disable services that use Bluetooth
- optional: disable Bluetooth hardware via dtoverlay
- optional: disable WiFi hardware via dtoverlay
- optional: use powersaving CPU frequency scaling governor
- install gmrender-resurrect
- ensure gmrender-resurrect runs at boot
- use a DLAN control point for song selection, play, stop, etc
- press power button to trigger a clean shutdown
- optional: automatic clean shutdown N hours after powerup
Hardware Details
Chosen Hardware
- Raspberry Pi 5
- Raspberry Pi 15W USB-C Power Supply
- KKSB Raspberry Pi 5 Case with Aluminium Heatsink for Silent Passive Cooling
- Teufel Cinebar One+ connected via USB
The RasPi 5 and case were purchased new. My existing 15W PSU is sufficient for my planned power draw. The Cinebar has been serving me well for a while now, I reused the 32 GiB µSD card since I am decommisionning the RasPi 4B and the Argon case. The 27W PSU is overkill for my use case (no fan, Cinebar has own PSU).
While my RasPi 5 has 8 GiB RAM, the 4 GiB model and even only 2 GiB would be more than sufficient for this one trick pony use case.
The following CPU and memory usage was collected while it was playing a song;
pcfe@raspi5:~ $ uptime
22:49:43 up 2:51, 1 user, load average: 0.03, 0.05, 0.05
pcfe@raspi5:~ $ free -h
total used free shared buff/cache available
Mem: 7.9Gi 279Mi 7.1Gi 5.4Mi 557Mi 7.6Gi
Swap: 99Mi 0B 99Mi
RasPi to Cinebar Connection
I connected the Cinebar to the RasPi via USB.
The RasPi 5 no longer comes with the low quality 3.5mm audio jack previous models had (good riddance). Plus I disable audio over HDMI because I do not plan to use audio over HDMI on this RasPi and I want the HDMI input on the Cinebar available for other uses.
This leaves only usb-audio, at index 0, and I can use the shipped defaults of alsa.conf
etc.
RasPi Enclosure
While I could use the naked RasPi, I wanted all of
- a heatsink
- no noisy fan
- some dust protection
I looked at the options available from the place I decided to by my RasPi5 from and chose this passively cooled KKSB case.
Software Used
gmrender-resurrect is available on Raspberry Pi OS (64-bit) (Debian 12)
with a simple apt install gmediarender
.
Operating System Used
I did a fresh install of Raspberry Pi OS (64-bit), Debian version: 12 (bookworm).
Created the µSD card with the Raspberry Pi Imaging Utility (aka rpi-imager
).
It is well documentated.
With these selections:
- Device: RaspberryPi 5
- Operating System: RaspberryPi OS Lite (64-bit)
- set hostname
- set user and password
- set locale
- enable ssh
- allow public-key authentication only
- eject media when finished
NOTE: Lite simply because on this headless RasPi there is no point in wasting resources on running a desktop environment,
so there is no point either in having it on the µSD card. If I want a package I can easily apt install
or ansible.builtin.package:
.
Not being in an active desktop session has the welcome side-effect of the Pi shutting down cleanly when I press the power button without me having to acknowledge in a window [that would] appear asking whether you want to shutdown, reboot, or logout.
Once the tool had finished writing to the SD card, I plugged it into the RaspberryPi 5 and booted from it.
Once it had booted up, I upgraded using APT
sudo apt update && sudo apt full-upgrade # click to see details
pcfe@raspi5:~ $ sudo apt update
Hit:1 http://deb.debian.org/debian bookworm InRelease
Get:2 http://deb.debian.org/debian-security bookworm-security InRelease [48.0 kB]
Get:3 http://deb.debian.org/debian bookworm-updates InRelease [55.4 kB]
Get:4 http://archive.raspberrypi.com/debian bookworm InRelease [23.6 kB]
Get:5 http://deb.debian.org/debian-security bookworm-security/main armhf Packages [150 kB]
Get:6 http://deb.debian.org/debian-security bookworm-security/main arm64 Packages [153 kB]
Get:7 http://deb.debian.org/debian-security bookworm-security/main Translation-en [92.9 kB]
Get:8 http://deb.debian.org/debian bookworm-updates/main armhf Packages [13.2 kB]
Get:9 http://deb.debian.org/debian bookworm-updates/main arm64 Packages [13.7 kB]
Get:10 http://deb.debian.org/debian bookworm-updates/main Translation-en [16.0 kB]
Get:11 http://archive.raspberrypi.com/debian bookworm/main armhf Packages [422 kB]
Get:12 http://archive.raspberrypi.com/debian bookworm/main arm64 Packages [413 kB]
Fetched 1,401 kB in 1s (1,652 kB/s)
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
42 packages can be upgraded. Run 'apt list --upgradable' to see them.
pcfe@raspi5:~ $ sudo apt full-upgrade
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
Calculating upgrade... Done
The following NEW packages will be installed:
linux-headers-6.6.28+rpt-common-rpi linux-headers-6.6.28+rpt-rpi-2712 linux-headers-6.6.28+rpt-rpi-v8
linux-image-6.6.28+rpt-rpi-2712 linux-image-6.6.28+rpt-rpi-v8 linux-kbuild-6.6.28+rpt pastebinit
python3-pycryptodome
The following packages will be upgraded:
bsdextrautils bsdutils dpkg dpkg-dev eject fdisk less libblkid1 libc-bin libc-dev-bin libc-devtools
libc-l10n libc6 libc6-dbg libc6-dev libcamera-ipa libcamera0.2 libdav1d6 libdpkg-perl libfdisk1
libglib2.0-0 libmount1 libpisp-common libpisp1 libsmartcols1 libuuid1 linux-headers-rpi-2712
linux-headers-rpi-v8 linux-image-rpi-2712 linux-image-rpi-v8 linux-libc-dev locales mount pi-bluetooth
raspi-config raspi-firmware raspi-utils rfkill rpi-eeprom rpicam-apps-lite util-linux util-linux-extra
42 upgraded, 8 newly installed, 0 to remove and 0 not upgraded.
Need to get 109 MB of archives.
After this operation, 141 MB of additional disk space will be used.
Do you want to continue? [Y/n]
[…]
pcfe@raspi5:~ $ sudo reboot
Broadcast message from root@raspi5 on pts/1 (Sat 2024-05-18 14:52:53 CEST):
The system will reboot now!
pcfe@raspi5:~ $ Connection to raspi5.internal.pcfe.net closed by remote host.
Connection to raspi5.internal.pcfe.net closed.
Wait a bit for it to finish booting, and log in again.
user@workstation ~ $ ssh raspi5.internal.pcfe.net
Linux raspi5 6.6.28+rpt-rpi-2712 #1 SMP PREEMPT Debian 1:6.6.28-1+rpt1 (2024-04-22) aarch64
The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.
Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Sat May 18 14:45:25 2024 from 192.168.50.59
pcfe@raspi5:~ $ uptime
14:55:40 up 2 min, 1 user, load average: 0.24, 0.19, 0.08
pcfe@raspi5:~ $ uname -r
6.6.28+rpt-rpi-2712
pcfe@raspi5:~ $ cat /etc/os-release
PRETTY_NAME="Debian GNU/Linux 12 (bookworm)"
NAME="Debian GNU/Linux"
VERSION_ID="12"
VERSION="12 (bookworm)"
VERSION_CODENAME=bookworm
ID=debian
HOME_URL="https://www.debian.org/"
SUPPORT_URL="https://www.debian.org/support"
BUG_REPORT_URL="https://bugs.debian.org/"
pcfe@raspi5:~ $
And I ensured I was running the latest firmware with
sudo rpi-update # click to see details
pcfe@raspi5:~ $ sudo rpi-update
*** Raspberry Pi firmware updater by Hexxeh, enhanced by AndrewS and Dom
*** Performing self-update
*** Relaunching after update
*** Raspberry Pi firmware updater by Hexxeh, enhanced by AndrewS and Dom
FW_REV:3b768c3f4d2b9a275fafdb53978f126d7ad72a1a
BOOTLOADER_REV:61fb89536fc94a57c1e0afd42617849b6d0cac37
*** We're running for the first time
*** Backing up files (this will take a few minutes)
*** Backing up firmware
*** Backing up modules 6.6.28+rpt-rpi-2712
WANT_32BIT:0 WANT_64BIT:1 WANT_PI4:1 WANT_PI5:1
##############################################################
WARNING: This update bumps to rpi-6.6.y linux tree
See: https://forums.raspberrypi.com/viewtopic.php?p=2191175
'rpi-update' should only be used if there is a specific
reason to do so - for example, a request by a Raspberry Pi
engineer or if you want to help the testing effort
and are comfortable with restoring if there are regressions.
DO NOT use 'rpi-update' as part of a regular update process.
##############################################################
Would you like to proceed? (y/N)
Downloading bootloader tools
Downloading bootloader images
*** Downloading specific firmware revision (this will take a few minutes)
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0
100 142M 0 142M 0 0 20.3M 0 --:--:-- 0:00:07 --:--:-- 23.4M
*** PREPARING EEPROM UPDATES ***
BOOTLOADER: update available
CURRENT: Mon 13 May 15:15:01 UTC 2024 (1715613301)
LATEST: Fri 17 May 11:29:43 UTC 2024 (1715945383)
RELEASE: latest (/lib/firmware/raspberrypi/bootloader-2712/latest)
Use raspi-config to change the release.
CURRENT: Mon 13 May 15:15:01 UTC 2024 (1715613301)
UPDATE: Fri 17 May 11:29:43 UTC 2024 (1715945383)
BOOTFS: /boot/firmware
'/tmp/tmp.tWeQTpPTrQ' -> '/boot/firmware/pieeprom.upd'
UPDATING bootloader. This could take up to a minute. Please wait
*** Do not disconnect the power until the update is complete ***
If a problem occurs then the Raspberry Pi Imager may be used to create
a bootloader rescue SD card image which restores the default bootloader image.
flashrom -p linux_spi:dev=/dev/spidev10.0,spispeed=16000 -w /boot/firmware/pieeprom.upd
UPDATE SUCCESSFUL
*** Updating firmware
*** Updating kernel modules
*** depmod 6.6.30-v8+
*** depmod 6.6.30-v8-16k+
*** Updating VideoCore libraries
*** Running ldconfig
*** Storing current firmware revision
*** Deleting downloaded files
*** Syncing changes to disk
*** If no errors appeared, your firmware was successfully updated to 3b768c3f4d2b9a275fafdb53978f126d7ad72a1a
*** A reboot is needed to activate the new firmware
pcfe@raspi5:~ $ sudo reboot
Broadcast message from root@raspi5 on pts/1 (Sat 2024-05-18 14:59:19 CEST):
The system will reboot now!
pcfe@raspi5:~ $ Connection to raspi5.internal.pcfe.net closed by remote host.
Connection to raspi5.internal.pcfe.net closed.
Configured Using Ansible
Back in 2021, I had cobbled together what I learned from
- Playing music on a Raspberry Pi using UPnP and DLNA (v3).
- Raspbian Bullseye - Updating alsa options
- How can I use an external USB sound-card and set it as default?
- Banana Pi as UPnP music player (gstreamer1.0-alsa needs installing)
into an Ansible playbook. You will find an updated version further down below in this 2024 post.
Follow the above links if you are not comfortable with Ansible, it shows you how do the setup via bash. The reason I use Ansible for my setup is because a RasPi, especially the µSD card is cattle, not pets to me. So if something breaks, I want to be able to plonk a new one in, run a playbook that configures Raspbian and listen again to music in the home office room.
Inventory Entries
A couple inventory entries are needed for this playbook. Adjust to your username and RasPi hostname.
- My
…/ansible-inventory-housenet/hosts
is in INI format and has a line
raspi5.internal.pcfe.net
- Since this version of Raspberry Pi OS was installed without creating a user
pi
, but with creating a userpcfe
. This user, created via OS Customization in rpi-imager, can sudo without password. My…/ansible-inventory-housenet/host_vars/raspi5.internal.pcfe.net/ansible_user.yml
reads;
---
ansible_user: pcfe
- My
…/ansible-inventory-housenet/host_vars/raspi5.internal.pcfe.net/gmediarenderer.yml
reads;
---
gmediarender_logging: false
If I feel the need to debug, then I set gmediarender_logging: true
and read /var/log/gmediarender/gmediarender.log
.
Because the log is chatty, once a problem is resolved, I set the boolean back to false and re-run the play
to both disable logging and delete the log directory.
Template for Poweroff Timer, Systemd
My templates/timers/shutdown_12_hours_after_boot.timer.j2
reads;
[Unit]
Description=Poweroff 12 hours after boot
[Timer]
OnBootSec=12hours
Unit=systemd-poweroff.service
[Install]
WantedBy=timers.target
This powers down unconditionally 12 hours after powerup, adjust the number of OnBootSec=…
to your needs.
The Ansible Playbook
This is an adjusted version of my earlier playbook,
it’s shorter now as I got rid of the Argon case and
no longer fiddle with /lib/modprobe.d/aliases.conf
to force USB audio to a specific index
(which was then followed by configuring alsa to use that chosen index).
The Playbook, called type__entertainment_raspi_dlna__prepare.yml
, is meant to be self explanatory.
Hence the many comment lines and the long task names. Both are intentional.
code as docs and all that jazz.
Read it, adjust to your needs. Name it any name you want, I chose this rather long name because it is in a repository containing many other ansible plays.
For the steps marked optional: in the tl;dr section; what would need doing in a shell is hopefully obvious
after reading both my playbook and the other sources
(e,g, Edit some file and change foo to bar in bash is ansible.builtin.lineinfile:
with regexp: foo
and line: bar
in ansible.
Add a section [pi5] with these two lines … and before the section [all] in bash is ansible.builtin.blockinfile:
with insertbefore: ^\[all\]
in ansible.
After you edited the file, reboot with sudo shutdown -r now
in bash is notify: Handle rebooting
and ansible.builtin.reboot:
in ansible. You get the idea)
####################################################################################
# author: Patrick C. F. Ernzer <pcfe@pcfe.net>
# description: Configures a RasPi 5
# that is running RaspberryPi OS Lite (Debian 12)
# connected to my Teufel Cinebar One+
# for DLNA music player usage
# license: Creative Commons Attribution-ShareAlike 4.0 International License
# min_ansible_version: 2.14
####################################################################################
#
# used hardware:
# - Teufel Cinebar One+
# https://teufel.de/cinebar-one-105396000
# - Raspberry Pi 5
# https://www.raspberrypi.com/products/raspberry-pi-5/
# - KKSB Raspberry Pi 5 Case with Aluminium Heatsink for Silent Passive Cooling
# https://kksb-cases.com/products/kksb-raspberry-pi-5-case-with-aluminium-heatsink-for-silent-passive-cooling
---
- name: Ensure the Raspberry Pi is ready for DLNA renderer duties
hosts: raspi5.internal.pcfe.net
become: true
handlers:
- name: Handle restarting cpufrequtils.service
ansible.builtin.service:
name: cpufrequtils
state: restarted
changed_when: true
# please note that the service takes some 30 seconds to shutdown or restart
- name: Handle restarting gmediarenderer
ansible.builtin.service:
name: gmediarender
state: restarted
changed_when: true
- name: Handle systemd daemon reload
ansible.builtin.systemd:
daemon_reload: true
- name: Handle rebooting
ansible.builtin.reboot:
tasks:
# ensure the needed packages are installed
# I use ALSA simply because the author of gmediarender-resurrect uses ALSA
# https://github.com/hzeller/gmrender-resurrect/blob/master/INSTALL.md
# and gmrender-resurrect is the only thing I use this RasPi for.
# cpufrequtils because I want the ability to reduce idle power consumption
- name: Ensure wanted packages are present
ansible.builtin.package:
name:
- libupnp-dev
- libgstreamer1.0-dev
- gstreamer1.0-plugins-base
- gstreamer1.0-plugins-good
- gstreamer1.0-plugins-bad
- gstreamer1.0-plugins-ugly
- gstreamer1.0-libav
- gstreamer1.0-alsa
- cpufrequtils
state: present
- name: Ensure HDMI audio is disabled
ansible.builtin.lineinfile:
group: root
mode: u=rwx,g=rx,o=rx
owner: root
path: /boot/firmware/config.txt
regexp: '^dtoverlay=vc4-kms-v3d'
line: 'dtoverlay=vc4-kms-v3d,noaudio'
- name: Ensure all updates are applied
ansible.builtin.package:
update_cache: true
name: '*'
state: latest # noqa package-latest
tags: apply_errata
- name: Ensure gmrender-resurrect is installed, package name is gmediarender
ansible.builtin.package:
name:
- gmediarender
state: present
- name: Ensure gmediarender has no ALSA_DEVICE set, it should use the gstreamer default
ansible.builtin.lineinfile:
path: /etc/default/gmediarender
regexp: '^ALSA_DEVICE'
state: absent
notify: Handle restarting gmediarenderer
# I find the default volume too high for comfort, so lower it
- name: Ensure gmediarender has a more reasonable start volume of 40/100 than the default 75/100
ansible.builtin.lineinfile:
path: /etc/default/gmediarender
regexp: '^INITIAL_VOLUME_DB='
line: 'INITIAL_VOLUME_DB=-28'
notify: Handle restarting gmediarenderer
# For logging on/off, use the variable gmediarender_logging (bool)
- name: If logging is enabled, then ensure directory /var/log/gmediarender exists
ansible.builtin.file:
path: /var/log/gmediarender
state: directory
owner: root
group: audio
mode: u=rwx,g=rwx,o=rx
when: gmediarender_logging
- name: Ensure gmediarender DOES have logging enabled
ansible.builtin.lineinfile:
path: /etc/default/gmediarender
regexp: '^DAEMON_EXTRA_ARGS='
insertafter: '^# DAEMON_EXTRA_ARGS='
line: 'DAEMON_EXTRA_ARGS="--logfile /var/log/gmediarender/gmediarender.log"'
notify: Handle restarting gmediarenderer
when: gmediarender_logging
- name: If logging is disabled, then ensure /var/log/gmediarender does not exists
ansible.builtin.file:
path: /var/log/gmediarender
state: absent
when: not gmediarender_logging
- name: Ensure gmediarender does NOT have logging enabled
ansible.builtin.lineinfile:
path: /etc/default/gmediarender
regexp: '^DAEMON_EXTRA_ARGS='
insertafter: '^# DAEMON_EXTRA_ARGS='
line: 'DAEMON_EXTRA_ARGS=""'
notify: Handle restarting gmediarenderer
when: not gmediarender_logging
# as of 2024-05-18 I still get a SystemV init file from the
# Debian 12 gmediarender package. Since Debian 12 has wrappers to allow
# `systemctl […] gmediarender.service` commands to work just fine,
# for now just use that /etc/init.d/gmediarender
# even though stopping takes 30 secs,that's fine as systemd gives it
# 5 mins to get sorted, if it takes longer it is killed.
- name: Ensure gmediarender service is enabled and started
ansible.builtin.service:
name: gmediarender
enabled: true
state: started
# Currently I have no use for Bluetooth on this DLNA renderer,
# disable services that use it.
- name: Ensure Bluetooth using services I do no intend use are disabled and stopped
ansible.builtin.service:
name: '{{ item }}'
enabled: false
state: stopped
loop:
- hciuart
- bluetooth
# disable onboard Bluetooth and WiFi hardware
# using a model filter of [rp5]
# c.f. https://www.raspberrypi.com/documentation/computers/config_txt.html#model-filters
- name: Ensure WiFi and Bluetooth are disabled on RasPi 5
ansible.builtin.blockinfile:
dest: /boot/firmware/config.txt
block: |
[pi5]
dtoverlay=disable-bt-pi5
dtoverlay=disable-wifi-pi5
marker: "# {mark} Ansible Managed Block to disable BT and WiFi on RasPi5"
insertbefore: ^\[all\]
owner: root
group: root
mode: u=rwx,g=rx,o=rx
notify: Handle rebooting
- name: Check to see if we need a reboot, Debian style
ansible.builtin.stat:
path: /var/run/reboot-required
register: reboot_required_file
when: ansible_pkg_mgr == "apt"
- name: Notify the handler for rebooting, if Debian style hint file was found
ansible.builtin.debug:
msg: Found reboot hint file
when:
- reboot_required_file is defined
- reboot_required_file.stat.exists is defined
- reboot_required_file.stat.exists
changed_when: reboot_required_file.stat.exists
notify: Handle rebooting
# When I forget to shut down the RasPi manually,
# it should power itself down 12 hours after bootup.
- name: Ensure systemd-poweroff.timer for systemd is present
ansible.builtin.template:
src: timers/shutdown_12_hours_after_boot.timer.j2
dest: /etc/systemd/system/systemd-poweroff.timer
owner: root
group: root
mode: u=rw,g=r,o=r
notify: Handle systemd daemon reload
- name: Ensure timer to power off after 12 hours is both started and enabled
ansible.builtin.systemd:
name: systemd-poweroff.timer
state: started
enabled: true
# c.f. https://www.raspberrypi.com/documentation/computers/raspberry-pi.html#using-dvfs
- name: Ensure cpufrequtils service is enabled and running
ansible.builtin.service:
name: cpufrequtils
enabled: true
state: started
# on 2024-05-17 I still got an old style SysV init file with cpufrequtils, :sigh:
# actively setting this task to fail if the file does not exist, so that I can notice
# when cpufrequtils on Debian gets modernised to a modern unit file
- name: Ensure old style /etc/init.d/cpufrequtils uses the powersave governor
ansible.builtin.lineinfile:
path: /etc/init.d/cpufrequtils
regexp: '^GOVERNOR='
line: 'GOVERNOR="powersave"'
create: false
notify: Handle restarting cpufrequtils.service
How to Run the Playbook
Option 1: with ansible-navigator
ansible-navigator run type__entertainment_raspi_dlna__prepare.yml
When having the relevant ssh private key loaded into the ssh-agent(1) of the session you run navighator from,
then navigator will use that key to authenticate as ansible_user: …
when connecting to the RasPi.
Please note, I have an ansible-navigator.yml
pointing to the used inventory and setting a few other options I like to use.
Click to see my Ansible Navigator configuration file.
ansible-navigator.yml
in the directory I run the the playbook from.
Do not copy blindly, edit to your needs, especially location of inventory.
And maybe also the location of log files, making the host’s CA trust available to the execution environment, set how navigator will open a file when you type :o
, etc.
I use AAP 2.4’s ee-minimal-rhel8
in this config file.
You can use any Execution Environment (EE) Image you want
(for example ghcr.io/ansible/creator-ee
).
options: O
in volume-mounts:
alows the EE both to have your hosts’s ca-trust available
and allows the EE to adjust it’s ca-trust but those changes in the EE will not end up on your host.
Create the directory navigator-output and add it to your .gitignore
---
# RTFM at https://ansible.readthedocs.io/projects/navigator/settings/
ansible-navigator:
ansible:
inventory:
entries:
- ../../../HouseNet/ansible-inventory-housenet/hosts
- ../../../HouseNet/ansible-vault-housenet/empty-hosts-file-to-make-ansible-happy.ini
ansible-runner:
artifact-dir: navigator-output/runner/
rotate-artifacts-count: 10
execution-environment:
container-engine: podman
enabled: true
image: registry.redhat.io/ansible-automation-platform-24/ee-minimal-rhel8
pull:
policy: missing
environment-variables:
set:
ANSIBLE_LOG_PATH: navigator-output/ansible.log
volume-mounts:
- src: /etc/pki/ca-trust
dest: /etc/pki/ca-trust
options: O
logging:
append: false
file: navigator-output/ansible-navigator.log
playbook-artifact:
enable: true
save-as: navigator-output/{playbook_name}-artifact-{time_stamp}.json
editor:
command: codium -g {filename}:{line_number}
console: false
Also note that I actually
ANSIBLE_VAULT_PASSWORD_FILE=.vault_password.sh ansible-navigator run …
simply because I have 2 inventories configured in the git repository the playbook lives in and one of them is a collection of vaulted files (none of which is needed for this one play though).
Click to see my .vault_password.sh script.
.vault_password.sh
in the directory I run the the playbook from.
#!/bin/sh
#
# See section "Store the vault password in an environment variable" at
# https://ansible.readthedocs.io/projects/navigator/faq/#how-can-i-use-a-vault-password-with-ansible-navigator
#
# put your password in an env var, but not in your bash history
# obviously not only set history control, but also remember to actually use a leading space
# after that this scriptlet will echo your password and ansible tooling (-playbook, -vault,
# -navigator, etc) is happy to use this script as vault password source
# Set the environment variable to the location of the file when executing ansible-navigator
#
# use as follows
# user@host $ HISTCONTROL=ignorespace
# user@host $ export ANSIBLE_VAULT_PASSWORD=my_password
# user@host $ ANSIBLE_VAULT_PASSWORD_FILE=.vault_password.sh ansible-navigator run site.yml
echo ${ANSIBLE_VAULT_PASSWORD}
If you are not a bash user, then adjust the exclusion of the export ANSIBLE_VAULT_PASSWORD=my_password
command from your shell’s history (zsh, fish or whichever your shell of choice is).
Option 2: with ansible-playbook
You can of course also run this old-school with ansible-playbook
if you are not using ansible-navigator.
ansible-playbook \
--inventory […some path…]/hosts \
type__entertainment_raspi_dlna__prepare.yml
Playing Music via DLNA
Obvious if you used DLNA before, but in case this is your first use of DLNA;
- If off (LED red), boot the RasPi by shortly pressing the power button on the case, Wait a moment for the RasPi to finish booting.
- Ensure the Cinebar is on and set to Bluetooth input, wait for LED to be solid blue (USB and BT use the same input. When the Cinebar is still starting up, the LED pulses).
- Open your preferred DLNA control point on a device of your choice (on Android I use BubbleUPnP).
- select a media library of your choice (I use ReadyMedia (aka minidlna) on a Linux server).
- select your RasPi as renderer, by default it is called gmediarender on $(hostname).
- via your DLNA control point, you manage
- choice of song
- playlist (n.b. the playlist resides on your control point, not the renderer)
- volume
- play, pause, seek, stop, next/previous track
Be patient when waiting for DLNA devices to appear, if your setup is suboptimal, wait easily 10 minutes or more for your music server to appear.
Usage Notes
Ideally you would shut down both the RasPi and the Cinebar when not in use, to save some energy.
The RasPi 5 comes with a power buton, no additional software or setup needed. Press it briefly to initiate shutdown.
Because I chose Raspberry Pi OS (64-bit) Lite, I have no desktop session, which means a clean shutdown is triggered, without additional dialogs to click OK in, by briefly pressing the power button. Exactly the behaviour I want.
To force a hard shutdown, press and hold the power button.
Avoid doing that, prefer the clean shutown.
The Cinebar will enter low power mode (LED is red) by itself if no audio is played for a while.
If, like me, you frequently forget to power down the RasPi, then consider setting up an automatic shutdown timer as shown in the playbook.
Why Did I Start from Scratch
Reason for New OS Install
Normally, on Debian, I upgrade from one stable release to the next, but the Raspberry Pi OS docs say
Upgrading an existing image is sometimes possible, but is not guaranteed to work in every circumstance, and we do not recommend it.
Never touch a running system is a dumb idea, security updates need applying and when an operating system version is at End of Life, then it’s time to pick a newer base OS version.
Reasons for Playbook Changes
This was really just a cleanup job of the playbook I used for my Debian 11 plus RasPi 4B based setup, With the RasPi 5 I could drop quite a few tasks I needed back then for the Argon software.
Reason for New Hardware
The idea was to simply re-use the RasPi 4B and Argon ONE, but while the Argon 40’s instructions to
curl https://download.argon40.com/argon1.sh | bash
already annoyed me in the past, under bookworm I was really not having much joy getting the install script itself andd the softeware the script installs to work reliably.
As I feared, I was not alone in having trouble with the vendor’s software under Debian 12. It seems the vendor is taking way too long to support a Debian version that was released over half a year ago for my taste.
While https://gitlab.com/DarkElvenAngel/argononed worked better that the vendor software, it always bothered me that RasPis, up to and including the 4B, do not come with power on/off control out of the box.
Because the Raspberry Pi 5 comes with a power button, if I upgraded from a 4B to a 5, then I would not need software outside of the Debian 12 repos.
Since I only use this RasPi for playing music, I decided to pick a passively cooled case.
Because I play the music over USB, not HDMI, I decided to disable HDMI audio.
I setled on a KKSB Raspberry Pi 5 Case with Aluminium Heatsink for Silent Passive Cooling, it’s silent, small and has a simple plastic bit that presses the power button on the RasBerry Pi 5 itself.
So far passive cooling keeps it cool enough for my taste.
Before switching to the powersave governor, well below 55°C when playing a song.
pcfe@raspi5:~ $ vcgencmd measure_temp
temp=52.7'C
And with the powersave governor I do not even reach 51°C on the RasPi even though ambient temperature in the room is 28.3°C.
Lowest I saw so far when playing music was
pcfe@raspi5:~ $ vcgencmd measure_temp
temp=48.3'C
and the highest
pcfe@raspi5:~ $ vcgencmd measure_temp
temp=50.5'C
TODO
- revisit post when this has been in active use for a few weeks
- maybe use
gstout_buffer_duration: 0