Tutorial: Install Gladys Assistant on a Home Assistant Yellow (Internal Zigbee)
Nov 7, 2026 · @XDECO
Introduction
This tutorial explains how to replace Home Assistant OS with Gladys Assistant (under Docker) on a Home Assistant Yellow, while keeping the Zigbee radio integrated into the board. The procedure has been carried out once, on a single Yellow: it is neither official on the Gladys side, nor on the Nabu Casa side.
Read before starting:
- The installation erases Home Assistant OS and all SSD content. Back up what you want to keep.
- The Zigbee radio must receive firmware adapted to Zigbee2MQTT (step 1). Do this from Home Assistant OS, before erasing it.
- In our test, Wi-Fi does not work (missing firmware): connect the Yellow via Ethernet.
- Only Zigbee, Ethernet, and NVMe SSD have been verified. The other functions of the board (Wi-Fi, Bluetooth, clock, LED, button) have not been tested.
- The SSD preparation commands are given for macOS; under Linux or Windows, the logic is the same.
Materials and Software Used
Here is the exact configuration on which the procedure was tested.
Hardware
| Item | Detail |
|---|---|
| Board | Home Assistant Yellow |
| Compute Module | Raspberry Pi CM4 Lite (no eMMC), 8 GB RAM, with Wi-Fi |
| Storage | Samsung 970 EVO Plus 500 GB NVMe SSD, in the Yellow’s M.2 port |
| Network | Ethernet (Wi-Fi does not work in this setup) |
| Zigbee Radio | Yellow’s internal Silicon Labs radio, connected to the serial port /dev/ttyAMA1 |
Software
| Item | Detail |
|---|---|
| System | Raspberry Pi OS Lite 64-bit (Debian Trixie), kernel 6.18.50+rpt-rpi-v8 |
| Containers | Docker and Docker Compose |
| Gladys Assistant | image gladysassistant/gladys:v5 |
| Automatic Updates | Watchtower (nickfedor/watchtower) |
| MQTT Broker | Mosquitto (eclipse-mosquitto:2) |
| Zigbee | Zigbee2MQTT (koenkk/zigbee2mqtt), adapter ember |
| Radio Firmware | yellow_zigbee_ncp_7.4.4.0, installed with the Silicon Labs Flasher module |
| Hardware Configuration File | bcm2711-rpi-cm4-ha-yellow.dtb, extracted from the Home Assistant OS 18.4 image for Yellow |
If your Yellow is a CM4 with eMMC, the installation steps on the SSD differ: this procedure does not cover it.
Step 1: Put the Adapted Zigbee Firmware on the Radio (from Home Assistant OS)
Zigbee2MQTT requires a Zigbee “NCP” firmware on the Yellow’s radio. Do this step while Home Assistant OS is still running: it relies on an add-on that will no longer exist after erasure.
- In Home Assistant, stop everything that uses the radio (ZHA, Zigbee2MQTT, multiprotocol module), to free the serial port.
- Install the Silicon Labs Flasher module from the add-on store.
- In its configuration, set: device
/dev/ttyAMA1, baud rate115200, hardware flow control enabled. Choose the Yellow’s Zigbee firmware (yellow_zigbee_ncp_7.4.4.0). The labels may vary depending on the module version. - Start the module and read its logs. In our case, it detected the radio, then the flash completed successfully.
The firmware is written once: it remains in place after the SSD is erased.
Step 2: Retrieve the Yellow’s Hardware Configuration File
Raspberry Pi OS does not know the Yellow board: you need to provide the bcm2711-rpi-cm4-ha-yellow.dtb file (device tree), which describes the serial ports connected to the radio. We take it from the official Home Assistant OS image for Yellow.
- Download the
haos_yellow-<version>.img.xzimage from the Home Assistant Operating System versions page (we used 18.4), then decompress it. - Mount the first partition of the image (the boot partition, in FAT format) and copy the
.dtbfile from it. Also keep, for reference, itsconfig.txtandcmdline.txtfiles.
On macOS:
xz -d haos_yellow-18.4.img.xz
hdiutil attach -nomount haos_yellow-18.4.img
diskutil list # identify the image disk, e.g., disk4
diskutil mount readOnly /dev/disk4s1
mkdir -p ~/yellow-gladys
cp /Volumes/*/bcm2711-rpi-cm4-ha-yellow.dtb ~/yellow-gladys/
cp /Volumes/*/config.txt /Volumes/*/cmdline.txt ~/yellow-gladys/
hdiutil detach /dev/disk4
Copy the file before detaching the image. Adapt the disk number (disk4) to your machine, and verify with ls /Volumes that the correct volume is mounted: the wildcard * can refer to multiple volumes.
On Linux: sudo losetup -fP --show haos_yellow-18.4.img, then mount the p1 partition of the obtained device and copy the same files.
Step 3: Write Raspberry Pi OS Lite to the NVMe SSD
Remove the SSD from the Yellow and connect it to your computer with a case or a USB adapter for NVMe. If your Yellow already booted from this SSD under Home Assistant OS, the CM4 boot order is already set for NVMe.
- Launch Raspberry Pi Imager.
- Board model: Raspberry Pi 4 (the CM4 is close to it).
- System: in Raspberry Pi OS (other), choose Raspberry Pi OS Lite (64-bit). It does not appear in the main list.
- Storage: choose the SSD, making sure it is the correct one and not another disk, as it will be erased.
- Customization: host name
gladys, userpiwith a password you will remember, SSH enabled, time zone and keyboard to your liking. Disable Raspberry Pi Connect if the assistant offers it. - Write the image and wait for the verification to complete.
Do not yet put the SSD back into the Yellow: the next step modifies its boot partition.
Step 4: Adapt the Boot Partition to the Yellow
After writing, the bootfs partition of the SSD (in FAT format) is visible on your computer. Three modifications are sufficient. First, make a copy of the original files.
cd /Volumes/bootfs # adapt the path under Linux or Windows
cp config.txt config.txt.orig
cp cmdline.txt cmdline.txt.orig
cp ~/yellow-gladys/bcm2711-rpi-cm4-ha-yellow.dtb .
1. config.txt: add these lines at the end of the file.
[cm4]
device_tree=bcm2711-rpi-cm4-ha-yellow.dtb
enable_uart=1
arm_64bit=1
gpu_mem=32
2. cmdline.txt: this file contains only one line. Replace the default serial console (console=serial0,115200) with console=ttyAMA2,115200n8 and do not touch anything else, especially root=PARTUUID=.... The file must remain on one line, without a line break in the middle.
3. The .dtb file is the one copied above: it must be in the root of bootfs, next to config.txt.
Eject the SSD properly, put it back into the Yellow, and plug in the Ethernet cable. If the Yellow does not boot, the .orig files allow you to return to the original state for comparison.
Step 5: First Boot, Serial Ports, and Docker
The first boot takes one to two minutes. Then connect via SSH, from your computer:
ssh pi@gladys.local
If the name gladys.local does not resolve, use the Yellow’s IP address indicated by your internet box.
Check that the hardware configuration file is properly taken into account
ls /dev | grep -E 'tty(AMA|S|USB|ACM)'
The ports ttyAMA0, ttyAMA1, and ttyAMA2 must appear. ttyAMA1 is the one for the Zigbee radio. If they are missing, the .dtb is not loaded: reread step 4.
Install Docker
curl -fsSL https://get.docker.com | sh
sudo usermod -aG docker pi
exit
Reconnect via SSH for the docker group membership to be taken into account, then test:
docker run --rm hello-world
docker compose version
Step 6: Install Gladys Assistant and Watchtower
This is the usual Docker installation of Gladys, written as a Docker Compose file. Create the folder and file:
mkdir -p ~/gladys && cd ~/gladys
nano gladys-compose.yml
Content of the file gladys-compose.yml:
services:
gladys:
image: gladysassistant/gladys:v5
container_name: gladys
restart: always
privileged: true
network_mode: host
cgroup: host
environment:
NODE_ENV: production
SQLITE_FILE_PATH: /var/lib/gladysassistant/gladys-production.db
SERVER_PORT: 80
TZ: Europe/Paris
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- /var/lib/gladysassistant:/var/lib/gladysassistant
- /dev:/dev
- /run/udev:/run/udev:ro
- /run/dbus:/run/dbus:ro
watchtower:
image: nickfedor/watchtower
container_name: watchtower
restart: always
volumes:
- /var/run/docker.sock:/var/run/docker.sock
command: --cleanup --include-restarting
Adjust the timezone (TZ). Watchtower automatically updates Gladys; we used the image nickfedor/watchtower, but any other Watchtower image will work as well.
Start everything:
docker compose -f gladys-compose.yml up -d
docker logs --tail 20 gladys
Then open http://gladys.local in a browser. If you’re starting from scratch, create your account. If you’re migrating an existing instance (step 9), do not create an account here: the import will bring the accounts from the old instance.
Step 7: Mosquitto and Zigbee2MQTT on the internal radio
The “Installation from Gladys” mode of the Zigbee2MQTT integration is designed for a USB dongle, which Gladys looks for on USB ports. The Yellow’s radio is an internal serial port (/dev/ttyAMA1), so we launch Mosquitto and Zigbee2MQTT ourselves, then connect Gladys to this existing installation (step 8).
mkdir -p ~/zigbee/mosquitto/config ~/zigbee/mosquitto/data ~/zigbee/z2m-data
cd ~/zigbee
~/zigbee/mosquitto/config/mosquitto.conf
listener 1883
allow_anonymous true
persistence true
persistence_location /mosquitto/data/
This configuration accepts connections without credentials: to be reserved for a trusted local network.
~/zigbee/docker-compose.yml
services:
mosquitto:
image: eclipse-mosquitto:2
container_name: mosquitto
restart: always
ports:
- "1883:1883"
volumes:
- ./mosquitto/config:/mosquitto/config
- ./mosquitto/data:/mosquitto/data
zigbee2mqtt:
image: koenkk/zigbee2mqtt
container_name: zigbee2mqtt
restart: always
depends_on:
- mosquitto
ports:
- "8080:8080"
volumes:
- ./z2m-data:/app/data
devices:
- /dev/ttyAMA1:/dev/ttyAMA1
environment:
- TZ=Europe/Paris
~/zigbee/z2m-data/configuration.yaml
version: 5
mqtt:
base_topic: zigbee2mqtt
server: mqtt://mosquitto:1883
serial:
port: /dev/ttyAMA1
adapter: ember
baudrate: 115200
rtscts: true
frontend:
enabled: true
port: 8080
advanced:
channel: 20
pan_id: GENERATE
ext_pan_id: GENERATE
network_key: GENERATE
Important points: the adapter is ember, the baud rate is 115200, and hardware flow control (rtscts: true) must be enabled, as when flashing the firmware. The GENERATE values make Zigbee2MQTT create a random network ID and key on first startup.
Start and check:
docker compose up -d
docker logs --tail 30 zigbee2mqtt
The RESET_WATCHDOG message at radio startup is harmless. The Zigbee2MQTT web interface is then available at http://gladys.local:8080.
Network Key: The configuration.yaml file contains the generated Zigbee network key. Never publish it (forum, screenshot, file copy): anyone who knows it can listen to your Zigbee network. If it has leaked, regenerate it before associating any device.
Step 8: Connect Gladys to Zigbee2MQTT and Associate Devices
Connection
- In Gladys, open Integrations, then Zigbee2MQTT, Configuration tab.
- Two cards are offered. Click Choose in the right one, “Connect to an existing installation”. Do not choose “Installation from Gladys”: Gladys would launch its own containers, which would compete with yours for the radio and port 8080.
- Enter the MQTT broker address:
mqtt://localhost:1883(Gladys being in host network,localhostreaches Mosquitto). Otherwise usemqtt://<Yellow IP address>:1883. Leave the username and password empty with the Mosquitto configuration above. - If the Zigbee2MQTT interface URL is requested:
http://<Yellow IP address>:8080. - Save and check that the integration indicates a connection.
Associate a Device
- A device already associated with another coordinator must first be reset (factory reset), otherwise it will not look for a new network. Also remove it from the old network if possible.
- Enable association: Zigbee Discovery tab in Gladys, or Permit join button in the Zigbee2MQTT interface. The window lasts about four minutes.
- Put the device in association mode, one or two meters from the Yellow, one device at a time.
- First associate mains-powered devices (plugs, bulbs), which strengthen the network, then battery-powered ones.
- Give each device a clear name. Gladys identifies a Zigbee2MQTT device by its name: when migrating, reuse old names to find devices already present.
To display availability and last reception, in the Zigbee2MQTT interface: Settings, Availability tab, enable Enabled; Advanced tab, set last_seen to ISO_8601.
Linky Meter (ZLinky_TIC), if applicable: in the device-specific settings, the Linky mode must match that of the meter (historical or standard, or auto). In our case, the meter is in historical mode with a Tempo contract, and linky_mode is set to historical. The rate is set to “Historical - BBR”. The historical mode is compatible with Tempo.
Step 9 (optional): Migrate an Existing Gladys Instance with Its History
This step retrieves data from a Gladys installed elsewhere (here on a Synology NAS). The data folder contains the SQLite database, the DuckDB history database, and the integration files.
Keep the old instance stopped during and after migration, so that two Gladys instances do not control the same devices.
On the Old Server
docker inspect gladys --format '{{range .Mounts}}{{.Source}} -> {{.Destination}}{{"\n"}}{{end}}'
docker stop gladys
The first command indicates the host data folder (the one mounted on /var/lib/gladysassistant). Make a backup copy of this folder, then archive it:
tar czf /tmp/gladys-data.tgz -C <parent folder> gladysassistant
On a Synology, docker requires sudo.
On the Yellow
Retrieve the archive (the -O option of scp is necessary if SFTP is disabled on the NAS):
scp -O <user>@<NAS address>:/tmp/gladys-data.tgz /tmp/
Then replace the empty data of the new installation:
cd ~/gladys
docker compose -f gladys-compose.yml stop gladys
sudo mv /var/lib/gladysassistant /var/lib/gladysassistant.empty
sudo mkdir /var/lib/gladysassistant
sudo tar xzf /tmp/gladys-data.tgz -C /var/lib/gladysassistant --strip-components=1
sudo chmod -R u+rwX /var/lib/gladysassistant
docker compose -f gladys-compose.yml start gladys
Then log in with the account from the old instance.
What remains to be done after the import
- The extensions (external integrations) run in
gladys-ext-*containers that are not recreated automatically: in our case, we had to force the update of all installed extensions, one by one: Integrations, the extension concerned, Supervision tab, Force Update button. Gladys then recreates its container and it works again. Check withdocker ps. - Zigbee devices need to be reassociated with the new coordinator (step 8), with their old names. Gladys has correctly applied the renaming to existing devices; verify on a device that its history is preserved before doing them all again.
- The imported Zigbee2MQTT integration configuration points to the old installation: redo step 8 after the import.
- Stop the extension containers from the old server and keep its backup for several days.
Known limits, troubleshooting, and backup
Observed limits
- Wi-Fi: it does not work in our setup, as the Wi-Fi chip firmware is not provided for this device tree. Use Ethernet.
- Other card functions (Bluetooth, real-time clock, LED, button): not tested.
- Procedure tested only once, on a CM4 Lite 8 Go with NVMe SSD.
Troubleshooting
| Symptom | Lead |
|---|---|
| The Yellow does not respond after startup | Check the Ethernet cable and IP address in your box. Check the contents of config.txt and cmdline.txt (one line only). |
No ttyAMA1 |
The .dtb is not loaded: [cm4] block in config.txt and presence of the file at the root of bootfs. |
| Zigbee2MQTT does not start | Read docker logs zigbee2mqtt. Check adapter: ember, baudrate: 115200, rtscts: true and that the NCP firmware is properly flashed. |
| A device does not associate | Reset it, keep “Permit join” active, bring it closer to the Yellow, follow docker logs -f zigbee2mqtt. |
| A Gladys extension is not connected | docker ps to see if its container is running, then docker logs <container name>. Test access to the device from the container (docker exec <container> ping <address>). |
A device responds to ping but not in the application |
Restart it completely (unplugged for 30 seconds): this is what restored our AirSend box. |
Checks after installation
docker inspect -f '{{.Name}} {{.HostConfig.RestartPolicy.Name}}' gladys zigbee2mqtt mosquitto watchtower
sudo reboot
The four containers must display always, and all containers must be “Up” after the reboot (docker ps).
Backup: regularly copy /var/lib/gladysassistant and ~/zigbee/z2m-data to another device. The second contains the Zigbee network key and the list of devices: without it, everything would need to be reassociated.
sudo tar czf ~/gladys-backup-$(date +%F).tgz /var/lib/gladysassistant zigbee/z2m-data
sudo chown $USER:$USER ~/gladys-backup-*.tgz && chmod 600 ~/gladys-backup-*.tgz
Run this command from your home directory and keep the archive in a safe place, as it contains the network key.
Towards a Gladys OS for the Yellow? Sources
This procedure demonstrates that a Yellow can run Gladys on Raspberry Pi OS, with the internal Zigbee. A ready-to-flash image would be possible by integrating the bcm2711-rpi-cm4-ha-yellow.dtb file, the three modifications to config.txt and cmdline.txt, Docker, Gladys, Mosquitto, and Zigbee2MQTT. For a clean image, the following still need to be verified: Wi-Fi, Bluetooth, the real-time clock, and the management of the radio firmware. Feedback from other Yellow users, especially those with a CM4 and eMMC, would be valuable.
Sources: