NEWS
Watchdog für Alter der Datenpunkte
-
Hallo zusammen,
ich möchte einen Watchdog für die Änderung von Datenpunkten setzen, um meine Sensoren zu überwachen.
Da ich nicht auf die Änderung des Wertes triggern kann (ansonsten würde nach Neustart des Skripts bei einem bereits defekten Sensors nicht getriggert werden), habe ich einen Zeitplan definiert, der periodisch abfragt, ob sich der Zeitstempel bestimmter Sensoren geändert hat. Die betreffenden Datenpunkte habe ich in die iobroker Funktionen "watchdog" "gelegt".
Das ganze funktioniert auch so weit. Nun möchte ich möglichst schnell eine Info über einen defekten Sensor erhalten, aber sobald der Alarm ausgelöst wurde nicht immer wieder eine Nachricht erhalten, sondern ich würde hier gerne eine Kadenz einbauen. Also Abfrage der Sensor-Zeiten z. B. alle 5 min, aber die Benachrichtigung nur einmal direkt und dann z. B. jede Stunde. Daran scheitere ich gerade, da dies natürlich für jeden Sensor einzeln funktionieren soll.
<xml xmlns="https://developers.google.com/blockly/xml"> <variables> <variable id="5MS[62qBDEe5efRr9Als">darfSenden</variable> <variable id=".TPfY;gG|C!d+S9;2kUC">listWert</variable> <variable type="timeout" id="timeout">timeout</variable> </variables> <block type="variables_set" id="1F}o;zLV8NIL/[Dj*I_3" x="112" y="-487"> <field name="VAR" id="5MS[62qBDEe5efRr9Als">darfSenden</field> <value name="VALUE"> <block type="logic_boolean" id=")36{:!hXet^s}olc,G+I"> <field name="BOOL">TRUE</field> </block> </value> <next> <block type="schedule" id="0iraJ-umJfZ2v8^G.U@t"> <field name="SCHEDULE">*/5 * * * *</field> <statement name="STATEMENT"> <block type="controls_forEach" id="5Cd:JpJ$16NKFfIZF.P["> <field name="VAR" id=".TPfY;gG|C!d+S9;2kUC">listWert</field> <value name="LIST"> <block type="selector" id="t8{}nQK1MHjhE!B_FyuF"> <field name="TEXT">state[id=*](functions=watchdog)</field> </block> </value> <statement name="DO"> <block type="controls_if" id="Nfk=2r6]vAsd7(c*(^:N"> <value name="IF0"> <block type="logic_operation" id="Po:r62z?T6j6OSD{KhoR"> <field name="OP">AND</field> <value name="A"> <block type="variables_get" id="P}[j-O%B:qLd[v:fJ2u8"> <field name="VAR" id="5MS[62qBDEe5efRr9Als">darfSenden</field> </block> </value> <value name="B"> <block type="logic_compare" id="o)H%]$-3F7S+uO?*`iyU"> <field name="OP">GT</field> <value name="A"> <block type="math_arithmetic" id="5?)xuy1JV0{6,Er4:_3y"> <field name="OP">MINUS</field> <value name="A"> <shadow xmlns="http://www.w3.org/1999/xhtml" type="math_number"> <field name="NUM">1</field> </shadow> <block type="time_get" id=",r8wfoe=oFD4%j2V5tm6"> <mutation xmlns="http://www.w3.org/1999/xhtml" format="false" language="false"></mutation> <field name="OPTION">object</field> </block> </value> <value name="B"> <shadow type="math_number"> <field name="NUM">1</field> </shadow> <block type="get_value_var" id="e5J$}Zf)s@N[@ZNw9gL["> <field name="ATTR">ts</field> <value name="OID"> <shadow type="text"> <field name="TEXT"></field> </shadow> <block type="variables_get" id="z+~]lSD*$L%_0O`6Rg0G"> <field name="VAR" id=".TPfY;gG|C!d+S9;2kUC">listWert</field> </block> </value> </block> </value> </block> </value> <value name="B"> <block type="math_number" id="~5v16u^15UCUf4X6Y#cK"> <field name="NUM">900000</field> </block> </value> </block> </value> </block> </value> <statement name="DO0"> <block type="debug" id="~rf5W:iu_SC6_*)ZUR}["> <field name="Severity">log</field> <value name="TEXT"> <shadow type="text" id="QpSou#H}T[T[LjsA8{P/"> <field name="TEXT">BME280 Luftsensor: Sensorwert zu alt.</field> </shadow> <block type="text_join" id="V{6a/D`C].v1G#qzN{,k"> <mutation items="2"></mutation> <value name="ADD0"> <block type="text" id="6Ga/v*xFkhcl|~Q5fX!H"> <field name="TEXT">Sensorwert zu alt: </field> </block> </value> <value name="ADD1"> <block type="variables_get" id="{9-B4S/J$KyW(D3=4j2."> <field name="VAR" id=".TPfY;gG|C!d+S9;2kUC">listWert</field> </block> </value> </block> </value> <next> <block type="timeouts_cleartimeout" id="+1PM+[i;{oU5d8X!:D(y"> <field name="NAME">timeout</field> <next> <block type="timeouts_settimeout" id="Sl/!Vg[9|%lmlAD:dQ1s"> <field name="NAME">timeout</field> <field name="DELAY">60</field> <field name="UNIT">min</field> <statement name="STATEMENT"> <block type="variables_set" id="FsMK!|s_[qe.=)]ko/ob"> <field name="VAR" id="5MS[62qBDEe5efRr9Als">darfSenden</field> <value name="VALUE"> <block type="logic_boolean" id="#gN-[|7]hjh/y7%~.lce"> <field name="BOOL">TRUE</field> </block> </value> </block> </statement> <next> <block type="variables_set" id="rsQ9ig,9DHcV7w;2A=2X"> <field name="VAR" id="5MS[62qBDEe5efRr9Als">darfSenden</field> <value name="VALUE"> <block type="logic_boolean" id="L,1EWAq:h:p3/=ap/kkK"> <field name="BOOL">FALSE</field> </block> </value> </block> </next> </block> </next> </block> </next> </block> </statement> </block> </statement> </block> </statement> </block> </next> </block> <block type="variables_set" id="EhVj/|!D0?IbfP{#;s@=" x="193" y="1193"> <field name="VAR" id="5MS[62qBDEe5efRr9Als">darfSenden</field> <value name="VALUE"> <block type="logic_boolean" id="tH:WpL%tM0RP.^AHqnv0"> <field name="BOOL">TRUE</field> </block> </value> </block> </xml>
Ich bekomme es nicht hin, dass der Timeout bzw. die Variable "darfSenden" für jeden "lstWert" separat betrachtet wird. Offensichtlich ist die Variable nicht nur innerhalb der Schleife sondern global im Skript gültig.
So wie es jetzt gestaltet ist, wird der Alarm mit dem ersten Sensor ausgelöst und ab dann natürlich nicht mehr, da "darfSenden" dann wahr ist.Ich wollte schon Datenpunkte mit einem darfSenden oder Alarm_flag für jeden Sensor separat erstellen, aber das soll dann das Skript automatisiert tun und ich bekomme es nicht hin, automatisch aus der Objekt-ID einen sinnvollen Namen dafür zu extrahieren und einen Datenpunkt zu erzeugen.
Hat jemand eine Idee? Ich möchte nicht für jeden Sensor ein eigenes Skript oder eine eigene Funktion.
Danke!
-
-
@crunchip Die Idee eines Watchdogs ist ja, dass es in regelmäßigen Abständen ein Lebenszeichen gibt. Bleibt dies aus, so stimmt was auf der Seite des Sensors nicht. Bei meinen Sensoren ist sichergestellt, dass diese regelmäßig senden. Nicht alle meine Sensoren haben ein online/reachable/... Datenpunkt.
Den Adapter hatte ich mir bereits angesehen, habe aber keine Möglichkeit gefunden, einzelne Datenpunkte zu überwachen. So wie ich das sehe, kann man hier nur unterstützte Geräte/Adapter überwachen. Meine Daten kommen meist (nicht immer) über MQTT.
-
@sts85 sagte in Watchdog für Alter der Datenpunkte:
Die Idee eines Watchdogs ist ja, dass es in regelmäßigen Abständen ein Lebenszeichen gibt
durchaus, wenn ich jedoch zigbee als Beispiel nehme
The availability feature works differently for active and passive devices. Active devices (routers or mains powered end devices): by default they have to check-in every 10 minutes. If they don't, they will be pinged, if that fails the device will be marked as offline. Passive devices (everything that is not an active device, mostly battery powered devices): these devices need to check-in every 25 hours, they cannot be pinged so if they don't they will be marked as offline.
-
@crunchip Ja, aber auch hier gilt: Wenn mehr als 25h nichts passiert ist, gibt es wahrscheinlich ein Problem oder das Gerät wird nicht genutzt. Ein solches Gerät würde ich hier nicht überwachen wollen. Zumal Zigbee hier gleich den online/offline Flag mitbringt, auf den könnte man direkt triggern.
Es muss aber immer einen Coordinator/Server geben, der diesen Status setzt. Damit sind wir wieder bei meinem Skript, der das für nicht-Zigbee-Sensoren übernehmen soll.
Dennoch danke für den Hinweis.
-
@sts85 sagte: ist die Variable nicht nur innerhalb der Schleife sondern global im Skript gültig.
So ist es. Du benötigst ein Array für die Timer-Variable(n) und evtl. eines für
darfSenden
. Beispiel hier.@sts85 sagte in Watchdog für Alter der Datenpunkte:
ich bekomme es nicht hin, automatisch aus der Objekt-ID einen sinnvollen Namen dafür zu extrahieren
Wie sehen die DP-IDs aus?
-
@paul53 Oh, das sieht vielversprechend aus; ist ja sehr ähnlich. Vielleicht bekomme ich es anhand des Beispiels hin.
Kann ich denn die Intervalle mit dynamischen Namen belegen? Man kann in den Baustein keine Variable einfügen, sondern muss ihn direkt benennen?!
Hier ein Beispiel für eine Objekt-ID: mqtt.0.Sensor.ESP8266-IBC.IBCFuellmenge
-
@sts85 sagte: Kann ich denn die Intervalle mit dynamischen Namen belegen?
Wozu? Alle Intervall-Variablen werden in einem Array abgelegt.
@sts85 sagte in Watchdog für Alter der Datenpunkte:
Beispiel für eine Objekt-ID: mqtt.0.Sensor.ESP8266-IBC.IBCFuellmenge
Wenn der Name eindeutig ist, sollte man besser diesen verwenden.
Du prüfts auf einen Zeitstempel älter als 15 min. Das kann man auch mit einem Timeout von 15 Minuten, der bei jedem Trigger des zugehörigen Datenpunktes vorher gestoppt wird.
Anmerkung: "setze Intervall" und "setze timeout" lassen sich erst zum Schluss selektieren (evtl. vorher in die Javascript-Ansicht und wieder zurück wechseln).
-
@paul53 Schon mal danke.
Das Problem ist aber, dass der Datenpunkt ja nicht aktualisiert wird, wenn keine neuen Werte rein kommen. Damit kann ich darauf ja auch nicht triggern, sonst wäre es viel einfacher.
Wenn z. B. nach einem Stromausfall der ioBroker neu startet und dabei auch ein Sensor keine Werte mehr liefert, dann wird der jeweilige Datenpunkt ja nicht mehr aktualisiert, da keine neuen Werte mehr rein kommen. Hier hilft also nur die Überprüfung des Alters des DP oder habe ich einen Denkfehler?Somit funktioniert doch auch der Trigger auf die Änderung der ids nicht, richtig?
-
@sts85 sagte: der Datenpunkt ja nicht aktualisiert wird, wenn keine neuen Werte rein kommen.
Wenn er nicht (mehr) aktualisiert wird, läuft timeout ab und liefert die Nachricht.
@sts85 sagte in Watchdog für Alter der Datenpunkte:
Wenn z. B. nach einem Stromausfall der ioBroker neu startet und dabei auch ein Sensor keine Werte mehr liefert
Das ist ein Sonderfall, der mit dieser Lösung nicht abgedeckt wird.
Wenn man eine Zeitplan-Trigger verwendet, kann man den Namen mittels einer JS-Funktion mit Ergebnis ermitteln:return getObject(id).common.name;
-
@sts85 sagte in Watchdog für Alter der Datenpunkte:
@paul53 Schon mal danke.
Wenn z. B. nach einem Stromausfall der ioBroker neu startet und dabei auch ein Sensor keine Werte mehr liefert, dann wird der jeweilige Datenpunkt ja nicht mehr aktualisiert, da keine neuen Werte mehr rein kommen. Hier hilft also nur die Überprüfung des Alters des DP oder habe ich einen Denkfehler?In meinem Javascript, ist aber aktuell nur für einen Datenpunkt. Beende/Starte ich den Timeout beim Aktualieren und beim Neustart des Skripts. (Naja ich trigger auf nen Zeitwert den ich alle X abfrage, aber ist wie ein Timeout, nur das ich es selbst mache.)
-
@paul53 said in Watchdog für Alter der Datenpunkte:
@sts85 sagte: der Datenpunkt ja nicht aktualisiert wird, wenn keine neuen Werte rein kommen.
Wenn er nicht (mehr) aktualisiert wird, läuft timeout ab und liefert die Nachricht.
@sts85 sagte in Watchdog für Alter der Datenpunkte:
Wenn z. B. nach einem Stromausfall der ioBroker neu startet und dabei auch ein Sensor keine Werte mehr liefert
Das ist ein Sonderfall, der mit dieser Lösung nicht abgedeckt wird.
Wenn man eine Zeitplan-Trigger verwendet, kann man den Namen mittels einer JS-Funktion mit Ergebnis ermitteln:return getObject(id).common.name;
Wow, super. Vielen lieben Dank! Es funktioniert.... fast. Leider gibt er jetzt immer dieselbe Nachricht im Intervall aus. Also der Nachrichteninhalt ist immer identisch. Ich denke, da muss ich die msg auch in einer Liste speichern.
Du hast mir aber super weiter geholfen und ich habe das Prinzip mit der Variable Intervall und den Listen kapiert. -
@sts85 sagte: Leider gibt er jetzt immer dieselbe Nachricht im Intervall aus.
Wirklich? Zu jeder ID (und somit zu jedem Namen) gehört ein eigenes Intervall, an dessen Callback-Funktion die zugehörige Nachricht übergeben wird.
-
@paul53
In der Message außerhalb des Intervalls klappt es. Sobald diese innerhalb ist, bleibt sie gleich (letztverwendete Nachricht, so wie ich das sehe).
Hab es bisher noch nicht hinbekommen. Da macht es auch keinen Unterschied, die msg in eine Liste zu schreiben und anhand des Index auszuwählen. In dem Intervall bleibt die Nachricht gleich. -
@sts85 sagte: In dem Intervall bleibt die Nachricht gleich.
Poste bitte den erzeugten Javascript-Code ohne die letzte Zeile in Code tags.
Vermutung: Es gibt zwei VariablenIntervall
? -
@paul53 said in Watchdog für Alter der Datenpunkte:
@sts85 sagte: In dem Intervall bleibt die Nachricht gleich.
Poste bitte den erzeugten Javascript-Code ohne die letzte Zeile in Code tags.
Vermutung: Es gibt zwei VariablenIntervall
?Du hattest Recht, es gab zwei Variablen Intervall. Ich habe die Variable gelöscht. Die Intervall-Bausteine ebenfalls gelöscht und neu eingefügt. Danach die "richtige" Intervall-Variable gewählt. Nun habe ich das:
var ids, id, intervalle, idx, Intervall, msg; function listsRepeat(value, n) { var array = []; for (var i = 0; i < n; i++) { array[i] = value; } return array; } // Beschreibe diese Funktion … async function getName(id) { return getObject(id).common.name; } ids = Array.prototype.slice.apply($("state[id=*](functions=watchdog)")); intervalle = listsRepeat(null, ids.length); schedule("*/2 * * * * *", async function () { for (var id_index in ids) { id = ids[id_index]; idx = ids.indexOf(id) + 1; Intervall = intervalle[(idx - 1)]; if (parseFloat((new Date().getTime())) - getState(id).ts <= 900000) { (function () {if (Intervall) {clearInterval(Intervall); Intervall = null;}})(); } else if (!Intervall) { msg = 'Sensorwert zu alt: ' + String(await getName(id)); console.log(msg); Intervall = setInterval(async function () { console.log(msg); }, 6000); } intervalle[(idx - 1)] = Intervall; } });
Das Ergebnis ist aber dasselbe?!
Edit: Die timings sind nur für debugging-Zwecke
-
@sts85 sagte: Das Ergebnis ist aber dasselbe?!
Gerade getestet: Du hast recht. Erklären kann ich mir das Verhalten aber nicht.
-
@paul53
msg muss als 3. Parameter an die interne Intervall Funktion übergeben werden. Das geht doch auch bei seinterval? -
@ticaki sagte: msg muss als 3. Parameter an die interne Intervall Funktion übergeben werden.
Gerade getestet: Funktioniert auch nicht.
-