Mender-enabled OS images for Raspberry Pi 5 radar nodes. The image comes pre-loaded with Docker, SDRplay API, Avahi mDNS, and a WiFi captive portal for easy setup.
- Docker CE with Compose plugin
- SDRplay API v3.15 for RSPDuo hardware
- SDRconnect v1.0.5 for standalone SDR analysis
- Chrony for NTP clock disciplining
- Cloudflared for secure tunneling
- Avahi mDNS for
<hostname>.localdiscovery - WiFi Connect captive portal for network setup
- Mender client for OTA updates
-
Flash the image to an SD card (64GB+) using Raspberry Pi Imager
- Download from Releases
- Select
owl-os-vx.x.x.imgas custom OS - Do not apply OS customisation settings
-
Boot and connect to WiFi
- Connect to the
node-setupWiFi network - Captive portal opens automatically (or go to http://192.168.42.1)
- Enter your WiFi credentials - node reboots and connects
- Connect to the
-
Accept device in Mender
- Node appears as "pending" once online
- Accept to enable OTA updates
-
Deploy retina-node stack via Mender OTA
Cloud services (mender-authd, mender-updated, mender-connect) are handled differently between the two build artifacts:
.img(fresh flash) — cloud services are disabled by default.mender.confis backed up to/data/mender-cloud-disabled/and the three Mender systemd services are masked. The user must consent via the retina-gui install flow to enable them..mender(OTA artifact) — cloud services are re-enabled viadebugfsin theimage2menderpost-processing step. This is required becausemender-updatedmust start after reboot to runArtifactVerifyRebootand commit the update — without it the update hangs and rolls back.
After install, users can toggle cloud services on/off from http://owl.local. The preference persists across reboots and OTA updates. Toggling is blocked while any update is in progress.
During a retina-node install, retina-gui holds an install.lock in /data/retina-gui/ to prevent concurrent installs and block cloud service toggling mid-update. The lock is released on completion (success or failure) with a 40-minute stale timeout as a safety net. Mender state scripts write a separate mender-update.status file for real-time progress polling (downloading → installing → done).
After deploying retina-node, visit http://owl.local to configure capture settings, location, ADS-B truth source, and tar1090. See retina-node for details.
To enable Cloudflare tunnel forwarding, create a token file on the node:
sudo mkdir -p /data/cloudflared
echo "YOUR_TUNNEL_TOKEN" | sudo tee /data/cloudflared/tunnel-token
sudo chmod 600 /data/cloudflared/tunnel-token
sudo systemctl restart cloudflaredThe token persists across OTA updates.
End users: Add your SSH key via the web GUI at http://owl.local after boot. Once added, connect with:
ssh node@owl.local
# or by IP
ssh node@<ip-address>Keys persist across reboots and OTA updates.
Developers: Public keys can be baked into the image at build time by adding them to ssh_pub_keys/:
cp ~/.ssh/id_ed25519.pub ssh_pub_keys/yourname.pubTag a commit with os-vx.x.x and push:
git tag os-v1.0.0
git push origin os-v1.0.0This triggers the GHA workflow (.github/workflows/build_os.yml) which:
- Builds OS image and Mender artifact
- Uploads to GitHub Releases
- Uploads Mender artifact to OffWorld Lab Mender server
Note: Currently triggers on any
os-v*tag. TODO: Change to only PR merges into main.
Run in server mode (headless device):
/opt/sdrconnect/SDRconnect --serverConnect from a SDRconnect client on another machine using the Pi's IP.
Warning: Conflicts with blah2 - stop containers first:
cd /data/mender-docker-compose/current/manifests && docker compose -p retina-node down
For GitHub Actions: tenant token is added via GH secrets.
For local builds: Create a custom config file:
echo 'mender_tenant_token: "YOUR_TOKEN_HERE"' > configuration/mender/mender_custom.ymlThis file is .gitignored to prevent accidental commits.
Install EDI and dependencies:
Ubuntu 24.04 or newer:
sudo apt install buildah containers-storage crun curl distrobox \
dosfstools e2fsprogs fakeroot genimage git mender-artifact \
mmdebstrap mtools parted python3-sphinx python3-testinfra \
podman rsync zerofreeedi -v project make owl-os-pi5.ymlOutput artifacts:
owl-os-vx.x.x.img- Flashable OS image with A/B partitioningowl-os-vx.x.x.mender- OTA update artifact
edi -v project clean owl-os-pi5.yml- Username:
node - Password:
raspberry