Install Gladys Assistant on a Home Assistant Yellow (internal Zigbee)

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.

  1. In Home Assistant, stop everything that uses the radio (ZHA, Zigbee2MQTT, multiprotocol module), to free the serial port.
  2. Install the Silicon Labs Flasher module from the add-on store.
  3. In its configuration, set: device /dev/ttyAMA1, baud rate 115200, 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.
  4. 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.

  1. Download the haos_yellow-<version>.img.xz image from the Home Assistant Operating System versions page (we used 18.4), then decompress it.
  2. Mount the first partition of the image (the boot partition, in FAT format) and copy the .dtb file from it. Also keep, for reference, its config.txt and cmdline.txt files.

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.

  1. Launch Raspberry Pi Imager.
  2. Board model: Raspberry Pi 4 (the CM4 is close to it).
  3. System: in Raspberry Pi OS (other), choose Raspberry Pi OS Lite (64-bit). It does not appear in the main list.
  4. Storage: choose the SSD, making sure it is the correct one and not another disk, as it will be erased.
  5. Customization: host name gladys, user pi with a password you will remember, SSH enabled, time zone and keyboard to your liking. Disable Raspberry Pi Connect if the assistant offers it.
  6. 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

  1. In Gladys, open Integrations, then Zigbee2MQTT, Configuration tab.
  2. 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.
  3. Enter the MQTT broker address: mqtt://localhost:1883 (Gladys being in host network, localhost reaches Mosquitto). Otherwise use mqtt://<Yellow IP address>:1883. Leave the username and password empty with the Mosquitto configuration above.
  4. If the Zigbee2MQTT interface URL is requested: http://<Yellow IP address>:8080.
  5. 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 with docker 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:

2 Likes