Orange Pi Zero 3 This guide shows how to integrate Thistle OTA on Orange Pi Zero 3. Start with a quick file‑update path (no A/B). Optionally, prepare your image for rootfs A/B, and pre‑enable SSH/Wi‑Fi before flashing.
Orange Pi Zero 3 uses Allwinner H618. Community images vary. Ensure you use a Linux image with U‑Boot and device tree overlays for I²C/SPI when needed. See community pinouts and I²C overlay guidance for related boards for enabling buses when integrating peripherals.

Board setup (vendor/community docs)

Flash the appropriate image for Zero 3 (Orange Pi OS or Armbian‑based), boot, and ensure SSH access.

Default Credentials

Login to your Orange Pi over serial or SSH using these defaults:
  • Orange Pi OS (official): oem / oem (default hostname: orange-os.local)

Prerequisites

  • Orange Pi Zero 3 with power supply and microSD card
  • Linux image (Ubuntu/Debian/Armbian‑based)
  • Network access
  • Linux/macOS workstation

Quick path: File updates (no A/B)

Use Thistle’s file‑update mode to ship signed files and app bundles without changing partitions. On Orange Pi OS the boot partition is mounted at /boot; use that as the persistent directory.
  1. Download tools
  • Workstation (TRH):
VER=1.5.0
curl -LO https://downloads.thistle.tech/embedded-client/$VER/trh-$VER-x86_64-unknown-linux-musl.gz
gunzip trh-$VER-x86_64-unknown-linux-musl.gz
chmod +x trh-$VER-x86_64-unknown-linux-musl && ln -sf trh-$VER-x86_64-unknown-linux-musl trh
  • Device (TUC on Zero 3, aarch64):
# On the device shell (SSH or serial)
VER=1.5.0
curl -LO https://downloads.thistle.tech/embedded-client/$VER/tuc-$VER-aarch64-unknown-linux-musl.gz
gunzip tuc-$VER-aarch64-unknown-linux-musl.gz
chmod +x tuc-$VER-aarch64-unknown-linux-musl
sudo mv tuc-$VER-aarch64-unknown-linux-musl /usr/local/bin/tuc
tuc --help | head -n 3
  1. Initialize and release a simple file update on the workstation
export THISTLE_TOKEN=$(cat)   # paste token, Enter, then Ctrl-D
./trh init --persist="/boot"

mkdir -p example && echo "hello from thistle" > example/app
# Install to /opt/example on device
./trh prepare --target=./example --file-base-path=/opt/example
./trh release
  1. Copy config to device and run client
# On workstation
scp config.json oem@orange-os.local:/tmp/tuc-config.json

# On device (SSH or serial)
sudo mv /tmp/tuc-config.json /boot/tuc-config.json
sudo tuc -c /boot/tuc-config.json
That’s it! File updates are fetched, verified, and installed atomically. Continue below only if you need rootfs A/B for boot‑time rollback.

Optional: Verify A/B partitions (if present)

Most Orange Pi OS images do not provision A/B partitions by default. If you’ve already created rootfsB (e.g., via the headless prep below) or your image includes it, SSH in and verify partitions:
ssh oem@orange-os.local
lsblk -o NAME,SIZE,FSTYPE,LABEL,MOUNTPOINT
Expected layout (names may vary by image):
  • p1 (vfat) mounted at /boot
  • p2 (ext4) mounted at /
  • p3 (ext4, label often rootfsB) present for A/B updates
If rootfsB is missing, follow the headless image prep section below to create it (resize rootfs and add a new rootfsB partition), then return here to verify.

Optional: Headless image prep (Orange Pi OS, aarch64)

Prepare an Orange Pi OS (aarch64) image before flashing: create rootfsB, enable SSH, preconfigure Wi‑Fi via NetworkManager, and set hostname. Docker is optional; any live Linux works.

1. Download the image

mkdir -p ~/opi-img && cd ~/opi-img
# Download an Orange Pi OS aarch64 image from the vendor and name it OrangePiOS_Arch64.img
# For example, if you have OrangePiOS_Arch64-<date>.img(.xz), place/decompress it here as OrangePiOS_Arch64.img

2. Start a Linux environment in Docker

docker run --rm -it --privileged -v "$PWD":/work ubuntu:24.04 bash
Inside the container:
apt-get update
apt-get install -y parted e2fsprogs kpartx util-linux
cd /work

3. Expand image size & map partitions

truncate -s +8G OrangePiOS_Arch64.img
losetup -Pf --show OrangePiOS_Arch64.img   # e.g. /dev/loop0
kpartx -av /dev/loop0                      # maps /dev/mapper/loop0p1, p2

4. Resize rootfs (p2) to 6 GiB

e2fsck -f /dev/mapper/loop0p2
resize2fs /dev/mapper/loop0p2 5900M
parted -s /dev/loop0 unit GiB resizepart 2 6
e2fsck -f /dev/mapper/loop0p2
resize2fs /dev/mapper/loop0p2

5. Create & format rootfsB

