AutoUpdate für Zigbee2MQTT

Moin,
vor fast genau 3 Jahren habe ich schon mit IPS, Z2M und dem Modul Zigbee2MQTT Updates für Geräte durchgeführt. In den letzten 3 Jahren ist an allen Ecken viel geschehen. Ich habe es mir jetzt angesehen und es geht mit kleinen Änderungen immer noch.

Die Idee hinter diesem Trick ist ganz einfach. Die Zigbee-Geräte sind nicht immer empfangsbereit für ein Updatebegehren da sie, wie ich, fast immer schlafen. Nachdem sie aber Statusänderungen gemeldet haben sind sie noch eine gewisse Zeit wach und nehmen Befehle entgegen und das nutze ich aus. Ich reagiere auf Aktualisierung von LQI und schicke dann sofort den Update-Befehl.

Im Zigbee2MQTT-Modul muss etwas hinzugefügt werden. In der Datei Zigbee2MQTTHelper.php muss Folgendes etwa bei Zeile 1930 ergänzt werden. Die beste Stelle ist vor/hinter der jetzigen Auswertung von „updateAvailable“.

                if (array_key_exists('update', $Payload)) {
						//Bleibt hier. gibt es nicht als Expose
					$this->RegisterVariableInteger('Z2M_FWinstalled', $this->Translate('installierte Firmware'), '');
					$this->RegisterVariableInteger('Z2M_FWlatest', $this->Translate('aktuelle Firmware'), '');
					$this->RegisterVariableString('Z2M_UpdateStatus', $this->Translate('Update Status'), '');
                    if (isset($Payload['update']["installed_version"])) $this->SetValue('Z2M_FWinstalled', $Payload['update']["installed_version"]);
                    if (isset($Payload['update']["latest_version"])) $this->SetValue('Z2M_FWlatest', $Payload['update']["latest_version"]);
                    if (isset($Payload['update']["progress"])){
                    	$this->SetValue('Z2M_UpdateStatus', $Payload['update']["state"] . " " . $Payload['update']["progress"] . "%");
                    }
                    else $this->SetValue('Z2M_UpdateStatus', $Payload['update']["state"]);
                }

Hiermit liefert Z2M wieder den Status von Update in „state“ und es wird als „Update Status“ als Variable ausgegeben. Ich werte 3 Stati aus:
idle = kein Update verfügbar
available = Update ist verfügbar
updating XY% = es läuft ein Update und XY% sind schon erledigt.

Am Ende von den Updates gibt es noch ein Paket mit Informationen zur Firmware Version. Die kann ich nicht mehr auswerten weil meine Geräte schon alle aktuelle Firmware haben. Wenn die Änderungen im Zigbee2MQTT Modul eingebaut worden sind und das Modul neu geladen wurde muss es einige Tagen laufen damit die ersten möglichen Updates auch übermittelt worden sind.

Weiter muss ein MQTT-Klient angelegt werden mit dem Topic „zigbee2mqtt/bridge/request/device/ota_update/update“ (ohne Anführungszeichen). Das GateWay für diesen Klienten auf den MQTT-Server von Zigbee2MQTT festlegen. Die ID der Variablen dieses Klienten merken denn die muss im folgenden Script eingesetzt werden.

<?php
// Variable anlegen wo die aktuell behandelte Z2M Instanz gespeichert wird.
$InstanzID = @IPS_GetVariableIDByName('InstanzID', $_IPS['SELF']);
if($InstanzID === false)
{
    $InstanzID = IPS_CreateVariable(1);
    IPS_SetName($InstanzID, 'InstanzID');
    IPS_SetParent($InstanzID, $_IPS['SELF']);
// Bisher keine Instanz behandeln    
    SetValue($InstanzID, 0);
}
// Variable anlegen wo der Trigger für die Update-Routine gespeichert wird
$TriggerID = @IPS_GetVariableIDByName('TriggerID', $_IPS['SELF']);
if($TriggerID === false)
{
    $TriggerID = IPS_CreateVariable(1);
    IPS_SetName($TriggerID, 'TriggerID');
    IPS_SetParent($TriggerID, $_IPS['SELF']);
// Bisher kein Trigger gesetzt    
    SetValue($TriggerID, 0);
}

