Zigbee2MQTT Cheat Sheet
Overview
Zigbee2MQTT is an open-source bridge that connects Zigbee devices to an MQTT broker, eliminating the need for proprietary Zigbee hubs from vendors like Philips Hue, IKEA, Aqara, or Samsung SmartThings. It supports over 3,000 devices from 400+ vendors, making it the most comprehensive Zigbee integration available. By translating Zigbee protocol messages to standard MQTT topics, Zigbee2MQTT integrates seamlessly with home automation platforms like Home Assistant, Node-RED, OpenHAB, and any MQTT-capable system.
Zigbee2MQTT requires a supported Zigbee coordinator USB adapter (such as the Sonoff Zigbee 3.0 USB Dongle Plus, SLZB-06, or ConBee II) connected to a Linux machine, Raspberry Pi, or Docker container. It provides a web-based frontend for device management, OTA firmware updates, network visualization, and device configuration. The project handles Zigbee network formation, device pairing, group management, binding, and scenes, all exposed through a clean MQTT API that publishes device states and accepts commands as JSON payloads.
Installation
Docker (Recommended)
# Create data directory
mkdir -p /opt/zigbee2mqtt/data
# Create initial configuration
cat > /opt/zigbee2mqtt/data/configuration.yaml << 'EOF'
homeassistant: true
permit_join: false
mqtt:
base_topic: zigbee2mqtt
server: mqtt://localhost:1883
serial:
port: /dev/ttyUSB0
frontend:
port: 8080
advanced:
network_key: GENERATE
pan_id: GENERATE
log_level: info
EOF
# Run with Docker
docker run -d \
--name zigbee2mqtt \
--restart=unless-stopped \
-v /opt/zigbee2mqtt/data:/app/data \
--device /dev/ttyUSB0:/dev/ttyUSB0 \
-p 8080:8080 \
-e TZ=America/New_York \
koenkk/zigbee2mqtt
Docker Compose
# docker-compose.yml
version: '3.8'
services:
mqtt:
image: eclipse-mosquitto:2
ports:
- "1883:1883"
volumes:
- mosquitto-data:/mosquitto/data
- mosquitto-config:/mosquitto/config
zigbee2mqtt:
image: koenkk/zigbee2mqtt
restart: unless-stopped
volumes:
- ./zigbee2mqtt-data:/app/data
ports:
- "8080:8080"
devices:
- /dev/ttyUSB0:/dev/ttyUSB0
environment:
- TZ=America/New_York
depends_on:
- mqtt
volumes:
mosquitto-data:
mosquitto-config:
Native Installation
# Install Node.js 18+
curl -fsSL https://deb.nodesource.com/setup_18.x | sudo -E bash -
sudo apt install -y nodejs
# Clone and build
sudo git clone --depth 1 https://github.com/Koenkk/zigbee2mqtt.git /opt/zigbee2mqtt
cd /opt/zigbee2mqtt
npm ci
# Create systemd service
sudo cat > /etc/systemd/system/zigbee2mqtt.service << 'EOF'
[Unit]
Description=Zigbee2MQTT
After=network.target
[Service]
Environment=NODE_ENV=production
ExecStart=/usr/bin/node /opt/zigbee2mqtt/index.js
WorkingDirectory=/opt/zigbee2mqtt
Restart=on-failure
RestartSec=10s
User=root
[Install]
WantedBy=multi-user.target
EOF
sudo systemctl daemon-reload
sudo systemctl enable zigbee2mqtt
sudo systemctl start zigbee2mqtt
Configuration
Main Configuration File
# /opt/zigbee2mqtt/data/configuration.yaml
homeassistant: true
permit_join: false
mqtt:
base_topic: zigbee2mqtt
server: mqtt://localhost:1883
user: mqtt_user
password: mqtt_password
keepalive: 60
version: 5
serial:
port: /dev/ttyUSB0
# adapter: zstack # auto-detected usually
# baudrate: 115200
frontend:
port: 8080
host: 0.0.0.0
auth_token: my-secret-token
advanced:
network_key: GENERATE
pan_id: GENERATE
ext_pan_id: GENERATE
channel: 15
log_level: info
log_output:
- console
- file
homeassistant_discovery_topic: homeassistant
homeassistant_status_topic: homeassistant/status
last_seen: ISO_8601
elapsed: true
transmit_power: 20
availability:
active:
timeout: 10
passive:
timeout: 1500
ota:
update_check_interval: 1440
disable_automatic_update_check: false
device_options:
legacy: false
Device-Specific Configuration
# In configuration.yaml
devices:
'0x00158d0001234567':
friendly_name: living_room_motion
retain: true
availability: true
'0x00158d0009876543':
friendly_name: kitchen_temperature
debounce: 1
debounce_ignore:
- action
groups:
'1':
friendly_name: living_room_lights
retain: false
devices:
- '0x00158d0001111111/1'
- '0x00158d0002222222/1'
'2':
friendly_name: all_lights
MQTT Commands
Device Control
# Publish to control a device
# Turn on a light
mosquitto_pub -t "zigbee2mqtt/living_room_light/set" -m '{"state": "ON"}'
# Set brightness and color
mosquitto_pub -t "zigbee2mqtt/living_room_light/set" -m \
'{"state": "ON", "brightness": 200, "color_temp": 350}'
# Set color by name or hex
mosquitto_pub -t "zigbee2mqtt/living_room_light/set" -m \
'{"color": {"hex": "#FF5733"}}'
# Set HSV color
mosquitto_pub -t "zigbee2mqtt/living_room_light/set" -m \
'{"color": {"hue": 120, "saturation": 100}}'
# Toggle device
mosquitto_pub -t "zigbee2mqtt/living_room_light/set" -m '{"state": "TOGGLE"}'
# Set thermostat
mosquitto_pub -t "zigbee2mqtt/thermostat/set" -m \
'{"occupied_heating_setpoint": 22, "system_mode": "heat"}'
# Lock/unlock
mosquitto_pub -t "zigbee2mqtt/front_door_lock/set" -m '{"state": "LOCK"}'
Subscribe to Device State
# Subscribe to all device updates
mosquitto_sub -t "zigbee2mqtt/#" -v
# Subscribe to specific device
mosquitto_sub -t "zigbee2mqtt/living_room_motion" -v
# Subscribe to bridge events
mosquitto_sub -t "zigbee2mqtt/bridge/#" -v
# Subscribe to device availability
mosquitto_sub -t "zigbee2mqtt/+/availability" -v
Bridge Management via MQTT
# Permit joining (60 seconds)
mosquitto_pub -t "zigbee2mqtt/bridge/request/permit_join" -m '{"value": true, "time": 60}'
# Disable joining
mosquitto_pub -t "zigbee2mqtt/bridge/request/permit_join" -m '{"value": false}'
# Rename device
mosquitto_pub -t "zigbee2mqtt/bridge/request/device/rename" -m \
'{"from": "0x00158d0001234567", "to": "kitchen_sensor"}'
# Remove device
mosquitto_pub -t "zigbee2mqtt/bridge/request/device/remove" -m '{"id": "kitchen_sensor"}'
# Force remove (unresponsive device)
mosquitto_pub -t "zigbee2mqtt/bridge/request/device/remove" -m \
'{"id": "old_sensor", "force": true}'
# Get network map
mosquitto_pub -t "zigbee2mqtt/bridge/request/networkmap" -m '{"type": "graphviz", "routes": true}'
# Restart Zigbee2MQTT
mosquitto_pub -t "zigbee2mqtt/bridge/request/restart" -m ""
# Check for OTA updates
mosquitto_pub -t "zigbee2mqtt/bridge/request/device/ota_update/check" -m '{"id": "living_room_light"}'
# Apply OTA update
mosquitto_pub -t "zigbee2mqtt/bridge/request/device/ota_update/update" -m '{"id": "living_room_light"}'
Group Management
# Create group
mosquitto_pub -t "zigbee2mqtt/bridge/request/group/add" -m '{"friendly_name": "bedroom_lights"}'
# Add device to group
mosquitto_pub -t "zigbee2mqtt/bridge/request/group/members/add" -m \
'{"group": "bedroom_lights", "device": "bed_light_left"}'
# Remove device from group
mosquitto_pub -t "zigbee2mqtt/bridge/request/group/members/remove" -m \
'{"group": "bedroom_lights", "device": "bed_light_left"}'
# Control group
mosquitto_pub -t "zigbee2mqtt/bedroom_lights/set" -m '{"state": "ON", "brightness": 150}'
Advanced Usage
Binding (Direct Device-to-Device)
# Bind switch to light (commands go directly, no coordinator needed)
mosquitto_pub -t "zigbee2mqtt/bridge/request/device/bind" -m \
'{"from": "wall_switch", "to": "ceiling_light", "clusters": ["genOnOff", "genLevelCtrl"]}'
# Unbind
mosquitto_pub -t "zigbee2mqtt/bridge/request/device/unbind" -m \
'{"from": "wall_switch", "to": "ceiling_light"}'
# Bind to group
mosquitto_pub -t "zigbee2mqtt/bridge/request/device/bind" -m \
'{"from": "wall_switch", "to": "living_room_lights"}'
Scenes
# Store scene
mosquitto_pub -t "zigbee2mqtt/living_room_lights/set" -m \
'{"scene_store": {"ID": 1, "name": "movie_mode"}}'
# Recall scene
mosquitto_pub -t "zigbee2mqtt/living_room_lights/set" -m \
'{"scene_recall": {"ID": 1}}'
External Converters
// /opt/zigbee2mqtt/data/my_converter.js
const fz = require('zigbee-herdsman-converters/converters/fromZigbee');
const tz = require('zigbee-herdsman-converters/converters/toZigbee');
const definition = {
zigbeeModel: ['CustomDevice123'],
model: 'CustomDevice123',
vendor: 'MyVendor',
description: 'Custom Zigbee sensor',
fromZigbee: [fz.temperature, fz.humidity],
toZigbee: [],
exposes: [e.temperature(), e.humidity()],
};
module.exports = definition;
# Add to configuration.yaml
external_converters:
- my_converter.js
Troubleshooting
| Issue | Solution |
|---|---|
| Coordinator not found | Check USB device path, try different port |
| Device won’t pair | Enable permit_join, bring device close to coord |
| Intermittent connectivity | Add Zigbee routers (always-on devices) to mesh |
| Device shows unavailable | Check battery, verify availability timeout |
| MQTT connection refused | Verify broker address, credentials, port |
| High latency | Reduce network size per channel, avoid WiFi ch |
| OTA update fails | Keep device close to coordinator during update |
| Frontend not loading | Check port 8080 not blocked, verify config |
Diagnostic Commands
# Check Zigbee2MQTT logs
docker logs -f zigbee2mqtt
# or
journalctl -u zigbee2mqtt -f
# Check coordinator firmware
mosquitto_sub -t "zigbee2mqtt/bridge/info" -C 1 | python3 -m json.tool
# List all devices
mosquitto_sub -t "zigbee2mqtt/bridge/devices" -C 1 | python3 -m json.tool
# Check device state
mosquitto_sub -t "zigbee2mqtt/my_device" -C 1
# Debug logging
# Set in configuration.yaml: advanced.log_level: debug
# Restart Zigbee2MQTT
# Find USB device path
ls -la /dev/ttyUSB* /dev/ttyACM*
dmesg | grep -i "usb\|tty"
WiFi Channel Interference
# Zigbee channels vs WiFi channels (2.4GHz overlap)
# Zigbee 15 -> WiFi 1 (least overlap)
# Zigbee 20 -> WiFi 6 (least overlap)
# Zigbee 25 -> WiFi 11 (least overlap)
# Best practice: Use Zigbee channel 15, 20, or 25