1 min read
IoTZigbee & Zigbee2MQTT Integration
Zigbee Smart Home mit Zigbee2MQTT. Lokale Kontrolle, MQTT Bridge, Device Pairing und Home Assistant Integration.
ZigbeeZigbee2MQTTSmart HomeMQTTHome AssistantLocal Control

Zigbee & Zigbee2MQTT Integration
Meta-Description: Zigbee Smart Home mit Zigbee2MQTT. Lokale Kontrolle, MQTT Bridge, Device Pairing und Home Assistant Integration.
Keywords: Zigbee, Zigbee2MQTT, Smart Home, MQTT, Home Assistant, Local Control, Mesh Network
Einführung
Zigbee ist das bewährte Protokoll für batteriebetriebene Smart Home Geräte. Zigbee2MQTT macht es unabhängig von proprietären Bridges – lokale Kontrolle via MQTT mit über 4.000 unterstützten Geräten.
Zigbee Architecture
┌─────────────────────────────────────────────────────────────┐
│ ZIGBEE2MQTT ARCHITECTURE │
├─────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Applications │ │
│ │ ┌───────────┐ ┌───────────┐ ┌───────────┐ │ │
│ │ │ Home │ │ Node │ │ Custom │ │ │
│ │ │ Assistant │ │ RED │ │ App │ │ │
│ │ └─────┬─────┘ └─────┬─────┘ └─────┬─────┘ │ │
│ └────────┼──────────────┼──────────────┼─────────────┘ │
│ │ │ │ │
│ ┌────────┴──────────────┴──────────────┴─────────────┐ │
│ │ MQTT Broker │ │
│ │ (Mosquitto / EMQX) │ │
│ └────────────────────────┬───────────────────────────┘ │
│ │ │
│ ┌────────────────────────┴───────────────────────────┐ │
│ │ Zigbee2MQTT │ │
│ │ ┌─────────────┐ ┌─────────────┐ ┌───────────┐ │ │
│ │ │ Frontend │ │ Bridge │ │ Converters│ │ │
│ │ │ (Web UI) │ │ (Core) │ │ (4000+) │ │ │
│ │ └─────────────┘ └─────────────┘ └───────────┘ │ │
│ └────────────────────────┬───────────────────────────┘ │
│ │ │
│ ┌────────────────────────┴───────────────────────────┐ │
│ │ zigbee-herdsman │ │
│ │ (Zigbee Protocol Stack) │ │
│ └────────────────────────┬───────────────────────────┘ │
│ │ │
│ ┌────────────────────────┴───────────────────────────┐ │
│ │ USB Adapter (Coordinator) │ │
│ │ Sonoff ZBDongle-P / ConBee II / CC2652P │ │
│ └────────────────────────┬───────────────────────────┘ │
│ │ │
│ ┌────────────────────────┴───────────────────────────┐ │
│ │ Zigbee Mesh Network │ │
│ │ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ │ │
│ │ │Router│───│Router│───│Router│───│ End │ │ │
│ │ │(Plug)│ │(Bulb)│ │(Plug)│ │Device│ │ │
│ │ └──────┘ └──────┘ └──────┘ └──────┘ │ │
│ └────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘Installation
# Docker Installation (empfohlen)
mkdir zigbee2mqtt-data
cd zigbee2mqtt-data
# configuration.yaml erstellen
cat > configuration.yaml << 'EOF'
homeassistant: true
permit_join: false
mqtt:
base_topic: zigbee2mqtt
server: mqtt://localhost:1883
user: mqtt_user
password: mqtt_password
serial:
port: /dev/ttyUSB0
adapter: zstack
frontend:
port: 8080
advanced:
network_key: GENERATE
pan_id: GENERATE
channel: 15
log_level: info
last_seen: 'ISO_8601'
EOF# docker-compose.yml
version: '3.8'
services:
zigbee2mqtt:
container_name: zigbee2mqtt
image: koenkk/zigbee2mqtt:latest
restart: unless-stopped
volumes:
- ./zigbee2mqtt-data:/app/data
- /run/udev:/run/udev:ro
ports:
- 8080:8080
environment:
- TZ=Europe/Berlin
devices:
- /dev/ttyUSB0:/dev/ttyUSB0
depends_on:
- mosquitto
mosquitto:
container_name: mosquitto
image: eclipse-mosquitto:2
restart: unless-stopped
volumes:
- ./mosquitto/config:/mosquitto/config
- ./mosquitto/data:/mosquitto/data
- ./mosquitto/log:/mosquitto/log
ports:
- 1883:1883
- 9001:9001MQTT Topics
// Zigbee2MQTT MQTT Topic Structure
// Base Topic: zigbee2mqtt
// Device State (Subscribe)
// zigbee2mqtt/[friendly_name]
{
"state": "ON",
"brightness": 254,
"color_temp": 370,
"linkquality": 156,
"last_seen": "2026-01-18T10:30:00.000Z"
}
// Device Control (Publish)
// zigbee2mqtt/[friendly_name]/set
{
"state": "ON",
"brightness": 200,
"color_temp": 300,
"transition": 2
}
// Device Availability
// zigbee2mqtt/[friendly_name]/availability
"online" | "offline"
// Bridge Status
// zigbee2mqtt/bridge/state
"online" | "offline"
// Bridge Info
// zigbee2mqtt/bridge/info
{
"version": "1.40.0",
"commit": "abc123",
"coordinator": {
"ieee_address": "0x00124b001cda7a45",
"type": "zStack3x0"
},
"network": {
"channel": 15,
"pan_id": 6754,
"extended_pan_id": "0xdddddddddddddddd"
}
}
// Device List
// zigbee2mqtt/bridge/devices
[
{
"ieee_address": "0x00158d00012345678",
"friendly_name": "living_room_light",
"type": "Router",
"model": "LED1545G12",
"vendor": "IKEA"
}
]Node.js Integration
// lib/zigbee2mqtt-client.ts
import mqtt, { MqttClient } from 'mqtt';
interface Z2MDevice {
ieee_address: string;
friendly_name: string;
type: 'Coordinator' | 'Router' | 'EndDevice';
model?: string;
vendor?: string;
supported: boolean;
definition?: {
description: string;
supports: string;
exposes: Z2MExpose[];
};
}
interface Z2MExpose {
type: string;
name: string;
property: string;
access: number;
values?: string[];
value_min?: number;
value_max?: number;
}
interface DeviceState {
state?: 'ON' | 'OFF';
brightness?: number;
color_temp?: number;
color?: { x: number; y: number };
temperature?: number;
humidity?: number;
battery?: number;
occupancy?: boolean;
contact?: boolean;
linkquality?: number;
last_seen?: string;
}
class Zigbee2MQTTClient {
private client: MqttClient;
private baseTopic: string;
private devices: Map<string, Z2MDevice> = new Map();
private states: Map<string, DeviceState> = new Map();
private listeners: Map<string, Set<(state: DeviceState) => void>> = new Map();
constructor(
brokerUrl: string,
baseTopic: string = 'zigbee2mqtt'
) {
this.baseTopic = baseTopic;
this.client = mqtt.connect(brokerUrl);
this.client.on('connect', () => this.onConnect());
this.client.on('message', (topic, payload) =>
this.onMessage(topic, payload.toString())
);
}
private onConnect(): void {
console.log('Connected to MQTT broker');
// Subscribe to all Z2M topics
this.client.subscribe(`${this.baseTopic}/#`);
// Request device list
this.publish('bridge/request/devices', '');
}
private onMessage(topic: string, payload: string): void {
const relativeTopic = topic.replace(`${this.baseTopic}/`, '');
// Bridge Events
if (relativeTopic === 'bridge/devices') {
const devices = JSON.parse(payload) as Z2MDevice[];
this.updateDeviceList(devices);
return;
}
if (relativeTopic === 'bridge/state') {
console.log(`Bridge state: ${payload}`);
return;
}
// Device State Updates
if (!relativeTopic.includes('/') || relativeTopic.endsWith('/availability')) {
return;
}
// State Update für Gerät
const deviceName = relativeTopic.split('/')[0];
try {
const state = JSON.parse(payload) as DeviceState;
this.states.set(deviceName, { ...this.states.get(deviceName), ...state });
// Listener benachrichtigen
this.listeners.get(deviceName)?.forEach(cb => cb(state));
this.listeners.get('*')?.forEach(cb => cb(state));
} catch {
// Nicht-JSON Payload ignorieren
}
}
private updateDeviceList(devices: Z2MDevice[]): void {
devices.forEach(device => {
this.devices.set(device.friendly_name, device);
});
console.log(`Loaded ${devices.length} devices`);
}
private publish(topic: string, payload: any): void {
const fullTopic = `${this.baseTopic}/${topic}`;
const message = typeof payload === 'string'
? payload
: JSON.stringify(payload);
this.client.publish(fullTopic, message);
}
// Public API
getDevices(): Z2MDevice[] {
return Array.from(this.devices.values());
}
getDevice(name: string): Z2MDevice | undefined {
return this.devices.get(name);
}
getState(deviceName: string): DeviceState | undefined {
return this.states.get(deviceName);
}
// Device Control
setState(deviceName: string, state: Partial<DeviceState>): void {
this.publish(`${deviceName}/set`, state);
}
turnOn(deviceName: string): void {
this.setState(deviceName, { state: 'ON' });
}
turnOff(deviceName: string): void {
this.setState(deviceName, { state: 'OFF' });
}
toggle(deviceName: string): void {
this.publish(`${deviceName}/set`, { state: 'TOGGLE' });
}
setBrightness(deviceName: string, brightness: number, transition?: number): void {
this.setState(deviceName, {
brightness: Math.min(254, Math.max(0, brightness)),
...(transition && { transition })
});
}
setColorTemp(deviceName: string, colorTemp: number): void {
// Mired: 153 (cool) - 500 (warm)
this.setState(deviceName, { color_temp: colorTemp });
}
setColor(deviceName: string, x: number, y: number): void {
this.setState(deviceName, { color: { x, y } });
}
// Event Listener
onStateChange(
deviceName: string,
callback: (state: DeviceState) => void
): () => void {
if (!this.listeners.has(deviceName)) {
this.listeners.set(deviceName, new Set());
}
this.listeners.get(deviceName)!.add(callback);
return () => {
this.listeners.get(deviceName)?.delete(callback);
};
}
// Bridge Control
permitJoin(permit: boolean, duration?: number): void {
this.publish('bridge/request/permit_join', {
value: permit,
time: duration || 120
});
}
renameDevice(oldName: string, newName: string): void {
this.publish('bridge/request/device/rename', {
from: oldName,
to: newName
});
}
removeDevice(deviceName: string, force?: boolean): void {
this.publish('bridge/request/device/remove', {
id: deviceName,
force: force || false
});
}
// OTA Updates
checkOTAUpdates(): void {
this.publish('bridge/request/device/ota_update/check', '');
}
updateDevice(deviceName: string): void {
this.publish('bridge/request/device/ota_update/update', {
id: deviceName
});
}
disconnect(): void {
this.client.end();
}
}
export { Zigbee2MQTTClient };Express API Wrapper
// api/zigbee-api.ts
import express from 'express';
import { Zigbee2MQTTClient } from '../lib/zigbee2mqtt-client';
const router = express.Router();
const z2m = new Zigbee2MQTTClient(process.env.MQTT_URL || 'mqtt://localhost:1883');
// GET /api/devices
router.get('/devices', (req, res) => {
const devices = z2m.getDevices()
.filter(d => d.type !== 'Coordinator')
.map(d => ({
name: d.friendly_name,
ieee: d.ieee_address,
type: d.type,
model: d.model,
vendor: d.vendor,
state: z2m.getState(d.friendly_name)
}));
res.json(devices);
});
// GET /api/devices/:name
router.get('/devices/:name', (req, res) => {
const device = z2m.getDevice(req.params.name);
if (!device) {
return res.status(404).json({ error: 'Device not found' });
}
res.json({
...device,
state: z2m.getState(req.params.name)
});
});
// POST /api/devices/:name/set
router.post('/devices/:name/set', (req, res) => {
const device = z2m.getDevice(req.params.name);
if (!device) {
return res.status(404).json({ error: 'Device not found' });
}
z2m.setState(req.params.name, req.body);
res.json({ success: true });
});
// POST /api/devices/:name/toggle
router.post('/devices/:name/toggle', (req, res) => {
z2m.toggle(req.params.name);
res.json({ success: true });
});
// Groups
// POST /api/groups/:name/set
router.post('/groups/:name/set', (req, res) => {
z2m.setState(req.params.name, req.body);
res.json({ success: true });
});
// Bridge Control
// POST /api/bridge/permit_join
router.post('/bridge/permit_join', (req, res) => {
const { permit, duration } = req.body;
z2m.permitJoin(permit, duration);
res.json({ success: true });
});
export default router;Home Assistant Auto-Discovery
// Zigbee2MQTT sendet automatisch Home Assistant Discovery Messages
// homeassistant/light/0x00158d00012345678/light/config
{
"name": "Living Room Light",
"unique_id": "0x00158d00012345678_light_zigbee2mqtt",
"state_topic": "zigbee2mqtt/living_room_light",
"command_topic": "zigbee2mqtt/living_room_light/set",
"availability": [
{ "topic": "zigbee2mqtt/bridge/state" },
{ "topic": "zigbee2mqtt/living_room_light/availability" }
],
"brightness": true,
"brightness_scale": 254,
"color_mode": true,
"supported_color_modes": ["color_temp", "xy"],
"min_mireds": 153,
"max_mireds": 500,
"schema": "json",
"device": {
"identifiers": ["zigbee2mqtt_0x00158d00012345678"],
"name": "Living Room Light",
"model": "LED1545G12",
"manufacturer": "IKEA",
"via_device": "zigbee2mqtt_bridge"
}
}Device Groups
# configuration.yaml
groups:
living_room:
friendly_name: Wohnzimmer
devices:
- living_room_light_1
- living_room_light_2
- living_room_light_3
all_lights:
friendly_name: Alle Lichter
devices:
- living_room_light_1
- living_room_light_2
- bedroom_light
- kitchen_light// Gruppen steuern
z2m.setState('living_room', { state: 'ON', brightness: 200 });
// Alle Lichter aus
z2m.turnOff('all_lights');Scenes & Automations
# configuration.yaml
# Szenen definieren
scenes:
- name: movie_mode
data:
living_room:
state: 'ON'
brightness: 50
color_temp: 500
kitchen:
state: 'OFF'
- name: morning_routine
data:
bedroom_light:
state: 'ON'
brightness: 100
color_temp: 250// Szene aktivieren
z2m.publish('scene/recall', { scene: 'movie_mode' });
// Custom Automation
z2m.onStateChange('motion_sensor', (state) => {
if (state.occupancy) {
z2m.turnOn('hallway_light');
// Auto-Off nach 5 Minuten
setTimeout(() => {
const currentState = z2m.getState('motion_sensor');
if (!currentState?.occupancy) {
z2m.turnOff('hallway_light');
}
}, 5 * 60 * 1000);
}
});
// Temperature-basierte Automation
z2m.onStateChange('temperature_sensor', (state) => {
if (state.temperature && state.temperature > 25) {
z2m.publish('fan/set', { state: 'ON', preset_mode: 'high' });
}
});Zigbee Network Map
// Network Topology abrufen
// zigbee2mqtt/bridge/request/networkmap
z2m.publish('bridge/request/networkmap', { type: 'raw' });
// Antwort auf zigbee2mqtt/bridge/response/networkmap
interface NetworkMap {
nodes: Array<{
ieee_address: string;
friendly_name: string;
type: 'Coordinator' | 'Router' | 'EndDevice';
network_address: number;
lqi: number; // Link Quality Indicator
relationship: number;
}>;
links: Array<{
source: { ieee_address: string };
target: { ieee_address: string };
lqi: number;
depth: number;
}>;
}Troubleshooting
// Häufige Probleme und Lösungen
// 1. Gerät reagiert nicht
async function troubleshootDevice(deviceName: string) {
const state = z2m.getState(deviceName);
// Linkqualität prüfen
if (state?.linkquality && state.linkquality < 50) {
console.log('Low link quality - consider adding router devices');
}
// Availability prüfen
// Subscribe to zigbee2mqtt/[device]/availability
// Device Interview neu durchführen
z2m.publish('bridge/request/device/interview', { id: deviceName });
}
// 2. Pairing funktioniert nicht
function resetAndPair() {
// Permit Join aktivieren
z2m.permitJoin(true, 180); // 3 Minuten
// Gerät in Pairing-Modus versetzen (geräteabhängig)
console.log('Reset device and put in pairing mode');
}
// 3. Mesh-Netzwerk optimieren
function optimizeMesh() {
// Router-Geräte (Steckdosen, Lampen) sind wichtig für Mesh
// Mindestens ein Router pro Raum
const devices = z2m.getDevices();
const routers = devices.filter(d => d.type === 'Router');
const endDevices = devices.filter(d => d.type === 'EndDevice');
console.log(`Routers: ${routers.length}, End Devices: ${endDevices.length}`);
if (endDevices.length / routers.length > 6) {
console.log('Warning: Not enough routers for stable mesh');
}
}Fazit
Zigbee2MQTT bietet:
- Lokale Kontrolle: Keine Cloud-Abhängigkeit
- 4000+ Geräte: Herstellerunabhängig
- MQTT Integration: Einfache Anbindung
- Open Source: Aktive Community
Der beste Weg für ein offenes Smart Home.
Bildprompts
- "Zigbee mesh network diagram with router and end devices connected"
- "Zigbee2MQTT web interface showing device list and controls"
- "USB Zigbee coordinator stick connected to Raspberry Pi, smart home hub"