8.0 KiB
Automatic eMMC provisioning for reTerminal DM4 (CM4)
This guide covers:
- Auto-flash: When the reTerminal is switched to boot mode (eMMC disable jumper) and connected via USB to a provisioning host, the host automatically deploys a golden image to the CM4 eMMC.
- Backup: When a device is detected (USB or network), the dashboard asks you to choose Backup or Deploy. Backup saves the device eMMC to a timestamped file in
backups/. - Network: If the device boots over the network and runs the provisioning client (see
network-client/), it registers with the dashboard and appears as "Device (Network)"; you then choose Backup or Deploy. Deploy streams the golden image to the device; Backup uploads the device eMMC to the server. - Cloud-init: The golden image includes cloud-init so each device configures itself on first boot (hostname, network, packages, kiosk setup).
Part 1: Auto-flash when reTerminal is in boot mode
How it works
- reTerminal has an eMMC disable jumper (see reTerminal docs; often “J2” or “nRPIBOOT”). When the jumper is fitted, the CM4 boots in USB device mode and waits for
rpibootfrom the host. - You connect the reTerminal’s USB slave port to a provisioning PC (Linux).
- udev detects the Raspberry Pi Foundation USB device (vendor
2b8e) and runs a trigger script. - The trigger starts a flash job that:
- Runs rpiboot (from the
usbbootproject). The CM4 then exposes its eMMC as a USB mass-storage device. - After
rpibootexits, finds the new block device (eMMC) and writes your golden image to it withdd.
- Runs rpiboot (from the
- You remove the jumper and power cycle; the reTerminal boots from eMMC and runs cloud-init on first boot.
Provisioning host setup (Linux)
1. Build and install usbboot (rpiboot)
sudo apt-get install -y libusb-1.0-0-dev
git clone --depth=1 https://github.com/raspberrypi/usbboot
cd usbboot
make
sudo mkdir -p /opt/usbboot
sudo cp rpiboot /opt/usbboot/
2. Create golden image and config directory
-
Build your golden image (see Part 2) and place it where the script will find it, e.g.:
sudo mkdir -p /var/lib/cm4-provisioning sudo cp /path/to/your/golden-reterminal.img /var/lib/cm4-provisioning/golden.img -
Or use a different path and set
GOLDEN_IMAGEwhen installing the script (see below).
3. Install the auto-flash script and trigger
# From this repo (chromium-setup/emmc-provisioning/)
SCRIPT_DIR="$(pwd)"
sudo mkdir -p /opt/cm4-provisioning
sudo cp flash-emmc-on-connect.sh /opt/cm4-provisioning/
sudo chmod +x /opt/cm4-provisioning/flash-emmc-on-connect.sh
# Optional: override paths via environment (create env file)
echo 'GOLDEN_IMAGE=/var/lib/cm4-provisioning/golden.img' | sudo tee /opt/cm4-provisioning/env
echo 'RPIBOOT_DIR=/opt/usbboot' | sudo tee -a /opt/cm4-provisioning/env
echo 'EMMC_SIZE_BYTES=8589934592' | sudo tee -a /opt/cm4-provisioning/env # 8GB; use 17179869184 for 16GB
sudo cp cm4-flash-trigger.sh /usr/local/bin/
sudo chmod +x /usr/local/bin/cm4-flash-trigger.sh
If your golden image path or rpiboot path is different, set GOLDEN_IMAGE, RPIBOOT_DIR, and optionally EMMC_SIZE_BYTES in /opt/cm4-provisioning/env and source it from the script, or pass them into the systemd-run call in the trigger (e.g. by making the trigger source the env file and export variables before systemd-run).
4. Install udev rule
sudo cp 90-cm4-boot-mode.rules /etc/udev/rules.d/
sudo udevadm control --reload-rules
sudo udevadm trigger
5. Enable provisioning (safety)
Provisioning runs only if the “enabled” file exists:
sudo mkdir -p /etc/cm4-provisioning
sudo touch /etc/cm4-provisioning/enabled
To disable auto-flash, remove that file: sudo rm /etc/cm4-provisioning/enabled.
6. Optional: pass environment into the flash job
If you use /opt/cm4-provisioning/env, update the trigger so the flash script sees those variables. For example change /usr/local/bin/cm4-flash-trigger.sh to:
#!/usr/bin/env bash
set -a
[[ -f /opt/cm4-provisioning/env ]] && source /opt/cm4-provisioning/env
set +a
export GOLDEN_IMAGE RPIBOOT_DIR EMMC_SIZE_BYTES
FLASH_SCRIPT="${CM4_FLASH_SCRIPT:-/opt/cm4-provisioning/flash-emmc-on-connect.sh}"
exec systemd-run --no-block --unit=cm4-flash-once --property=Environment="GOLDEN_IMAGE=$GOLDEN_IMAGE" ...
Or keep it simple and edit the defaults inside flash-emmc-on-connect.sh (e.g. GOLDEN_IMAGE, RPIBOOT_DIR, EMMC_SIZE_BYTES).
Usage
- Fit the eMMC disable jumper on the reTerminal.
- Connect the reTerminal USB slave port to the provisioning PC.
- Power the reTerminal (or apply power after USB).
- On the host,
rpibootwill run automatically; when it exits, the script willddthe golden image to the eMMC. Watch logs:journalctl -u cm4-flash-once -forjournalctl -t cm4-flash -f. - When done, remove the jumper and power cycle the reTerminal. It will boot from eMMC; cloud-init will run on first boot.
Part 2: Golden image with cloud-init
Raspberry Pi OS (recent versions) supports cloud-init using the NoCloud datasource: it reads user-data, meta-data, and optionally network-config from the boot (FAT32) partition.
Creating the golden image
- Flash Raspberry Pi OS (or your base image) to a spare SD card or a loop file.
- Mount the boot partition (first partition, FAT32). On the image file it might be at an offset; use
losetup -Por mount the SD’s partition. - Add cloud-init NoCloud files on the boot partition (same level as
config.txt, not in a subfolder for default NoCloud):user-data– main config (packages, runcmd, etc.)meta-data– optional (instance-id, local-hostname)network-config– optional (network config in netplan format)
You can use the examples in this repo:
# After mounting boot partition at e.g. /mnt/boot
# (On Raspberry Pi OS, boot is often /boot/firmware on the running system, or the first FAT partition of the image)
cp emmc-provisioning/cloud-init/user-data /mnt/boot/
cp emmc-provisioning/cloud-init/meta-data /mnt/boot/
cp emmc-provisioning/cloud-init/network-config /mnt/boot/
- Customise
user-dataandnetwork-config(hostname, WiFi, packages, Chromium kiosk, etc.). - Copy your kiosk/Chromium scripts into the image rootfs if needed (e.g. under
/home/pi/or/opt/) and reference them fromuser-dataruncmdor a systemd unit. - Unmount, then create a golden image from the SD or loop device (e.g.
ddorddof the whole block device). Use that asgolden.imgon the provisioning host.
Cloud-init file locations on the Pi
- NoCloud: Boot partition root –
user-data,meta-data,network-config. - Some images expect them in a subfolder
cloud-init/or on a separate vfat partition labeledcidata; check your OS docs. Standard Raspberry Pi OS NoCloud uses the boot partition root.
Per-device config (optional)
NoCloud can also use a seed partition or config drive. For per-device hostname/settings you can:
- Use meta-data
instance-idandlocal-hostnameand generate differentmeta-dataper device when imaging (e.g. script that writesmeta-databefore flashing), or - Use a first-boot script that calls a provisioning server (e.g. by serial number) and applies device-specific config; cloud-init can launch that script from
runcmd.
Summary
| Step | Action |
|---|---|
| 1 | Build usbboot, install rpiboot on provisioning host. |
| 2 | Create golden image with cloud-init user-data, meta-data, network-config on boot partition. |
| 3 | Install flash-emmc-on-connect.sh, cm4-flash-trigger.sh, and udev rule; set GOLDEN_IMAGE and enable file. |
| 4 | Put reTerminal in boot mode (jumper), connect USB to host; image is written automatically. |
| 5 | Remove jumper, power cycle; device boots from eMMC and cloud-init runs on first boot. |
This gives you automatic deployment of the golden image to eMMC when the reTerminal is in boot mode, plus first-boot configuration via cloud-init.