Setzt man neben Homematic Komponenten und der Steuerung via CCU (o. ä. piVCCU/RaspberryMatic…) zusätzlich auch das ioBroker Smart-Home-System ein, kommt man eigentlich um die Installation und Nutzung des ioBroker HomeMatic RPC Adapters (ioBroker.hm-rpc) zur Anbindung an die Kommunikationsmodule der Steuerungszentrale nicht herum. Dabei kommuniziert der Adapter mit einer Schnittstelle von der Steuerungszentrale, entweder über das BIN-RPC oder XML-RPC Protokoll. Oft müssen auch mehrere Adapter-Instanzen gleichzeitig laufen, da eine Instanz des Adapters nur für genau EINES der unterstützen Module (rfd (funk), HMIP-rfd, hs485d (wired), cuxd ..) zuständig sein kann.

Leider kam es bei Änderungen von Datenpunkten in ioBroker bei mir regelmäßig zu Übertragungsprobleme, sobald der Adapter versucht die Werte zur Steuerung der Homematic Komponenten an die Zentrale zu übertragen. Teilweise kommt dann eine entsprechende Meldung im ioBroker Log, was aber nicht immer der Fall sein muss.

Logmeldung – Beispiele:
error: hm-rpc.0 (26742) xmlrpc -> setValue ["MEQXXXXXXXX:1","LEVEL",1] FLOAT
error: hm-rpc.0 (26742) Cannot call setValue: XML-RPC fault: Failure

oder
error: hm-rpc.0 (26742) Error: XML-RPC fault: Generic error (TIMEOUT)

In all diesen Fällen, wurde der Wert nicht korrekt übertragen und die gewünschte Aktion nicht ausgeführt. Diese Problematik konnte ich vor allem dann beobachten, wenn viele Werte der Homematic-Datenpunkte in kurzer aktualisiert werden.

Beispiele: wenn Datenpunkt-Werte mittels Iteration in einem Script gesetzt oder mehrere Scripte mit solchen Aktionen zeitgleich oder kurz hintereinander laufen.

Leider konnte ich dieses Problem bisher nicht wirklich lösen, trotz intensiver Recherche und ausprobieren unterschiedlicher Lösungsansätze wie setStateDelayed, setTimeout usw….

Um das Problem trotzdem in den Griff zu bekommen, habe ich deshalb nachfolgendes Script als Workaround entwickelt. Zumindest bisher trat damit, bei konsequenter Verwendung in ioBroker Scripte, das Problem nicht mehr auf.

Script – Funktionsweise

Anstelle der Verwendung des Befehls setState zum Setzen neuer Werte, muss die gleichnamige Funktion „setState“ der „GlobalStateHandler“ Klasse verwendet werden. Diese führt bei Homematic Datenpunkten nicht sofort den „setState“ Befehl aus, sondern fügt zuerst die Aktion zu einer Warteschlange (Queue) hinzu. Die Abarbeitung der Queue wird danach sofort begonnen. Läuft jedoch bereits eine Verarbeitung, muss die Aktion solange mit der Abarbeitung warten, bis alle vorherigen Aktionen in der Queue verarbeitet wurden. Durch die synchrone Verarbeitung „zum Entprellen“ (Debounce) ist sichergestellt, dass nicht mehrere „setState“ Befehle gleichzeitig über Scripte gestartet werden, die sich ggf. gegenseitig beeinträchtigen können. Die Verarbeitung des nächsten Eintrags in der Warteschlange wird dann fortgesetzt, sobald für den betroffenen Datenpunkt, die Anerkennung der Änderung durch das Acknowledge (ack) Flag bestätigt wurde. Da nicht alle Homematic-Komponenten eine Rückmeldung für die Verarbeitung innerhalb des definierten Zeitraums zurückliefern, wird die Verarbeitung der Warteschlange nach erreichen eines Timeouts fortgesetzt.

Script – Installation

Der JavaScript-Code muss in ioBroker als globales Script eingerichtet werden. Somit ist eine zentrale Instanz der „GlobalStateHandler“ Klasse in allen Scripten verfügbar. Hierzu muss zuerst im Scripte Bereich des Javascript Script Engine Adapters, der Expertenmodus aktiviert werden. Danach sollte der neue Ordner/Bereich „global“ sichtbar sein, in dem das Script gespeichert werden muss.

Script – Verwendung

Beispiel 1:
Durch den await Befehl, wartet das Script solange, bis die „setState“ Aktion ausgeführt wurde und setzt dann das Script fort.

 (async () => { 
    const id_test_state = "javascript.0.variables.test";

    setTimeout(async function(){ await GSH.setState(id_test_state, '2'); }, 500);
    setTimeout(async function(){ await GSH.setState(id_test_state, '3'); }, 500);
    setTimeout(async function(){ await GSH.setState(id_test_state, '4'); }, 500);
    await GSH.setState(id_test_state, '1'); 

})();

Beispiel 2:
Die „setState“ Aktionen werden ohne zu warten der Warteschlange hinzugefügt und nacheinander abgearbeitet. Durch die Funktion „waitWhileProcessing“ besteht aber zusätzlich die Möglichkeit zu warten, bis alles aus der Warteschlange abgearbeitet wurde.

 const id_test_state = "javascript.0.variables.test";

 setTimeout(function(){ GSH.setState(id_test_state, '3'); }, 500);

 GSH.setState(id_test_state, '1'); // do not wait until action have been processed
 GSH.setState(id_test_state, '2'); 

 (async () => { 
    await GSH.waitWhileProcessing(); // wait until all actions in queue have been processed
    log('Complete! All queued actions are processed');
 })();

Script – Hinweis

Natürlich ist das Script nicht wirklich „die Lösung“ des eigentlichen Problems. Auch wird bedingt durch die synchrone Verarbeitung, die Ausführung von mehreren Befehlen verzögert. Daher sollte das Script bewusst und mit Be­dacht eingesetzt werden.

Script – Quellcode

https://github.com/mesche/iobroker-scripts/tree/master/iobroker_global_state_handler

setState: Synchrone Verarbeitung der ioBroker Homematic RPC Adapter Befehle via BIN-RPC/XML-RPC um Probleme bei der Kommunikation zu vermeiden

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.