Überwachung beliebiger Readings mit einem einzigen at

Begonnen von Benni, 18 Dezember 2022, 16:08:08

Vorheriges Thema - Nächstes Thema

Benni

Ja ich weiß: Es gibt readingsWatcher und es gibt DOIF und man kann das wahrscheinlich auch mit den beiden machen!

Nichts desto trotz habe ich was kleines, handliches gesucht, um readings auf Änderung zu überwachen um festzustellen, ob bestimmte Geräte noch "am Leben" sind, möglichst ohne zusätzliches Modul.

Für HM macht das bei mir natürlich schon der Action Detector. Für alle anderen, das waren bei mir bisher nicht sehr viele, gab es jeweils dedizierte Überprüfungen, verschiedenster Couleur.

Also habe ich das mal quasi mit FHEM-Grundbausteinen, bei mir in einem einzigen at zentralisiert, das beliebig viele readings, beliebiger devices entsprechend überwacht und einen Event erzeugt, wenn irgendein Reading zu alt geworden ist.
Mehr Anforderungen habe ich daran nicht. Darauf reagiert wird dann in einem oder mehreren notify.

Hier also die Raw Definition at-Devices:


defmod atAliveMonitoring at +*00:01:00 {\
my $hash=$defs{$SELF};;\
my ($cnt,$alerts) =(0,0);;\
my @alertDev;;\
readingsBeginUpdate($hash);;\
foreach (split /[,|\n]/,AttrVal($SELF,'monitored','')) {\
my ($dev,$rdWatch,$maxAge) = split /[:]/;;\
if(defined $dev && IsDevice($dev) && defined $rdWatch && $rdWatch && defined $maxAge && $maxAge+0>0) {\
$cnt++;;\
my $rdAlert='alert_'.$dev.'_'.$rdWatch;;\
my $age=ReadingsAge($dev,$rdWatch,-1);;\
if($age<$maxAge) {\
readingsBulkUpdateIfChanged($hash,$rdAlert,0,1);;\
} else {\
$alerts++;;\
push @alertDev,$dev.':'.$rdWatch;;\
if(ReadingsNum($SELF,$rdAlert,0)==0) {\
readingsBulkUpdateIfChanged($hash,$rdAlert,$age,1);; \
}\
}\
}\
}\
push @alertDev,'none' if(!@alertDev);;\
readingsBulkUpdateIfChanged($hash,'checked',$cnt,1);; \
readingsBulkUpdateIfChanged($hash,'alerts',$alerts,1);; \
readingsBulkUpdateIfChanged($hash,'alert-readings',join(",",@alertDev),1);; \
readingsEndUpdate($hash,1);;\
return;;\
}
attr atAliveMonitoring userattr monitored
attr atAliveMonitoring comment This at checks every minute, if the readings, specified in the userattr 'monitored' have been updated in the interval specifiead alongside the reading.\
The readings to be checked in 'monitored' are specified in the pattern \
\
  <device>:<reading>:<maxAge> \
\
as a comma or linefeed separated list.\
If newline is used then it is recommended to set the widgedOverride attribute of the FHEMWEB-Device to include the 'monitored' attribute with the 'textField-long' wigdget.\
\
\
Readings and events created:\
\
For each reading to be checked an appropriate flag-reading with a name pattern \
\
  alert_<device>_<reading> \
  \
in this at is created. Its  value is the age of the checked reading if it exceeds maxAge or 0 if not.   \
Exceeding maxAge is only flagged once for multiple exceedings in a row!\
\
Additional readings created: \
\
  'checked'   -> the number of readings checked in the last cycle.\
  'alerts'    -> how many alerts where detected the last cycle.\
  'alert-dev' -> all readings with errors as a comma separated list of <device>:<reading>\
\
For all those Readings, events are created, which could be further handled, e.g. by using a notify!
attr atAliveMonitoring devStateIcon inactive:ios-off:active .*:ios-on-blue:inactive
attr atAliveMonitoring event-on-change-reading .*


Normalerweise bin ich auch der Meinung, dass Code, wie hier in der DEF, besser in der MyUtils aufgehoben ist. In diesem Fall fand ich es aber charmant, das Device in vollem Funktionsumfang per Raw Definition zur Verfügung stellen zu können.
Konsequenterweise habe ich dafür auf ausführliche Kommentare im Code verzichtet, denn den muss ein "normaler" Endanwender auch gar nicht verstehen können. ;)

Eine "Doku" zur Anwendung auf Englisch findet sich im comment-Attribut des at.

Trotzdem hier nochmal kurz auf Deutsch:

Sobald das at, wie oben  definiert ist, können alle Readings von Devices, die überwacht werden sollen, im Attirbut 'monitored' eingetragen werden.
Eingetragen wird in Form einer durch Komma oder Zeilenvorschub (Lesbarkeit) getrennten Liste von Spezifikationen der Form <device>:<reading>:<maxAge>.
<reading> ist der Name der Readings vom Device <device> das überwacht werden soll und dessen Wert nicht älter als <maxAge> Sekunden sein darf.

Überschreitet eins der Readings das angegebene maxAge zum Zeitpunkt der Überprüfung werden im at das reading mit Namen alert_<device>_<reading> mit dem Alter in Sekunden des überwachten readings befüllt.
Dies geschieht nur einmal, beim ersten auftreten des "Fehlerfalls", sollte das mehre Überprüfungszyklen in Folge der Falls sein.
Ansonsten enthält dieses alert_ - Reading 0.

Außerdem werden in jedem Zyklus (Das at läuft alle 60 Sekunden) bei Änderung folgende Readings/Events generiert:

    checked: Anzahl geprüfter readings (Spezifikationen)
    alerts: Anzahl der festgestellten Zeitüberschreitungen
    alert-dev: Liste der zu alten Readings in Form einer Komma getrennten Liste aus <device>:<reading> (gibt's keine steht 'none' drin)

That's it!

Viel Spaß damit!
gb#