parted -s /dev/loop0 -a optimal mkpart primary ext4 6GiB 100%
kpartx -a /dev/loop0
mkfs.ext4 -F -L rootfsB /dev/mapper/loop0p3

6. Enable headless SSH + Wi‑Fi

Mount rootfs:
mkdir -p /mnt/root
mount /dev/mapper/loop0p2 /mnt/root

a) Enable SSH at boot

ln -sf /usr/lib/systemd/system/sshd.service \
  /mnt/root/etc/systemd/system/multi-user.target.wants/sshd.service

b) Add your SSH key

mkdir -p /mnt/root/home/oem/.ssh
chmod 700 /mnt/root/home/oem/.ssh
echo 'ssh-ed25519 AAAA...you@host' >> /mnt/root/home/oem/.ssh/authorized_keys
chmod 600 /mnt/root/home/oem/.ssh/authorized_keys
chroot /mnt/root chown -R oem:oem /home/oem/.ssh || true

c) Configure Wi‑Fi (NetworkManager profile)

mkdir -p /mnt/root/etc/NetworkManager/system-connections
cat > /mnt/root/etc/NetworkManager/system-connections/headless.nmconnection <<'EOF'
[connection]
id=headless
type=wifi
autoconnect=true

[wifi]
ssid=YOUR_SSID
mode=infrastructure

[wifi-security]
key-mgmt=wpa-psk
psk=YOUR_PASSWORD

[ipv4]
method=auto

[ipv6]
method=auto
EOF
chmod 600 /mnt/root/etc/NetworkManager/system-connections/headless.nmconnection

# Ensure NetworkManager is enabled
ln -sf /usr/lib/systemd/system/NetworkManager.service \
  /mnt/root/etc/systemd/system/multi-user.target.wants/NetworkManager.service

d) Set hostname (optional)

echo "orangepi" > /mnt/root/etc/hostname
Unmount:
umount /mnt/root

7. Cleanup

kpartx -dv /dev/loop0
losetup -d /dev/loop0
exit

8. Flash to SD (on macOS host)

diskutil list                         # locate your SD (e.g., /dev/disk3)
diskutil unmountDisk /dev/diskN       # replace diskN with your SD identifier
sudo dd if=OrangePiOS_Arch64.img of=/dev/rdiskN bs=4m status=progress
sync

9. First boot

  • Partitions:
    • p1 → boot (FAT)
    • p2 → rootfs (6 GiB ext4)
    • p3 → rootfsB (ext4, label rootfsB)
  • SSH enabled automatically
  • Wi‑Fi auto‑connects to your SSID
  • Hostname set to orangepi (or your choice)
Login:
ssh oem@orangepi.local
# or: ssh oem@<board-ip>

Thistle Tools

On the workstation and the device, download TRH/TUC as appropriate, then export your Project Access Token on the workstation.
# Workstation: TRH (prepare/release)
VER=1.5.0
curl -LO https://downloads.thistle.tech/embedded-client/$VER/trh-$VER-x86_64-unknown-linux-musl.gz
gunzip trh-$VER-x86_64-unknown-linux-musl.gz
chmod +x trh-$VER-x86_64-unknown-linux-musl && ln -sf trh-$VER-x86_64-unknown-linux-musl trh

# Device: TUC (install)
ssh oem@orange-os.local 'VER=1.5.0; curl -LO https://downloads.thistle.tech/embedded-client/$VER/tuc-$VER-aarch64-unknown-linux-musl.gz && gunzip tuc-$VER-aarch64-unknown-linux-musl.gz && chmod +x tuc-$VER-aarch64-unknown-linux-musl && sudo mv tuc-$VER-aarch64-unknown-linux-musl /usr/local/bin/tuc && tuc --help | head -n 3'

# Workstation: Project token for TRH
export THISTLE_TOKEN=$(cat)

Initialize and Prepare Rootfs Release

./trh init --persist="/boot"
./trh prepare --target=myrootfs.img
./trh release

Device Configuration

Create tuc-config.json:
{
  "name": "opi_zero3",
  "persistent_directory": "/boot",
  "public_keys": ["<YOUR_PUBLIC_KEY>"],
  "bootloader": "Thistle-U-Boot",
  "part_a": "/dev/mmcblk0p2",
  "part_b": "/dev/mmcblk0p3"
}
On Orange Pi OS, the boot chain typically uses U‑Boot; set bootloader to Thistle-U-Boot. Verify device nodes with lsblk and adjust part_a/part_b if yours differ.
Copy configuration to the board and persist under /boot:
scp tuc-config.json oem@orange-os.local:/tmp/
ssh oem@orange-os.local 'sudo cp /tmp/tuc-config.json /boot/tuc-config.json'

Run Update

ssh oem@orange-os.local
sudo tuc -c /boot/tuc-config.json
The device installs to the inactive slot and reboots. After reboot, run the client again to latch‑in the update.

Notes and Tips

  • Verify which storage node your rootfs partitions use (/dev/mmcblk0p2, /dev/mmcblk0p3).

References