// aktuell behandelte Instanz laden
$Instanz = GetValue($InstanzID);
switch ($_IPS['SENDER']){
// Wenn das Script durch Trigger aufgerufen wurde    
    case "Variable":
        $VarID1 = @IPS_GetObjectIDByIdent('Z2M_UpdateStatus', $Instanz);
// aktuellen Update-Status auslesen
        $Var1 = GetValue($VarID1);
// Wenn Update verfügbar Z2M sagen das es das Update starten möge
        if ($Var1 == 'available'){
// Konfiguration der Z2M Instanz laden um an den Topic von dem Gerät zu kommen            
            $config = json_decode(IPS_GetConfiguration($Instanz), true);
// Hier die ID der Variablen vom erstellten MQTT-Klienten eintragen
            RequestAction(<ID von MQTT-Klienten Variable eintragen>, $config["MQTTTopic"]);
        }
// Kein Update mehr verfügbar, d.h. Update-Routine wurde beendet
        if ($Var1 == 'idle'){
// Ins Logfile eintragen            
            IPS_LogMessage("Update Ende", IPS_GetName($Instanz));
// Trigger deaktivieren
            $Trigger = GetValue($TriggerID);
            IPS_SetEventActive($Trigger, false);
            SetValue($InstanzID, 0);
// Nach 2 Minuten neu auf Updates prüfen
            IPS_SetScriptTimer($_IPS['SELF'], 120);
        }
        break;
// Wenn Script in Console oder per Timer gestartet wurde
    case "Execute":
    case "TimerEvent":
// Alle Zigbee2MQTT Instanzen in ein Feld einlesen
        $InstanzIDsList = IPS_GetInstanceListByModuleID('{E5BB36C6-A70B-EB23-3716-9151A09AC8A2}');  // Zigbee2MQTT
// alle Z2M Instanzen untersuchen
        foreach ($InstanzIDsList as $Instanz) {
// Gibt es Status-Variable
            $VarID1 = @IPS_GetObjectIDByIdent('Z2M_UpdateStatus', $Instanz);
// ID von LQI ermitteln für den Trigger
            $VarID2 = @IPS_GetObjectIDByIdent('Z2M_Linkquality', $Instanz);
// Status-Variable vorhanden
            if ($VarID1 > 0){
                $Var1 = GetValue($VarID1);
// Gibt es Update für dieses Gerät?
                if ($Var1 == 'available'){
// Update Start ins Logfile eintragen
                    IPS_LogMessage("Update Start", IPS_GetName($Instanz));
// Jetzt nicht mehr per Timer sondern per Trigger aufrufen
                    IPS_SetScriptTimer($_IPS['SELF'], 0);
// aktuelle Instanz merken
                    SetValue($InstanzID, $Instanz);
// Gibt es schon Trigger?
                    $Trigger = GetValue($TriggerID);
// Nein
                    if ($Trigger == 0){
// Trigger einrichten und ID für später merken
                        $Trigger = IPS_CreateEvent(0);
                        IPS_SetParent($Trigger, $_IPS['SELF']);
                        IPS_SetEventAction($Trigger, "{7938A5A2-0981-5FE0-BE6C-8AA610D654EB}",[]);
                        IPS_SetEventActive($Trigger, false);
                        SetValue($TriggerID, $Trigger);
                    }
// Trigger auf LQI von aktueller Instanz setzen
                    IPS_SetEventTrigger($Trigger, 0, $VarID2);
// Trigger aktivieren                    
                    IPS_SetEventActive($Trigger, true);
                    return;
                }
            }
        }
// Wenn es keine Updates mehr gibt Script nur einmal pro Woche aufrufen        
        IPS_SetScriptTimer($_IPS['SELF'], 7 * 24 * 3600);
        break;
}
?>

Wenn das Script einmal gestartet wurde läuft es im Prinzip ewig und sorgt immer für aktuelle Firmware. Möchte man es anhalten muss das Trigger-Ereignis und der Script-Timer deaktiviert werden.

Zu den Updates gibt es noch einiges zu sagen:

  1. Bei Lampen und Steckdosen ist es unkompliziert da die Geräte immer auch Befehle warten und sich auch oft melden. Oft startet das Update bei der ersten Aktualisierung von LQI. Möchte man es erzwingen einfach Steckdose oder Lampe schalten und auf den Update Status achten. Es kann einige Sekunden/Minuten dauern bis updating auch gemeldet wird. Bei Lampen/Steckdosen dauert ein Update meistens weniger als 1 Stunde.
  2. Bei Sensoren die sich oft melden wie Bewegung- oder Helligkeitssensoren ist es ähnlich unkompliziert wie bei den Lampen. Update dauert hier aber deutlich länger im Stundenbereich.
  3. Bei Aktoren die sich nur sehr selten von alleine melden wie z.B. Schalter sollte man etwas nachhelfen indem man eine Taste drückt und dann wartet ob sich der Update Status ändert. Bei meinen Tadfri-Schalter (Ikea) reichte oft ein einziger Tastendruck.
  4. Das ein Update beendet wurde heißt leider noch nicht das es auch erfolgreich war. Gerade bei batteriebetriebenen Sensoren kann es öfter vorkommen das es nicht auf Anhieb klappt. In diesem Fall hilft es den Sensor/Aktor in die Nähe des Koordinators zu stellen wenn möglich. Wenn mir jemand das Payload am Ende eines erfolgreichen Updates schicken könnte würde ich es in das Script einbauen so das man sofort erkennen kann ob es erfolgreich war.

Selbst wenn man das Script nicht benutzen möchte ist es hilfreich. In IPS sieht man wo ein Update verfügbar ist und kann dann gezielt das Update in der GUI von Z2M starten.

Frohe Weihnacht Ralf

1 „Gefällt mir“

Vielen Dank für das nette Gift.

Wünsche ein frohes Weihnachtsfest

Moin,
eines habe ich noch vergessen. Falls ihr Z2M schon lange benutzt und auch OTA Updates verwendet habt steht bei Ikea vielleicht noch „test url benutzen“ das sollte deaktiviert werden denn dort liegen jetzt ältere Firmware Versionen.

Ralf