| | 63 | == Zigbee2MQTT ↔ ioBroker: kritische Einstellungskombination == |
| | 64 | |
| | 65 | === Symptom === |
| | 66 | |
| | 67 | Beim Setzen eines Wertes über Zigbee (beobachtet an `occupied_heating_setpoint` |
| | 68 | eines SONOFF TRVZB) erscheint im ioBroker zuerst das Kommando ohne ACK, dann der |
| | 69 | '''alte''' Wert mit ACK und erst danach der neue Wert mit ACK. |
| | 70 | |
| | 71 | === Ursache === |
| | 72 | |
| | 73 | Zwei z2m-Mechanismen greifen ineinander: |
| | 74 | |
| | 75 | * `advanced.last_seen != disable` — jeder empfangene Frame löst über |
| | 76 | `onLastSeenChanged` → `publishEntityState` einen Publish aus. '''Auch der |
| | 77 | `writeRsp`''', mit dem das Gerät das Schreiben quittiert. |
| | 78 | * `advanced.cache_state: true` — `publishEntityState` mischt den kompletten |
| | 79 | gecachten Zustand in jedes Payload. |
| | 80 | |
| | 81 | Der `writeRsp` trifft ein, '''bevor''' `convertSet` zurückkehrt und den neuen Wert |
| | 82 | in den Cache schreibt. Der last_seen-Publish transportiert deshalb den alten Wert. |
| | 83 | Erst danach folgt der optimistische Publish mit dem neuen. |
| | 84 | |
| | 85 | Nicht die Ursache und ohne Wirkung: |
| | 86 | |
| | 87 | * `optimistic: false` — der Geräte-Report folgt ohnehin ~10 ms später, die |
| | 88 | Reihenfolge alt→neu bleibt. |
| | 89 | * `debounce` / `throttle` — greifen nur in `receive.ts` für Nachrichten '''vom |
| | 90 | Gerät'''. last_seen- und Set-Publishes laufen daran vorbei. |
| | 91 | |
| | 92 | === Korrekte Einstellung === |
| | 93 | |
| | 94 | {{{#!yaml |
| | 95 | advanced: |
| | 96 | last_seen: ISO_8601 |
| | 97 | cache_state: false |
| | 98 | availability: |
| | 99 | enabled: true |
| | 100 | }}} |
| | 101 | |
| | 102 | ||= Einstellung =||= Wirkung =|| |
| | 103 | || `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. || |
| | 104 | || `last_seen: ISO_8601` || Kann anbleiben. Wird für die „Last seen"-Spalte im z2m-Frontend und für die Adapter-Option `alwaysUpdateAvailableState` gebraucht. || |
| | 105 | || `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). || |
| | 106 | |
| | 107 | === Folgen und Randbedingungen === |
| | 108 | |
| | 109 | * `cache_state_send_on_startup` hängt an `cache_state` und greift nicht mehr. |
| | 110 | Bestehende Datenpunkte behalten ihre Werte; nur frisch angelegte bleiben leer, |
| | 111 | bis das Gerät das Attribut meldet. Notfalls mit `.../get` nachhelfen. |
| | 112 | * `ts` / `lc` der Datenpunkte werden dadurch '''aussagekräftiger''': vorher hat |
| | 113 | jeder Full-State-Publish den Zeitstempel aller ~40 Datenpunkte hochgesetzt. |
| | 114 | * z2ms interner Cache bleibt unberührt — `state.set()` läuft in |
| | 115 | `publishEntityState` vor der `cache_state`-Abfrage. Frontend und |
| | 116 | `filtered_cache` arbeiten unverändert. |
| | 117 | * `last_seen: disable` löst das Symptom ebenfalls, kostet aber die |
| | 118 | Frontend-Spalte und legt `alwaysUpdateAvailableState` still. Nicht empfohlen. |
| | 119 | |
| | 120 | === Diagnose bei Wiederauftreten === |
| | 121 | |
| | 122 | `log_level: debug` setzen, Wert ändern, im Log die `MQTT publish`-Zeilen um den |
| | 123 | `writeRsp` herum ansehen. Publishes '''ohne''' `elapsed`-Feld stammen nicht aus |
| | 124 | dem Empfangspfad (`receive.ts`), sondern aus dem last_seen- oder Set-Pfad. Das |
| | 125 | ist das Unterscheidungsmerkmal. |
| | 126 | |