-
-
Notifications
You must be signed in to change notification settings - Fork 0
Pi Image Setup Guide
This page describes how I create the image file used on the Raspberry Pi. Regular users don't need this, but I've put this here for reference and because others might find this useful.
All steps are performed on a Linux machine with the Raspberry Pi SD card mounted via a card reader. The root partition is assumed to be mounted at /media/$USER/rootfs and the boot partition at /media/$USER/bootfs.
Requirements: This guide targets Raspberry Pi OS Trixie Lite. Both 32-bit and 64-bit are supported. Use the 32-bit image for the Pi Zero W, and the 64-bit image for the Pi Zero 2W, Pi 3, Pi 4, or Pi 5.
Did you find this tool useful? Feel free to support my open source tools - especially when using them commercially:
Trixie includes cloud-init, which handles first-boot configuration via two files on the boot partition:
-
user-data- creates the user, sets the hostname, installs Python dependencies, and starts our bridge service -
network-config- configures WiFi
Users only need to edit network-config to enter their WiFi credentials before first boot. Both files live on the FAT32 boot partition, so they are editable on Windows, Mac, and Linux without needing root.
lsblkIdentify the device (e.g. /dev/sda) and note where the partitions are mounted, for example:
-
Root partition ->
/media/$USER/rootfs -
Boot partition ->
/media/$USER/bootfs
If the partitions are not mounted yet:
sudo mkdir -p /media/$USER/rootfs /media/$USER/bootfs
sudo mount /dev/sda2 /media/$USER/rootfs
sudo mount /dev/sda1 /media/$USER/bootfsThese two files replace the wifi-setup service, user creation, and first-boot service from the old approach. They go on the boot partition and are processed automatically on first boot by cloud-init.
This is the file end users edit to connect to their WiFi network. Replace the existing network-config on the boot partition:
cat > /media/$USER/bootfs/network-config << 'EOF'
network:
version: 2
wifis:
wlan0:
dhcp4: true
# Change this to your country code (ISO 3166-1 alpha-2)
regulatory-domain: "NL"
access-points:
"YourNetworkName":
password: "YourPassword"
optional: false
EOFThis creates the bridge user, sets the hostname, installs Python dependencies on first boot, enables the bridge service, and disables cloud-init after it has run. Replace the existing user-data on the boot partition:
(generate the hashed password using: echo 'littleprinterlives' | openssl passwd -6 -stdin)
cat > /media/$USER/bootfs/user-data << 'EOF'
#cloud-config
hostname: little-printer-bridge
manage_etc_hosts: false
timezone: Europe/Amsterdam
users:
- name: bridge
groups: users,adm,dialout,audio,netdev,video,plugdev,cdrom,games,input,gpio,spi,i2c,render,sudo
shell: /bin/bash
lock_passwd: false
passwd: "$6$boqkDuR6gaVxXbFA$glw/miVRIqHulbFK0Bebyyov0NKQ3z7tlyUS7RYkXGjDozcEiSG.jSw2IDSI/ghItMpaJx/92Zajr.v6ebqmU1"
enable_ssh: false
rpi:
i2c: true
spi: true
# Install system-level dependencies
package_update: true
packages:
- libopenjp2-7
- python3-pip
- git
- libfreetype-dev
# Run once on first boot after network is up
runcmd:
# Clone the repository into /opt
- git clone https://github.com/javl/little-printer-zigbee-bridge.git /opt/little-printer-zigbee-bridge
# Install Python dependencies
- cd /opt/little-printer-zigbee-bridge && pip3 install -r bridge/requirements.txt --break-system-packages
# Enable and start the bridge service
- systemctl enable little-printer-zigbee-bridge.service
- systemctl start little-printer-zigbee-bridge.service
# Disable cloud-init
- touch /etc/cloud/cloud-init.disabled
EOFThis is the only systemd service we still need to create manually, since cloud-init does not have a built-in way to define persistent services.
sudo tee /media/$USER/rootfs/etc/systemd/system/little-printer-zigbee-bridge.service << 'EOF'
[Unit]
Description=Little Printer Zigbee Bridge Script
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=bridge
WorkingDirectory=/opt/little-printer-zigbee-bridge
ExecStartPre=/bin/sh -c 'until ping -c1 1.1.1.1 > /dev/null 2>&1; do sleep 2; done'
ExecStart=/usr/bin/env python3 -m bridge.main --sirius
Restart=on-failure
RestartSec=10
[Install]
WantedBy=multi-user.target
EOFNote: the service is not enabled here - cloud-init's runcmd enables it on first boot after dependencies are installed.
Not needed anymore: we now just clone the repo on the first start.
Copy the bridge project onto the image. Ownership will be fixed by cloud-init's runcmd on first boot.
sudo cp -r /path/to/little-printer-zigbee-bridge /media/$USER/rootfs/opt/little-printer-zigbee-bridge
Restore network-config to placeholder values - the same file from step 2a but with your actual credentials replaced:
cat > /media/$USER/bootfs/network-config << 'EOF'
network:
version: 2
wifis:
wlan0:
dhcp4: true
# Change this to your country code (ISO 3166-1 alpha-2)
regulatory-domain: "NL"
access-points:
"YourNetworkName":
password: "YourPassword"
optional: true
EOFsudo rm -f /media/$USER/rootfs/root/.bash_history
sudo rm -f /media/$USER/rootfs/home/bridge/.bash_historysudo rm -f /media/$USER/rootfs/etc/machine-id
sudo rm -f /media/$USER/rootfs/var/lib/dbus/machine-id
sudo touch /media/$USER/rootfs/etc/machine-idAn empty /etc/machine-id triggers a fresh ID to be generated on first boot.
sudo rm -rf /media/$USER/rootfs/var/log/journal/*
sudo rm -rf /media/$USER/rootfs/var/log/*.log
sudo rm -rf /media/$USER/rootfs/tmp/*
sudo rm -rf /media/$USER/rootfs/var/tmp/*sudo umount /media/$USER/rootfs
sudo umount /media/$USER/bootfsReplace /dev/sda with your actual device from lsblk:
sudo dd if=/dev/sda of=~/little-printer-zigbee-bridge.img bs=4M status=progresswget https://raw.githubusercontent.com/Drewsif/PiShrink/master/pishrink.sh
chmod +x pishrink.sh
sudo ./pishrink.sh -z ~/little-printer-zigbee-bridge.imgThis creates little-printer-zigbee-bridge.img.gz, compressed and shrunk to the minimum size needed.
- Download
little-printer-zigbee-bridge.img.gzand flash it to an SD card using Raspberry Pi Imager or balenaEtcher - After flashing, open the boot partition of the SD card (visible on Windows, Mac, and Linux as a small FAT drive)
- Open
network-configand replaceYourNetworkNameandYourPasswordwith your WiFi credentials - Optionally update
regulatory-domainto your country code (e.g.GB,US,DE) - Save the file, eject the SD card, and insert it into the Raspberry Pi
- Power on - the Pi will configure WiFi, install Python dependencies, and start the bridge automatically on first boot. The first boot takes a little longer than usual while dependencies are installed.
Bridge does not start Check the cloud-init log to see if first-boot setup completed:
sudo cat /var/log/cloud-init-output.logWiFi never comes up Check NetworkManager and the network-config that was applied:
sudo systemctl status NetworkManager
sudo cat /var/log/cloud-init-output.log | grep -i networkScript starts before network is ready
The ExecStartPre ping loop should make the script wait until internet is reachable.
Check bridge service status
sudo systemctl status little-printer-zigbee-bridge.service
sudo journalctl -u little-printer-zigbee-bridge.service