changes
This commit is contained in:
233
raspberry/build-snapcast-zero-sd.sh
Executable file
233
raspberry/build-snapcast-zero-sd.sh
Executable file
@@ -0,0 +1,233 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# build_rpi_sd_no_chroot_auto.sh
|
||||
#
|
||||
# Fully automated Raspberry Pi SD card creation script WITHOUT chroot.
|
||||
# When the Pi boots the first time, it installs snapclient automatically.
|
||||
#
|
||||
# WARNING: This script will format and overwrite $SD_DEVICE!
|
||||
# Make sure you set $SD_DEVICE correctly.
|
||||
|
||||
set -e
|
||||
|
||||
#######################################
|
||||
# CONFIGURATION #
|
||||
#######################################
|
||||
# Where to download Raspberry Pi OS Lite if not found
|
||||
IMG_URL="https://downloads.raspberrypi.org/raspios_lite_armhf_latest"
|
||||
|
||||
# The exact .img filename you expect after extraction/unzipping
|
||||
EXPECTED_IMG="rpi_os_lite_latest.img"
|
||||
# Adjust to match the real image name. If the official download is .xz or .zip,
|
||||
# you might need to adapt the script below.
|
||||
|
||||
# Your SD card device (e.g., /dev/sdb, /dev/mmcblk0)
|
||||
SD_DEVICE="/dev/sda"
|
||||
|
||||
# Wi-Fi credentials
|
||||
WIFI_SSID="Cloonar-Multimedia"
|
||||
WIFI_PASS="K2MC28Zhk\$4zsx6Y"
|
||||
WIFI_COUNTRY="AT"
|
||||
|
||||
# Snapserver IP or hostname
|
||||
SNAPSERVER_HOST="snapcast.cloonar.com"
|
||||
|
||||
#######################################
|
||||
# FILE NAMES & PATHS ON THE PI #
|
||||
#######################################
|
||||
# We'll copy a systemd service and script into the Pi's root filesystem.
|
||||
FIRSTBOOT_SCRIPT="/usr/local/bin/firstboot.sh"
|
||||
FIRSTBOOT_SERVICE="/etc/systemd/system/firstboot.service"
|
||||
|
||||
#######################################
|
||||
# DOWNLOAD IMAGE IF NEEDED #
|
||||
#######################################
|
||||
download_image_if_needed() {
|
||||
if [[ ! -f "$EXPECTED_IMG" ]]; then
|
||||
echo ">>> $EXPECTED_IMG not found, downloading from $IMG_URL..."
|
||||
wget -O rpi_os_lite_latest.img.xz "$IMG_URL"
|
||||
echo ">>> Unzipping..."
|
||||
# unzip rpi_os_lite_latest.zip || true
|
||||
# If you get a .xz, un-comment:
|
||||
xz -dv *.xz
|
||||
|
||||
if [[ ! -f "$EXPECTED_IMG" ]]; then
|
||||
echo "ERROR: Expected .img file '$EXPECTED_IMG' not found after extraction!"
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
echo ">>> Using existing image file: $EXPECTED_IMG"
|
||||
fi
|
||||
}
|
||||
|
||||
#######################################
|
||||
# WRITE IMAGE TO SD #
|
||||
#######################################
|
||||
write_image_to_sd() {
|
||||
echo ">>> Writing $EXPECTED_IMG to $SD_DEVICE..."
|
||||
umount "${SD_DEVICE}"* || true
|
||||
dd if="$EXPECTED_IMG" of="$SD_DEVICE" bs=4M conv=fsync status=progress
|
||||
sync
|
||||
}
|
||||
|
||||
#######################################
|
||||
# MOUNT BOOT & ROOTFS #
|
||||
#######################################
|
||||
mount_partitions() {
|
||||
if [[ $SD_DEVICE == *"mmcblk"* ]]; then
|
||||
BOOT_PART="${SD_DEVICE}p1"
|
||||
ROOT_PART="${SD_DEVICE}p2"
|
||||
else
|
||||
BOOT_PART="${SD_DEVICE}1"
|
||||
ROOT_PART="${SD_DEVICE}2"
|
||||
fi
|
||||
|
||||
mkdir -p /mnt/rpi-boot
|
||||
mkdir -p /mnt/rpi-root
|
||||
|
||||
echo ">>> Mounting boot partition ($BOOT_PART) -> /mnt/rpi-boot"
|
||||
mount "$BOOT_PART" /mnt/rpi-boot
|
||||
|
||||
echo ">>> Mounting root partition ($ROOT_PART) -> /mnt/rpi-root"
|
||||
mount "$ROOT_PART" /mnt/rpi-root
|
||||
}
|
||||
|
||||
unmount_partitions() {
|
||||
echo ">>> Unmounting partitions..."
|
||||
umount /mnt/rpi-boot || true
|
||||
umount /mnt/rpi-root || true
|
||||
sync
|
||||
}
|
||||
|
||||
#######################################
|
||||
# PREPARE BOOT PARTITION (NO CHROOT)
|
||||
#######################################
|
||||
enable_ssh_wifi_hifiberry() {
|
||||
echo ">>> Enabling SSH..."
|
||||
touch /mnt/rpi-boot/ssh
|
||||
|
||||
echo ">>> Creating wpa_supplicant.conf..."
|
||||
cat << EOF > /mnt/rpi-boot/wpa_supplicant.conf
|
||||
country=$WIFI_COUNTRY
|
||||
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
|
||||
update_config=1
|
||||
|
||||
network={
|
||||
ssid="$WIFI_SSID"
|
||||
psk="$WIFI_PASS"
|
||||
}
|
||||
EOF
|
||||
|
||||
echo ">>> Enabling HiFiBerry Amp+ overlay in config.txt..."
|
||||
cat << EOF >> /mnt/rpi-boot/config.txt
|
||||
|
||||
# --- HiFiBerry Amp+ overlay ---
|
||||
dtoverlay=hifiberry-amp
|
||||
dtparam=audio=off
|
||||
EOF
|
||||
}
|
||||
|
||||
#######################################
|
||||
# INSTALL FIRST-BOOT SERVICE/SCRIPT
|
||||
# (PLACED INTO THE Pi ROOTFS)
|
||||
#######################################
|
||||
install_firstboot_autosetup() {
|
||||
echo ">>> Creating first-boot script ($FIRSTBOOT_SCRIPT) in Pi root filesystem..."
|
||||
|
||||
cat << 'FOO' > /mnt/rpi-root$FIRSTBOOT_SCRIPT
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
|
||||
echo ">>> [FIRST BOOT] Installing snapclient..."
|
||||
|
||||
# Update system
|
||||
apt-get update
|
||||
apt-get upgrade -y
|
||||
|
||||
# Install snapclient
|
||||
apt-get install -y snapclient
|
||||
|
||||
# Configure snapclient
|
||||
cat << SCLIENT > /etc/default/snapclient
|
||||
SNAPCLIENT_OPTS="--host SNAPSERVER_PLACEHOLDER"
|
||||
SCLIENT
|
||||
|
||||
systemctl enable snapclient
|
||||
systemctl start snapclient
|
||||
|
||||
echo ">>> [FIRST BOOT] Snapclient installation complete."
|
||||
|
||||
# Disable this service so it doesn't run again
|
||||
systemctl disable firstboot.service
|
||||
|
||||
# Optional: remove script & service
|
||||
rm -f /usr/local/bin/firstboot.sh
|
||||
rm -f /etc/systemd/system/firstboot.service
|
||||
FOO
|
||||
|
||||
# Replace placeholder with actual snapserver host
|
||||
sed -i "s|SNAPSERVER_PLACEHOLDER|$SNAPSERVER_HOST|g" /mnt/rpi-root$FIRSTBOOT_SCRIPT
|
||||
|
||||
# Make it executable
|
||||
chmod +x /mnt/rpi-root$FIRSTBOOT_SCRIPT
|
||||
|
||||
|
||||
echo ">>> Creating first-boot systemd service ($FIRSTBOOT_SERVICE)..."
|
||||
cat << EOF > /mnt/rpi-root$FIRSTBOOT_SERVICE
|
||||
[Unit]
|
||||
Description=Run once at first boot to install snapclient
|
||||
After=network-online.target
|
||||
Wants=network-online.target
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
ExecStart=$FIRSTBOOT_SCRIPT
|
||||
RemainAfterExit=true
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOF
|
||||
|
||||
echo ">>> Enabling firstboot.service so it runs automatically..."
|
||||
# We can manually create the symlink to "enable" it:
|
||||
mkdir -p /mnt/rpi-root/etc/systemd/system/multi-user.target.wants
|
||||
ln -s $FIRSTBOOT_SERVICE /mnt/rpi-root/etc/systemd/system/multi-user.target.wants/firstboot.service
|
||||
}
|
||||
|
||||
|
||||
#######################################
|
||||
# MAIN #
|
||||
#######################################
|
||||
main() {
|
||||
# 1) Download image if needed
|
||||
download_image_if_needed
|
||||
|
||||
# 2) Write image to SD
|
||||
write_image_to_sd
|
||||
|
||||
# 3) Mount partitions
|
||||
mount_partitions
|
||||
|
||||
# 4) Enable SSH, Wi-Fi, HiFiBerry in /boot
|
||||
enable_ssh_wifi_hifiberry
|
||||
|
||||
# 5) Place the "first boot" script & service in / (root partition)
|
||||
install_firstboot_autosetup
|
||||
|
||||
# 6) Unmount
|
||||
unmount_partitions
|
||||
|
||||
echo "=============================================================="
|
||||
echo "Done! The SD card is fully configured for auto snapclient setup."
|
||||
echo "Insert it into your Pi, power on, and wait a couple of minutes."
|
||||
echo ""
|
||||
echo "What happens on first boot:"
|
||||
echo " 1. Pi connects to Wi-Fi, SSH is enabled"
|
||||
echo " 2. 'firstboot.service' runs once, installs snapclient, configures it"
|
||||
echo " 3. The service disables itself and removes the script"
|
||||
echo ""
|
||||
echo "No user intervention is required. Enjoy!"
|
||||
echo "=============================================================="
|
||||
}
|
||||
|
||||
main "$@"
|
||||
Reference in New Issue
Block a user