= 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 === {{{#!yaml 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`