User Data Partition¶
This directory contains the writable user partition for the gateway.
Overview¶
Unlike the root filesystem (read-only SquashFS), the userdata partition uses JFFS2 — a writable, wear-leveling filesystem designed for flash memory.
This partition is essential because:
- The rootfs
/etcsymlinks most configuration files here - All init scripts are stored here (the rootfs only contains a bootstrap)
- User applications and customizations live here
This design allows modifying configuration and adding services without rebuilding the read-only rootfs.
Boot Integration¶
The rootfs bootstrap (/etc/init.d/rcS) mounts this partition at /userdata, then executes all scripts matching /userdata/etc/init.d/S??* in alphanumeric order.
Rootfs bootstrap
↓
Mount /userdata (JFFS2)
↓
Execute init scripts:
S05syslog → Start system logging
S10network → Configure network (DHCP or static)
S15hostname → Set hostname, /etc/hosts
S20time → Sync time via NTP
S30dropbear → Start SSH server
S60serialgateway → Start Zigbee bridge (if radio mode = zigbee)
S70otbr → Start Thread border router (if radio mode = otbr)
S90checkpasswd → Warn if default password
Partition Structure¶
/userdata/
├── etc/
│ ├── passwd # User accounts (with password hashes)
│ ├── group # User groups
│ ├── hostname # Gateway hostname
│ ├── profile # Shell profile (TERM, TERMINFO, resize)
│ ├── motd # Message of the day
│ ├── TZ # Timezone
│ ├── ntp.conf # NTP server configuration
│ ├── eth0.bak # Static IP template (for reference)
│ ├── radio.conf # Radio mode: MODE=otbr for Thread (absent = Zigbee)
│ ├── dropbear/ # Dropbear SSH host keys (generated on first boot)
│ └── init.d/ # Init scripts (executed by rootfs bootstrap)
│ ├── S05syslog
│ ├── S10network
│ ├── S15hostname
│ ├── S20time
│ ├── S30dropbear
│ ├── S60serialgateway
│ ├── S70otbr
│ └── S90checkpasswd
├── ssh/
│ └── authorized_keys # SSH public keys for passwordless access
├── thread/ # Thread network credentials (created by otbr-agent)
└── usr/
├── bin/ # User applications (nano, serialgateway, otbr-agent, ot-ctl, boothold)
└── share/
└── terminfo/ # Terminal definitions (linux, vt100, vt102, xterm)
Network Configuration¶
flash_userdata.sh asks for network configuration and radio mode at flash time.
The settings are baked into userdata.bin before flashing.
To change the IP after flashing, edit /userdata/etc/eth0.conf on the running gateway:
Format:
Then restart the network: /userdata/etc/init.d/S10network restart
/userdata/etc/eth0.bak is provided as a reference template.
Radio Mode¶
The gateway supports two radio modes, selected at flash time:
| Mode | Config | Init script | EFR32 firmware | Use case |
|---|---|---|---|---|
| Zigbee (default) | no radio.conf |
S60serialgateway |
NCP or RCP+zigbeed | Zigbee2MQTT, ZHA |
| Thread | MODE=otbr |
S70otbr |
OT-RCP | Matter, Home Assistant Thread |
The mode is controlled by /userdata/etc/radio.conf. When set to Thread mode, S60serialgateway is skipped and S70otbr starts otbr-agent instead.
See ot-br-posix/README.md for Thread-specific documentation.
Switching Radio Mode¶
To switch between modes on a running gateway:
Thread → Zigbee:
# 1. Stop otbr-agent
/userdata/etc/init.d/S70otbr stop
# 2. Remove radio.conf (reverts to Zigbee mode)
rm /userdata/etc/radio.conf
# 3. Reflash EFR32 with NCP firmware (from your workstation)
./flash_efr32.sh <GATEWAY_IP>
# Select [2] NCP-UART-HW
# 4. Gateway reboots — serialgateway starts automatically
Zigbee → Thread:
# 1. Stop serialgateway
/userdata/etc/init.d/S60serialgateway stop
# 2. Set radio mode to Thread
echo "MODE=otbr" > /userdata/etc/radio.conf
# 3. Reflash EFR32 with OT-RCP firmware (from your workstation)
./flash_efr32.sh <GATEWAY_IP>
# Select [3] RCP-UART-HW
# 4. Gateway reboots — otbr-agent starts automatically
Alternatively, reflash userdata with flash_userdata.sh which prompts for the radio mode.
SSH Passwordless Access¶
The /userdata/ssh/authorized_keys file allows SSH access without a password. Add your public key to this file:
# On your workstation, copy your public key
cat ~/.ssh/id_rsa.pub
# Add it to authorized_keys on the gateway
echo "ssh-rsa AAAA... user@host" >> /userdata/ssh/authorized_keys
Dropbear is configured to read this file, enabling secure key-based authentication.
Contents¶
| Directory/File | Description |
|---|---|
skeleton/ |
Base structure for the user partition |
nano/ |
GNU nano text editor build |
serialgateway/ |
Zigbee serial gateway build |
ot-br-posix/ |
OpenThread Border Router build |
build_userdata.sh |
Script to assemble and package the partition |
Building¶
# Build nano (optional)
cd nano && ./build_nano.sh && cd ..
# Build serialgateway
cd serialgateway && ./build_serialgateway.sh && cd ..
# Build otbr-agent (optional, for Thread mode)
cd ot-br-posix && ./build_otbr.sh && cd ..
# Assemble and package userdata
./build_userdata.sh
Output¶
userdata.bin— Flashable JFFS2 image with Realtek header (~12 MB)
Included Applications¶
nano¶
Lightweight text editor for editing configuration files directly on the gateway.
Terminal support: nano requires terminal capability definitions (terminfo) to display correctly. The profile sets up TERMINFO to point to /userdata/usr/share/terminfo/ which includes definitions for common terminal types:
| Terminal | Use case |
|---|---|
linux |
Direct console access |
vt100 |
Basic serial terminal |
vt102 |
Minicom, PuTTY (VT102 mode) |
xterm |
SSH from modern terminals |
If your terminal emulator uses a different type, you can add the corresponding terminfo file to /userdata/usr/share/terminfo/<first-letter>/<name>.
Terminal size: The profile automatically runs resize at login to detect the terminal dimensions. This ensures nano and other curses applications display at the correct size.
serialgateway¶
A lightweight serial-to-TCP bridge that exposes the Zigbee UART (/dev/ttyS1) over the network. This allows Zigbee2MQTT, Home Assistant ZHA, or other Zigbee coordinators to communicate with the Silabs EFR32 radio remotely.
Default configuration:
- Listens on TCP port 8888
- Connects to /dev/ttyS1 at 115200 baud
- Single client mode (new connection closes the previous one)
Options:
| Option | Description |
|--------|-------------|
| -p <port> | TCP port to listen on (default: 8888) |
| -d <device> | Serial device (default: /dev/ttyS1) |
| -b <baud> | Baud rate (default: 115200) |
| -f | Disable hardware flow control (default: enabled) |
| -D | Stay in foreground (don't daemonize) |
| -q | Quiet mode (suppress info messages) |
| -v | Show version and exit |
| -h | Show help |
Usage with Zigbee2MQTT:
Usage with Home Assistant ZHA:
Adding Custom terminfo¶
To add support for additional terminal types:
-
On a Linux system with the desired terminfo, locate the file:
-
Copy it to the gateway:
-
Set the terminal type:
Adding Your Own Applications¶
Cross-compiling applications for the gateway is straightforward. Use the existing build_*.sh scripts as templates:
-
Cross-compile your application using the toolchain:
-
Strip the binary to reduce size:
-
Transfer to the gateway via SSH:
The application is immediately available — no reboot required.
Adding Custom Init Scripts¶
To add a new service that starts at boot:
- Create a script in
/userdata/etc/init.d/with a name likeS70myservice - Make it executable:
chmod +x S70myservice - The script should accept
start,stop, and optionallyrestartarguments
Example:
#!/bin/sh
case "$1" in
start)
echo "Starting myservice..."
/userdata/usr/bin/myservice &
;;
stop)
echo "Stopping myservice..."
killall myservice
;;
restart)
$0 stop
$0 start
;;
esac
The number prefix (S70) determines execution order — lower numbers run first.
Mount Point¶
The userdata partition is mounted at /userdata by the rootfs bootstrap. The rootfs /etc symlinks point here, making this partition the source of truth for all configuration.