Skip to content

Commit

Permalink
Refactor and add log cleaner (#11)
Browse files Browse the repository at this point in the history
* Refactor
* Clean-up linter integration
* RAM disk for logs
* Log cleaner
* Add opinionated choices to README
  • Loading branch information
rmens authored Mar 19, 2024
1 parent e6dde24 commit 77aa1e0
Show file tree
Hide file tree
Showing 4 changed files with 108 additions and 57 deletions.
7 changes: 5 additions & 2 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
name: linter
on:
pull_request:
paths:
- '**/*.sh'
push:

paths:
- '**/*.sh'
jobs:
lint:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v1
uses: actions/checkout@v4
- name: Run ShellCheck
uses: azohra/shell-linter@latest
40 changes: 23 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,25 +1,31 @@
# rpi-umpx-decoder
This repository contains the MicroMPX set-up for [ZuidWest FM](https://www.zuidwestfm.nl/) in the Netherlands. It uses a Rapsberry 4 or 5 and a [HiFiBerry DAC2 Pro XLR
](https://www.hifiberry.com/shop/boards/hifiberry-dac2-pro-xlr/) as audio output. It downloads the most recent version of the MicroMPX decoder from Thimeo, which is managed by systemd as service.
This repository contains the MicroMPX setup for [ZuidWest FM](https://www.zuidwestfm.nl/) in the Netherlands. It is compatible with Raspberry Pi 4 or 5 and uses a [HiFiBerry DAC2 Pro XLR](https://www.hifiberry.com/shop/boards/hifiberry-dac2-pro-xlr/) for audio output. The repository facilitates downloading the latest version of the MicroMPX decoder from Thimeo, which systemd manages as a service.

# How to prepare the Raspberry Pi
- Install Raspberry Pi OS Lite 12 (Bookworm)
- Ensure you are root by running `sudo su`
- Download and run the install script with the command `/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/oszuidwest/rpi-umpx-decoder/main/setup.sh)"`
- After a reboot MicroMPX should be running on `http://{{ip}}:8080`
# How to Prepare the Raspberry Pi
- Install Raspberry Pi OS Lite 12 (Bookworm).
- Ensure you are root by executing `sudo su`.
- Download and execute the installation script with the command: `/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/oszuidwest/rpi-umpx-decoder/main/setup.sh)"`.
- After rebooting, MicroMPX should be accessible at `http://{{ip}}:8080`.

## A few words about the Raspberry Pi 5
MicroMPX and HiFiBerry boards work well with the Raspberry Pi 5. There is currently [a bug](https://github.com/raspberrypi/linux/issues/5743) in the firmware that requires you to edit the `/boot/firwmare/config.txt` manually. Add `,slave` after the `dtoverlay` for the HiFiBerry. For example `dtoverlay=hifiberry-dacplus,slave`.
## A Few Words About the Raspberry Pi 5
MicroMPX and HiFiBerry boards are compatible with the Raspberry Pi 5. Currently, there is [a firmware bug](https://github.com/raspberrypi/linux/issues/5743) that necessitates manually editing the `/boot/firmware/config.txt` file. Add `,slave` to the `dtoverlay` line for the HiFiBerry, such as `dtoverlay=hifiberry-dacplus,slave`.

# How to add the Raspberry Pi to the VPN
- Download and run the VPN script with the command `/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/oszuidwest/rpi-umpx-decoder/main/vpn.sh)"`
- Check with `ip a` if you have an interface named `wg0` with the correct IP
- If the `wg0` interface is not showing, enable debugging with `modprobe wireguard && echo module wireguard +p > /sys/kernel/debug/dynamic_debug/control` and `tail -f /var/log/syslog` to look for errors
# How to Connect the Raspberry Pi to the VPN
- Download and execute the VPN script with the command: `/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/oszuidwest/rpi-umpx-decoder/main/vpn.sh)"`.
- Verify the presence of an interface named `wg0` with the correct IP using `ip a`.
- If the `wg0` interface does not appear, enable debugging with `modprobe wireguard && echo module wireguard +p > /sys/kernel/debug/dynamic_debug/control` and use `tail -f /var/log/syslog` to identify any errors.

## Optional heartbeat monitoring
You can optionally integrate heartbeat monitoring. In this case the Pi will `wget --spider` a given url every minute, acting as a heartbeat. This can be any url, but we tested with Uptime Robot. A paid account is required at Uptime Robot for heartbeat monitoring.
## Optional Heartbeat Monitoring
Optionally, heartbeat monitoring can be integrated. In this configuration, the Pi will execute `wget --spider` on a specified URL every minute to serve as a heartbeat. This can be any URL, but testing was conducted with [Uptime Robot](https://uptimerobot.com/?rid=6f699dbd539740). Note that a paid Uptime Robot account is required for heartbeat monitoring.

# Opinionated Modifications
This script introduces several modifications to the default MicroMPX behavior, which we believe enhance the setup:

1. Logs are automatically deleted after 7 days instead of the default 30 days in MicroMPX. A cron job is set up to manage this.
2. To preserve the SD card from excessive writes, logs are written to a RAM disk instead of the SD card. MicroMPX logs can be quite verbose, and without this modification, we have experienced failures with some SD cards.
3. The HDMI audio output is disabled, allowing the analog output to be used for signal monitoring. Therefore, we recommend using a Raspberry Pi 4, as it still offers an analog output.

# License
This project is licensed under the GPLv3 License - see the LICENSE.md file for details.
This project is licensed under the GPLv3 License - see the LICENSE file for details.

Bugs, feedback, and ideas are welcome at `techniek@zuidwesttv.nl` or through pull requests.
For bugs, feedback, and ideas, please contact us at `techniek@zuidwesttv.nl` or file a pull request with your idea.
2 changes: 1 addition & 1 deletion ramdisk.service
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ After=local-fs.target
[Service]
Type=oneshot
ExecStartPre=/bin/mkdir -p /mnt/ramdisk
ExecStart=/bin/mount -t tmpfs -o size=250m tmpfs /mnt/ramdisk
ExecStart=/bin/mount -t tmpfs -o size=256m tmpfs /mnt/ramdisk
RemainAfterExit=yes

[Install]
Expand Down
116 changes: 79 additions & 37 deletions setup.sh
Original file line number Diff line number Diff line change
@@ -1,17 +1,38 @@
#!/usr/bin/env bash

# Set-up the functions library
FUNCTIONS_LIB_PATH="/tmp/functions.sh"
FUNCTIONS_LIB_URL="https://raw.githubusercontent.com/oszuidwest/bash-functions/main/common-functions.sh"

# Set-up MicroMPX
MICROMPX_DECODER_PATH="/opt/micrompx/MicroMPX_Decoder"
MICROMPX_DECODER_URL="https://download.thimeo.com/MicroMPX_Decoder_ARM64"
MICROMPX_SERVICE_PATH="/etc/systemd/system/micrompx.service"
MICROMPX_SERVICE_URL="https://raw.githubusercontent.com/oszuidwest/rpi-umpx-decoder/logcleaner/micrompx.service"
MICROMPX_LOG_DIR="/home/micrompx/.MicroMPX_Decoder.log"

# Set-up RAM disk
RAMDISK_SERVICE_PATH="/etc/systemd/system/ramdisk.service"
RAMDISK_SERVICE_URL="https://raw.githubusercontent.com/oszuidwest/rpi-umpx-decoder/logcleaner/ramdisk.service"
RAMDISK_PATH="/mnt/ramdisk"

# General Raspberry Pi configuration
CONFIG_FILE_PATHS=("/boot/firmware/config.txt" "/boot/config.txt")
FIRST_IP=$(hostname -I | awk '{print $1}')

# Start with a clean terminal
clear

# Remove old functions libraries and download the latest version
rm -f /tmp/functions.sh
if ! curl -s -o /tmp/functions.sh https://raw.githubusercontent.com/oszuidwest/bash-functions/main/common-functions.sh; then
# Remove old functions library and download the latest version
rm -f "$FUNCTIONS_LIB_PATH"
if ! curl -s -o "$FUNCTIONS_LIB_PATH" "$FUNCTIONS_LIB_URL"; then
echo -e "*** Failed to download functions library. Please check your network connection! ***"
exit 1
fi

# Source the functions file
source /tmp/functions.sh
# shellcheck source=/tmp/functions.sh
source "$FUNCTIONS_LIB_PATH"

# Set color variables
set_colors
Expand All @@ -27,19 +48,20 @@ is_this_os_64bit
check_rpi_model 4

# Determine the correct config file path
if [ -f /boot/firmware/config.txt ]; then
CONFIG_FILE=/boot/firmware/config.txt
elif [ -f /boot/config.txt ]; then
CONFIG_FILE=/boot/config.txt
else
CONFIG_FILE=""
for path in "${CONFIG_FILE_PATHS[@]}"; do
if [ -f "$path" ]; then
CONFIG_FILE="$path"
break
fi
done

if [ -z "$CONFIG_FILE" ]; then
echo -e "${RED}Error: config.txt not found in known locations.${NC}"
exit 1
fi

# Determine the first IP address
FIRST_IP=$(hostname -I | awk '{print $1}')

# Something fancy for the sysadmin
# Banner
cat << "EOF"
______ _ ___ __ _ ______ __ __
|___ / (_) | \ \ / / | | | ____| \/ |
Expand All @@ -49,8 +71,12 @@ cat << "EOF"
/_____\__,_|_|\__,_| \/ \/ \___||___/\__| |_| |_| |_|
EOF

# Hi!
# Greeting
echo -e "${GREEN}⎎ MicroMPX Setup for Raspberry Pi${NC}\n\n"
ask_user "ENABLE_HEARTBEAT" "n" "Do you want to integrate heartbeat monitoring via UptimeRobot (y/n)" "y/n"
if [ "$ENABLE_HEARTBEAT" == "y" ]; then
ask_user "HEARTBEAT_URL" "https://heartbeat.uptimerobot.com/xxx" "Enter the URL to get every minute for heartbeat monitoring" "str"
fi

# Check and stop MicroMPX service if running
echo -e "${BLUE}►► Checking and stopping MicroMPX service if running...${NC}"
Expand Down Expand Up @@ -80,51 +106,67 @@ else
usermod -aG audio micrompx > /dev/null
fi

# Install dependencies for MicroMPX
install_packages silent libasound2 libsndfile1
# Install dependencies
install_packages silent libasound2 libsndfile1 wget

# Download MicroMPX from Thimeo
echo -e "${BLUE}►► Downloading and installing MicroMPX...${NC}"
mkdir -p /opt/micrompx > /dev/null
curl -s -o /opt/micrompx/MicroMPX_Decoder https://download.thimeo.com/MicroMPX_Decoder_ARM64
chmod +x /opt/micrompx/MicroMPX_Decoder > /dev/null
setcap CAP_NET_BIND_SERVICE=+eip /opt/micrompx/MicroMPX_Decoder > /dev/null
curl -s -o "$MICROMPX_DECODER_PATH" "$MICROMPX_DECODER_URL"
chmod +x "$MICROMPX_DECODER_PATH" > /dev/null
setcap CAP_NET_BIND_SERVICE=+eip "$MICROMPX_DECODER_PATH" > /dev/null

# Add service
echo -e "${BLUE}►► Installing MicroMPX service...${NC}"
rm -f /etc/systemd/system/micrompx.service > /dev/null
curl -s -o /etc/systemd/system/micrompx.service https://raw.githubusercontent.com/oszuidwest/rpi-umpx-decoder/main/micrompx.service
rm -f "$MICROMPX_SERVICE_PATH" > /dev/null
curl -s -o "$MICROMPX_SERVICE_PATH" "$MICROMPX_SERVICE_URL"
systemctl daemon-reload > /dev/null
systemctl enable micrompx > /dev/null

# Add RAM disk
echo -e "${BLUE}►► Setting up RAM disk for logs...${NC}"
rm -f /etc/systemd/system/ramdisk.service > /dev/null
curl -s -o /etc/systemd/system/ramdisk.service https://raw.githubusercontent.com/oszuidwest/rpi-umpx-decoder/main/ramdisk.service
rm -f "$RAMDISK_SERVICE_PATH" > /dev/null
curl -s -o "$RAMDISK_SERVICE_PATH" "$RAMDISK_SERVICE_URL"
systemctl daemon-reload > /dev/null
systemctl enable ramdisk > /dev/null
systemctl start ramdisk

# Put MicroMPX logs on RAM disk
echo -e "${BLUE}►► Putting MicroMPX logs on the RAM disk...${NC}"
if [ -d "/home/micrompx/.MicroMPX_Decoder.log" ]; then
echo -e "${YELLOW}Log directory exists. Removed if before creating the symlink.${NC}"
rm -rf /home/micrompx/.MicroMPX_Decoder.log
if [ -d "$MICROMPX_LOG_DIR" ]; then
echo -e "${YELLOW}Log directory exists. Removing it before creating the symlink.${NC}"
rm -rf "$MICROMPX_LOG_DIR"
fi
ln -s "$RAMDISK_PATH" "$MICROMPX_LOG_DIR"
chown -R micrompx:micrompx "$RAMDISK_PATH"

# Clean logs every 7 days to save space on the RAM disk (MicroMPX does this every 30 days)
LOGS_CRONJOB="0 0 * * * find -L $MICROMPX_LOG_DIR -type f -mtime +7 -exec rm {} \;"
echo -e "${BLUE}►► Setting up log file deletion cronjob...${NC}"
# Check if the crontab exists for the current user, create one if not
if ! crontab -l 2>/dev/null; then
echo "No crontab for $(whoami). Creating one..."
echo "" | crontab -
fi
# Add the new cron job if it does not already exist
if ! crontab -l | grep -F -- "$LOGS_CRONJOB" > /dev/null; then
(crontab -l 2>/dev/null; echo "$LOGS_CRONJOB") | crontab -
else
echo -e "${YELLOW}Log file deletion cronjob already exists. No changes made.${NC}"
fi
ln -s /mnt/ramdisk /home/micrompx/.MicroMPX_Decoder.log
chown -R micrompx:micrompx /mnt/ramdisk

# Heartbeat monitoring
ask_user "ENABLE_HEARTBEAT" "n" "Do you want to integrate heartbeat monitoring via UptimeRobot (y/n)" "y/n"
if [ "$ENABLE_HEARTBEAT" == "y" ]; then
ask_user "HEARTBEAT_URL" "https://heartbeat.uptimerobot.com/xxx" "Enter the URL to get every minute for heartbeat monitoring" "str"
# Add a cronjob that calls the HEARTBEAT_URL every minute
echo -e "${BLUE}►► Setting up heartbeat monitoring cronjob...${NC}"
(crontab -l 2>/dev/null; echo "* * * * * wget --spider $HEARTBEAT_URL > /dev/null 2>&1") | crontab -
echo -e "${GREEN}Heartbeat monitoring cronjob added.${NC}"
echo -e "${BLUE}►► Setting up heartbeat monitoring...${NC}"
HEARTBEAT_CRONJOB="* * * * * wget --spider $HEARTBEAT_URL > /dev/null 2>&1"
if ! crontab -l | grep -F -- "$HEARTBEAT_CRONJOB" > /dev/null; then
(crontab -l 2>/dev/null; echo "$HEARTBEAT_CRONJOB") | crontab -
else
echo -e "${YELLOW}Heartbeat monitoring cronjob already exists. No changes made.${NC}"
fi
fi

# Disable only the hdmi audio so we can use the minijack for monitoring
# Disable HDMI audio to use the mini-jack for monitoring
echo -e "${BLUE}►► Disabling onboard audio...${NC}"
sed -i '/dtoverlay=vc4-fkms-v3d/ { /audio=off/! s/$/,audio=off/ }' "$CONFIG_FILE" > /dev/null
sed -i '/dtoverlay=vc4-kms-v3d/ { /noaudio/! s/$/,noaudio/ }' "$CONFIG_FILE" > /dev/null
Expand All @@ -151,14 +193,14 @@ case $device_number in
*) echo -e "${RED}Invalid input, exiting.${NC}"; exit 1 ;;
esac
if ! grep -q "dtoverlay=$overlay" "$CONFIG_FILE" > /dev/null; then
echo -e "dtoverlay=$overlay" >> "$CONFIG_FILE"
echo "dtoverlay=$overlay" >> "$CONFIG_FILE"
fi

# Apply HifiBerry kernel fix if needed
echo -e "${BLUE}►► Checking Linux version and disabling onboard EEPROM if necessary...${NC}"
kernel_version=$(uname -r | awk -F. '{print $1 "." $2}')
if [ "$(printf '%s\n' "5.4" "$kernel_version" | sort -V | head -n1)" = "5.4" ] && [ "$kernel_version" != "5.4" ]; then
grep -q 'force_eeprom_read=0' "$CONFIG_FILE" || echo -e "force_eeprom_read=0" >> "$CONFIG_FILE"
grep -q 'force_eeprom_read=0' "$CONFIG_FILE" || echo "force_eeprom_read=0" >> "$CONFIG_FILE"
fi

# Reboot
Expand Down

0 comments on commit 77aa1e0

Please sign in to comment.