diff --git a/01-prerequisites.md b/01-prerequisites.md new file mode 100644 index 0000000..37e21c6 --- /dev/null +++ b/01-prerequisites.md @@ -0,0 +1,32 @@ +# Prerequisites + +## System Requirements + +**Fresh Raspberry Pi OS (Lite/Bookworm recommended)** + +The installation script will automatically install the required packages, but if you prefer manual installation: + +```bash +sudo apt update && sudo apt upgrade -y +sudo apt install darkice icecast2 alsa-utils -y +sudo reboot +``` + +## Hardware Requirements + +- Raspberry Pi (any model, including Pi Zero 2W) +- USB audio interface (record player → RCA/3.5mm → USB) +- Reliable power supply (USB audio hates undervoltage - use a quality power adapter) +- Network connection (WiFi or Ethernet) + +## Software Requirements + +- Raspberry Pi OS (Debian-based) +- Git (usually pre-installed) +- Sudo access + +## Notes + +- The Pi Zero 2W works great for this setup +- USB audio disconnections are fixed by the wrapper script and USB audio configuration +- A stable power supply is critical - undervoltage causes USB audio issues diff --git a/02-deploy.sh b/02-deploy.sh new file mode 100755 index 0000000..cac0152 --- /dev/null +++ b/02-deploy.sh @@ -0,0 +1,30 @@ +#!/bin/bash +set -euo pipefail + +echo "šŸ–„ļø Deploying Record Player → Sonos AUX..." + +cd /home/pi + +# Copy files +cp 03-darkice-wrapper.sh . +cp 04-sonos-aux.service /etc/systemd/system/sonos-aux.service +cp darkice.cfg.example darkice.cfg # Edit your passwords! + +chmod +x darkice-wrapper.sh +sudo chown root:audio darkice-wrapper.sh +sudo chmod 755 darkice-wrapper.sh + +# Fix USB audio = card 0 always +echo "blacklist snd_bcm2835" | sudo tee -a /etc/modprobe.d/raspi-blacklist.conf +sudo sed -i 's/^options snd-usb-audio index=-2/#options snd-usb-audio index=-2/' /lib/modprobe.d/aliases.conf + +# Icecast setup (one-time) +sudo systemctl enable icecast2 +sudo systemctl start icecast2 + +# Systemd service +sudo systemctl daemon-reload +sudo systemctl enable sonos-aux.service + +echo "āœ… Reboot to finish: sudo reboot" +echo "Then check: journalctl -u sonos-aux.service -f" diff --git a/03-darkice-wrapper.sh b/03-darkice-wrapper.sh new file mode 100755 index 0000000..7567aae --- /dev/null +++ b/03-darkice-wrapper.sh @@ -0,0 +1,24 @@ +#!/usr/bin/env bash +set -euo pipefail + +MAX_WAIT_SEC=90 +SLEEP_STEP=2 +DARKICE_CMD="/usr/bin/darkice -c /home/pi/darkice.cfg" + +log() { echo "[$(date '+%H:%M:%S')] $*" >&2; } + +log "ā³ Waiting for ALSA card 0 (USB audio)..." + +elapsed=0 +while ! arecord -l 2>/dev/null | grep -q "^card 0:"; do + if (( elapsed >= MAX_WAIT_SEC )); then + log "šŸ’„ FATAL: No card 0 after ${MAX_WAIT_SEC}s" + arecord -l || true + exit 1 + fi + sleep "${SLEEP_STEP}" + elapsed=$((elapsed + SLEEP_STEP)) +done + +log "āœ… Card 0 ready! Launching DarkIce." +exec ${DARKICE_CMD} diff --git a/04-sonos-aux.service b/04-sonos-aux.service new file mode 100644 index 0000000..ba382ee --- /dev/null +++ b/04-sonos-aux.service @@ -0,0 +1,18 @@ +[Unit] +Description=Record player AUX stream to Sonos +After=network-online.target sound.target icecast2.service +Wants=network-online.target +StartLimitIntervalSec=0 +StartLimitBurst=0 + +[Service] +Type=simple +User=pi +Group=audio +WorkingDirectory=/home/pi +ExecStart=/home/pi/darkice-wrapper.sh +Restart=always +RestartSec=10 + +[Install] +WantedBy=multi-user.target diff --git a/README.md b/README.md index 11d3ee8..1c069eb 100644 --- a/README.md +++ b/README.md @@ -4,8 +4,9 @@ > **Repo Structure:** ``` ā”œā”€ā”€ README.md ← This file +ā”œā”€ā”€ install.sh ← šŸš€ ONE-COMMAND INSTALL (NEW!) ā”œā”€ā”€ 01-prerequisites.md -ā”œā”€ā”€ 02-deploy.sh ← One-command setup +ā”œā”€ā”€ 02-deploy.sh ← Manual deploy script ā”œā”€ā”€ 03-darkice-wrapper.sh ← USB wait + DarkIce launcher ā”œā”€ā”€ 04-sonos-aux.service ← Systemd unit (Pi OS compatible) ā”œā”€ā”€ darkice.cfg.example ← Your config template @@ -14,12 +15,40 @@ *** -## Quick Deploy (New Pi) +## šŸš€ One-Command Installation (Recommended) + +**Just run this on your Pi Zero 2:** + ```bash -git clone -cd record-player-sonos-aux +curl -fsSL https://git.geertrademakers.nl/master/sonos-aux-recordplayer-pi/raw/branch/master/install.sh | bash +``` + +Or with wget: +```bash +wget -qO- https://git.geertrademakers.nl/master/sonos-aux-recordplayer-pi/raw/branch/master/install.sh | bash +``` + +**What it does:** +- āœ… Installs all prerequisites (darkice, icecast2, alsa-utils) +- āœ… Clones/updates the repository +- āœ… Configures USB audio as card 0 (fixes disconnections!) +- āœ… Deploys all files and systemd service +- āœ… Sets up Icecast2 +- āœ… Enables auto-start on boot + +**After installation:** +1. Edit config: `nano /home/pi/darkice.cfg` (change password!) +2. Reboot: `sudo reboot` +3. Verify: `journalctl -u sonos-aux.service -f` + +--- + +## Quick Deploy (Manual - Alternative Method) +```bash +git clone https://git.geertrademakers.nl/master/sonos-aux-recordplayer-pi.git +cd sonos-aux-recordplayer-pi chmod +x *.sh -sudo ./02-deploy.sh +sudo ./install.sh ``` **Full guide below** ↓ @@ -187,6 +216,80 @@ curl -s http://localhost:8000/status-json.xsl | grep -o 'http[^<]*' 1. Add Sonos radio station: `http://:8000/rapi.mp3` 2. Works with any Sonos speaker/group! +## šŸ”§ Stability Fixes (Recommended for 24/7) + +Raspberry Pi Zero W/2W often loses WiFi due to power management. These steps ensure rock-solid uptime. + +### 1. Disable WiFi PowerSave (systemd service) + +```bash +sudo nano /etc/systemd/system/wifi-powermanagement-off.service +``` + +```ini +[Unit] +Description=Disable WiFi Power Management +After=network.target + +[Service] +Type=oneshot +ExecStart=/sbin/iwconfig wlan0 power off +RemainAfterExit=yes + +[Install] +WantedBy=multi-user.target +``` + +```bash +sudo systemctl daemon-reload +sudo systemctl enable wifi-powermanagement-off +sudo systemctl start wifi-powermanagement-off +``` + +**Verify:** `iwconfig` should show `Power Management:off` [web:27][web:28] + +### 2. Hardware Watchdog (Network + Load Monitoring) + +```bash +sudo apt install watchdog -y +sudo nano /etc/watchdog.conf +``` + +**Replace with this optimal config:** +```ini +watchdog-device = /dev/watchdog +interval = 20 +retry-timeout = 180 +ping = 192.168.1.1 # Your UniFi gateway +ping = 1.1.1.1 # Cloudflare backup +ping-count = 3 +realtime = yes +priority = 50 +max-load-1 = 24 +max-load-5 = 0 +max-load-15 = 0 +``` + +```bash +sudo systemctl enable watchdog +sudo systemctl start watchdog +``` + +**Test safely:** `sudo systemctl status watchdog` + `sudo journalctl -u watchdog -f` + +### 3. Verify Everything + +After reboot: +```bash +iwconfig # Power Management:off +systemctl status watchdog # active (running) +journalctl -u watchdog -n20 # Recent heartbeats +``` + +This combo prevents WiFi dropouts + auto-recovers from hangs/freezes while keeping your Sonos AUX stream running 24/7. + +**Reference:** [Watchdog Service for Raspberry Pi](https://xavier.arnaus.net/blog/watchdog-service-for-raspberry-pi-machines) + ## šŸ› ļø Troubleshooting | Issue | Fix | diff --git a/darkice.cfg.example b/darkice.cfg.example new file mode 100644 index 0000000..558f733 --- /dev/null +++ b/darkice.cfg.example @@ -0,0 +1,20 @@ +[general] +duration = 0 +bufferSecs = 2 # USB stability +reconnect = yes + +[input] +device = plughw:0,0 # USB card 0 (fixed by modprobe) +sampleRate = 44100 +bitsPerSample = 16 +channel = 2 + +[icecast2-0] +bitrateMode = cbr +format = mp3 +bitrate = 320 +server = localhost +port = 8000 +password = hackme # ← CHANGE to your Icecast source password +mountPoint = rapi.mp3 # Sonos URL: http://pi-ip:8000/rapi.mp3 +name = Record Player diff --git a/install.sh b/install.sh new file mode 100755 index 0000000..9783c1f --- /dev/null +++ b/install.sh @@ -0,0 +1,162 @@ +#!/bin/bash +set -euo pipefail + +# Master installation script for Record Player Pi → Sonos AUX +# Usage: curl -fsSL https://git.geertrademakers.nl/master/sonos-aux-recordplayer-pi/raw/branch/master/install.sh | bash +# Or: wget -qO- https://git.geertrademakers.nl/master/sonos-aux-recordplayer-pi/raw/branch/master/install.sh | bash + +REPO_URL="https://git.geertrademakers.nl/master/sonos-aux-recordplayer-pi.git" +INSTALL_DIR="/home/pi/sonos-aux-recordplayer-pi" +USER_HOME="/home/pi" + +log() { + echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" >&2 +} + +error() { + log "āŒ ERROR: $*" + exit 1 +} + +success() { + log "āœ… $*" +} + +info() { + log "ā„¹ļø $*" +} + +# Check if running as root for certain operations +check_sudo() { + if ! sudo -n true 2>/dev/null; then + info "This script requires sudo privileges. You may be prompted for your password." + fi +} + +# Detect if we're on a Raspberry Pi +check_pi() { + if [ ! -f /proc/device-tree/model ] || ! grep -q "Raspberry Pi" /proc/device-tree/model 2>/dev/null; then + info "āš ļø Warning: This doesn't appear to be a Raspberry Pi. Continuing anyway..." + fi +} + +# Install prerequisites +install_prerequisites() { + info "Installing prerequisites..." + + sudo apt-get update -qq + sudo apt-get install -y darkice icecast2 alsa-utils curl wget git || error "Failed to install prerequisites" + + success "Prerequisites installed" +} + +# Clone or update repository +setup_repo() { + if [ -d "$INSTALL_DIR" ]; then + info "Repository exists, updating..." + cd "$INSTALL_DIR" + git pull || error "Failed to update repository" + else + info "Cloning repository..." + git clone "$REPO_URL" "$INSTALL_DIR" || error "Failed to clone repository" + cd "$INSTALL_DIR" + fi + + success "Repository ready" +} + +# Fix USB audio to always be card 0 +fix_usb_audio() { + info "Configuring USB audio as card 0..." + + # Blacklist built-in audio + if ! grep -q "blacklist snd_bcm2835" /etc/modprobe.d/raspi-blacklist.conf 2>/dev/null; then + echo "blacklist snd_bcm2835" | sudo tee -a /etc/modprobe.d/raspi-blacklist.conf >/dev/null + fi + + # Fix USB audio index + if [ -f /lib/modprobe.d/aliases.conf ]; then + sudo sed -i 's/^options snd-usb-audio index=-2/#options snd-usb-audio index=-2/' /lib/modprobe.d/aliases.conf + fi + + success "USB audio configuration updated (reboot required for full effect)" +} + +# Deploy files +deploy_files() { + info "Deploying files..." + + # Copy wrapper script + sudo cp "$INSTALL_DIR/03-darkice-wrapper.sh" "$USER_HOME/darkice-wrapper.sh" + sudo chmod +x "$USER_HOME/darkice-wrapper.sh" + sudo chown root:audio "$USER_HOME/darkice-wrapper.sh" + sudo chmod 755 "$USER_HOME/darkice-wrapper.sh" + + # Copy systemd service + sudo cp "$INSTALL_DIR/04-sonos-aux.service" /etc/systemd/system/sonos-aux.service + + # Copy config if it doesn't exist + if [ ! -f "$USER_HOME/darkice.cfg" ]; then + cp "$INSTALL_DIR/darkice.cfg.example" "$USER_HOME/darkice.cfg" + info "šŸ“ Created darkice.cfg - please edit password and mountPoint!" + else + info "darkice.cfg already exists, skipping..." + fi + + success "Files deployed" +} + +# Setup Icecast +setup_icecast() { + info "Setting up Icecast2..." + + sudo systemctl enable icecast2 || true + sudo systemctl start icecast2 || true + + success "Icecast2 configured" +} + +# Setup systemd service +setup_service() { + info "Setting up systemd service..." + + sudo systemctl daemon-reload + sudo systemctl enable sonos-aux.service + + success "Systemd service enabled" +} + +# Main installation +main() { + log "šŸš€ Starting Record Player Pi → Sonos AUX installation..." + + check_sudo + check_pi + + install_prerequisites + setup_repo + fix_usb_audio + deploy_files + setup_icecast + setup_service + + echo "" + success "Installation complete!" + echo "" + info "Next steps:" + echo " 1. Edit darkice.cfg: nano $USER_HOME/darkice.cfg" + echo " - Change 'password' to your Icecast source password" + echo " - Change 'mountPoint' if desired" + echo "" + echo " 2. Reboot: sudo reboot" + echo "" + echo " 3. After reboot, verify:" + echo " - journalctl -u sonos-aux.service -f" + echo " - Or run: $INSTALL_DIR/verify.sh" + echo "" + echo " 4. Add to Sonos: http://:8000/rapi.mp3" + echo "" +} + +# Run main function +main "$@" diff --git a/verify.sh b/verify.sh new file mode 100755 index 0000000..9ad06ec --- /dev/null +++ b/verify.sh @@ -0,0 +1,12 @@ +#!/bin/bash +echo "šŸ” USB Audio Check:" +arecord -l | grep "card 0" || echo "āš ļø No card 0 found" + +echo -e "\nšŸ“Š Service Status:" +systemctl status sonos-aux.service --no-pager || echo "āš ļø Service not running" + +echo -e "\nšŸ“œ Last 20 log lines:" +journalctl -u sonos-aux.service -n20 --no-pager || echo "āš ļø No logs found" + +echo -e "\n🌐 Icecast streams:" +curl -s http://localhost:8000/status-json.xsl 2>/dev/null | grep -o 'http[^<]*' || echo "āš ļø Icecast not responding"