wiki:Zigbee2MqttEinrichtung

Zigbee2MQTT Konfiguration

Übersicht

Zigbee2MQTT (z2m) ist eine Bridge zwischen dem Zigbee-Funknetz und dem MQTT-Broker. Es übernimmt ausschließlich Protokollübersetzung und Netz-Management. Die Automationslogik liegt im IO-Broker. Der Coordinator ist ein Sonoff Dongle-Max (Silicon Labs EFR32MG21, EmberZNet-Firmware), angebunden per TCP über das interne Netz.

Coordinator

Gerät Sonoff Dongle-Max
Protokoll ember (EmberZNet)
Adresse tcp://zb-dongle-max.mqtt.p21.net:6638
Baudrate 115200, rtscts: false

MQTT

Broker zentraler Broker, internes Netz
Base-Topic zigbee
Protocol MQTT 3.1.1 (Version 4)
Retain deaktiviert (force_disable_retain: true)

Bridge-State wird automatisch auf zigbee/bridge/state publiziert ({"state":"online"} / {"state":"offline"}), nutzbar als LWT-Ersatz im IO-Broker.

Availability

Aktive Geräte (netzbetrieben) Timeout 3 min, Backoff aktiv, Pause bei >120 min
Passive Geräte (Batterie) Timeout 240 min

OTA-Updates

Automatische Update-Checks sind deaktiviert (disable_automatic_update_check: true). Geräte-initiierte Anfragen werden von z2m mit "kein Image verfügbar" beantwortet, kein Kontakt zu Drittservern. Manuelle Prüfung bei Bedarf per MQTT:

zigbee/bridge/request/device/ota_update/check
{"id": "friendly_name_des_geraets"}

Logging

Console-Logging abgeschaltet, nur File-Logging aktiv. Entlastet den Docker-Logger bei den minütlichen z2m-Statusmeldungen erheblich. In der configuration.yaml:

advanced:
  log_output:
    - file

Schlüsseldaten (Netzwerk)

Network Key, PAN ID und Extended PAN ID liegen im Klartext in /var/www/bsp12-zigbee2mqtt/z2m-data/configuration.yaml. Diese Datei ist sicherheitsrelevant und darf nicht öffentlich zugänglich sein.

TODO: Backup läuft über dirvish.

Zigbee2MQTT ↔ ioBroker: kritische Einstellungskombination

Symptom

Beim Setzen eines Wertes über Zigbee (beobachtet an occupied_heating_setpoint eines SONOFF TRVZB) erscheint im ioBroker zuerst das Kommando ohne ACK, dann der alte Wert mit ACK und erst danach der neue Wert mit ACK.

Ursache

Zwei z2m-Mechanismen greifen ineinander:

  • advanced.last_seen != disable — jeder empfangene Frame löst über onLastSeenChanged → publishEntityState einen Publish aus. Auch der writeRsp, mit dem das Gerät das Schreiben quittiert.
  • advanced.cache_state: true — publishEntityState mischt den kompletten gecachten Zustand in jedes Payload.

Der writeRsp trifft ein, bevor convertSet zurückkehrt und den neuen Wert in den Cache schreibt. Der last_seen-Publish transportiert deshalb den alten Wert. Erst danach folgt der optimistische Publish mit dem neuen.

Nicht die Ursache und ohne Wirkung:

  • optimistic: false — der Geräte-Report folgt ohnehin ~10 ms später, die Reihenfolge alt→neu bleibt.
  • debounce / throttle — greifen nur in receive.ts für Nachrichten vom Gerät. last_seen- und Set-Publishes laufen daran vorbei.

Korrekte Einstellung

advanced:
  last_seen: ISO_8601
  cache_state: false
availability:
  enabled: true
Einstellung Wirkung
cache_state: false Behebt das Problem. Publishes enthalten nur noch die tatsächlich geänderten Attribute. Der ioBroker aggregiert sie: Datenpunkte behalten ihren Wert, bis sie überschrieben werden.
last_seen: ISO_8601 Kann anbleiben. Wird für die „Last seen"-Spalte im z2m-Frontend und für die Adapter-Option alwaysUpdateAvailableState gebraucht.
availability.enabled Liefert das available-Feld im Objektbaum. Ohne das zeigt der Adapter alle Geräte als offline. Einzige brauchbare Strategie für Aktoren (aktives Pingen, Default 10 min).

Folgen und Randbedingungen

  • cache_state_send_on_startup hängt an cache_state und greift nicht mehr. Bestehende Datenpunkte behalten ihre Werte; nur frisch angelegte bleiben leer, bis das Gerät das Attribut meldet. Notfalls mit .../get nachhelfen.
  • ts / lc der Datenpunkte werden dadurch aussagekräftiger: vorher hat jeder Full-State-Publish den Zeitstempel aller ~40 Datenpunkte hochgesetzt.
  • z2ms interner Cache bleibt unberührt — state.set() läuft in publishEntityState vor der cache_state-Abfrage. Frontend und filtered_cache arbeiten unverändert.
  • last_seen: disable löst das Symptom ebenfalls, kostet aber die Frontend-Spalte und legt alwaysUpdateAvailableState still. Nicht empfohlen.

Diagnose bei Wiederauftreten

log_level: debug setzen, Wert ändern, im Log die MQTT publish-Zeilen um den writeRsp herum ansehen. Publishes ohne elapsed-Feld stammen nicht aus dem Empfangspfad (receive.ts), sondern aus dem last_seen- oder Set-Pfad. Das ist das Unterscheidungsmerkmal.

Geräte-Strategie

Netzbetriebene Geräte (Router) zuerst pairen, danach Endgeräte (Batterie). Friendly Names nach Schema: raumname_funktion, z.B. wohnzimmer_heizung.

  • Setpoint-Steuerung und Zeitpläne ausschließlich über IO-Broker
  • Tuya-TRVs im Modus heat, interner Schedule deaktiviert

Für ME167-Thermostate (Tuya TS0601): kein nativer externer Sensor-Support. Externe Temperaturregelung vollständig in IO-Broker implementieren.

Metadaten abrufen (ohne Neustart)

mosquitto_pub -h broker.mqtt.p21.net -t "zigbee/bridge/request/devices" -m ""

Antwort auf: zigbee/bridge/devices

Last modified 5 weeks ago Last modified on Sep 28, 2026, 3:39:10 PM