FHEM Forum

FHEM - Hausautomations-Systeme => MQTT => Thema gestartet von: Mihca am 25 Juni 2020, 14:59:40

Titel: [gelöst] LWT von allen MQTT2-Device auslesen und ggf. Warnhinweis geben
Beitrag von: Mihca am 25 Juni 2020, 14:59:40
Ich würde gerne einen "Warndummy" schalten, wenn eines meiner ca 30 per MQTT2 angebundenen Devices ausfällt, d.h. das Reading LWT ist nicht mehr "Online". Per readingsGroup habe ich alle wichtigen Raeadings (auch LWT) bereits zusammengefasst.

Den Dummy könnte man natürlich schalten, indem von alle Devices jeweils einzeln per DoIf das LWT ausgelesen wird {"ReadingsVal("[Device]", "LWT",  "offline")} und der Dummy geschaltet wird. Das gibt dann ca. 30 individuelle "ReadingsVal" Abfragen.

Hat jemand von Euch eine Idee, wie man das eleganter hinbekomen kann?

Vielen Dank vorab!
Achim

Titel: Antw:LWT von allen MQTT2-Device auslesen und ggf. Warnhinweis geben
Beitrag von: Beta-User am 25 Juni 2020, 15:21:42
Hätte dazu u.a. zwei Ansätze anzubieten:

Als reine Anzeige kannst du dir eine weitere readingsGroup bauen, die eben nur die "[Oo]ffline"-Geräte anzeigt. Hier mal ein cfg-Auszug, wie ich das für meine MySensors-Devices habe (bis zum debuggen der Verbindung hatte ich da einige Ausfälle gehabt...):
define Status_RS485 readingsGroup <Gerät>,<Status> TYPE=MYSENSORS_DEVICE:FILTER=IODev=MySensorsRS485GW:heartbeat
attr Status_RS485 group Technik
attr Status_RS485 mapping %ALIAS
attr Status_RS485 noheading 1
attr Status_RS485 room Startseite,Steuerung->Allgemein
attr Status_RS485 valueFormat {$VALUE !~ m/alive/?$VALUE:undef;;}
attr Status_RS485 valueIcon {'heartbeat.dead' => 'lan_rs485@orange','heartbeat.NACK' => 'lan_rs485@red' }


Ansonsten kannst du z.B. mit einem notify, das auf .*:LWT.[Oo]ffline reagiert, nicht nur den Dummy triggern, sondern auch eine Telegramm-Message senden, wenn was ausfällt. Die "Gegenrichtung" ist nicht ganz so trivial, aber auch da könnte man z.B. prüfen, ob es Überhaupt MQTT2_DEVICE gibt, die im Reading LWT "offline" haben. Auf die Schnelle nur ein Perl-Fragment, das du ggf. anpassen kannst:
{my @devices=devspec2array("TYPE=(siri|alexa|gassistant)");;return 1 if $devices[0];;return 0}
Titel: Antw:LWT von allen MQTT2-Device auslesen und ggf. Warnhinweis geben
Beitrag von: Mihca am 25 Juni 2020, 16:30:59
Danke! Habe aus Deinem ersten Vorschlag dann das gemacht:

define StatusMQTT2 readingsGroup <Gerät>,<Status> TYPE=MQTT2_DEVICE:FILTER=IODev=MQTT2Server:LWT
attr StatusMQTT2 group Warnung
attr StatusMQTT2 mapping %ALIAS
attr StatusMQTT2 room Haus,System,MQTT2_DEVICE
attr StatusMQTT2 valueFormat {$VALUE !~ m/Connected/?$VALUE:undef;;}
attr StatusMQTT2 valueIcon {'LWT.Offline' => '10px-kreis-rot@red','LWT.Connection Lost' => '10px-kreis-rot@red' }


Das führt dazu, dass all Devices in der ReadungsGroup auftauchen und nicht nur die "Offline" Devices. Hast Du noch eine Rat?
Danke
Achim
Titel: Antw:LWT von allen MQTT2-Device auslesen und ggf. Warnhinweis geben
Beitrag von: Beta-User am 25 Juni 2020, 17:00:46
Hast du das hier schon versucht:

attr StatusMQTT2 valueFormat {$VALUE !~ m/[Oo]ffline/?$VALUE:undef;;}

Wenn alles online ist, wird da nichts angezeigt; da steht nur was drin, wenn auch tatsächlich ein Device "Offline" oder "offline" ist. Zum Testen ggf. mal manuell einen passenden LWT-Status setzen oder einen vom Netz nehmen?
Titel: Antw:LWT von allen MQTT2-Device auslesen und ggf. Warnhinweis geben
Beitrag von: Mihca am 25 Juni 2020, 17:19:44
Damit bleiben alle Geräte in der Liste des StatusMQTT2-Devices, die "Online" oder "Connected" sind. Gräte, die "Offline" (vom Netz) sind erscheinen nicht mehr in der Liste.
Titel: Antw:LWT von allen MQTT2-Device auslesen und ggf. Warnhinweis geben
Beitrag von: Beta-User am 25 Juni 2020, 17:26:49
Oh ja, sorry! Da war ja die Logik invertiert. Dann also entweder den "nicht-Match" nehmen, aber mit den passenden Werten, oder eben den "Match":


attr StatusMQTT2 valueFormat {$VALUE =~ m/[Oo]ffline/?$VALUE:undef;;}



attr StatusMQTT2 valueFormat {$VALUE !~ m/([Oo]nline|Connected)/?$VALUE:undef;;}
Titel: Antw:LWT von allen MQTT2-Device auslesen und ggf. Warnhinweis geben
Beitrag von: Mihca am 25 Juni 2020, 17:51:56
Cool, das geht!  :) Jetzt sind nur noch die Devices in der Liste die "Offline" (Tasmota) sind oder auf "Connection Lost" (ESPEasy) stehen. Hier für alle, die dasselbe machen möchten das komplette RAW-Listing des funktionierenden Devices:

defmod StatusMQTT2 readingsGroup <Gerät>,<Status> TYPE=MQTT2_DEVICE:FILTER=IODev=MQTT2Server:LWT
attr StatusMQTT2 group Warnung
attr StatusMQTT2 mapping %ALIAS
attr StatusMQTT2 room Haus,System,MQTT2_DEVICE
attr StatusMQTT2 valueFormat {$VALUE !~ m/([Oo]nline|Connected)/?$VALUE:undef;;}
attr StatusMQTT2 valueIcon {'LWT.Offline' => '10px-kreis-rot@red','LWT.Connection Lost' => '10px-kreis-rot@red' }


Jetzt fehlt mir noch der Schritt, wie ich diese Liste auswerte und meinen Dummy trigger.

Titel: Antw:LWT von allen MQTT2-Device auslesen und ggf. Warnhinweis geben
Beitrag von: Beta-User am 25 Juni 2020, 18:02:48
Die readingsGroup ist wie geschrieben als reine Anzeige gedacht.
Zitat von: Beta-User am 25 Juni 2020, 15:21:42
Als reine Anzeige
Wenn du irgend einen konsolidierten Dummy brauchst, gilt immer noch:
ZitatAnsonsten kannst du z.B. mit einem notify, das auf .*:LWT.[Oo]ffline reagiert, nicht nur den Dummy triggern, sondern auch eine Telegramm-Message senden, wenn was ausfällt. Die "Gegenrichtung" ist nicht ganz so trivial, aber auch da könnte man z.B. prüfen, ob es Überhaupt MQTT2_DEVICE gibt, die im Reading LWT "offline" haben. Auf die Schnelle nur ein Perl-Fragment, das du ggf. anpassen kannst: {my @devices=devspec2array("TYPE=(siri|alexa|gassistant)");;return 1 if $devices[0];;return 0}
Wenn es z.B. um die pure Anzahl geht, könntest du EDIT: "count" verwenden. Die passende devspec kannst du mit list ermitteln. Ungetestet:
list TYPE=MQTT2_DEVICE:FILTER=IODev=MQTT2Server:FILTER=LWT!~([Oo]nline|Connected)
Dann ein notify auf alle LWT-Events und dann eben in Perl als Anweisung was in diese Richtung (ungetestet, per Edit korrigiert):
{ my $counts=fhem("count <deine devspec> raw"); fhem("setreading meinTollerDummy count_disconnected $counts")}(Gibt sicher auch andere Varianten, das umzusetzen. Ich bin halt "altmodisch", was sowas angeht).
Titel: Antw:LWT von allen MQTT2-Device auslesen und ggf. Warnhinweis geben
Beitrag von: Mihca am 25 Juni 2020, 19:37:43
Nun habe ich ein DoIf eingerichtet:

defmod StoerungMQTT2DoIf DOIF ({fhem("list TYPE=MQTT2_DEVICE:FILTER=IODev=MQTT2Server:FILTER=LWT!~([Oo]nline|Connected)")} !1) \
(\
set StoerungMQTT2 on\
) \
DOELSE\
(\
set StoerungMQTT2 off\
)


Es detektiert allerdings immer cmd2 also keine Störung :(

Wenn ich

{fhem("list TYPE=MQTT2_DEVICE:FILTER=IODev=MQTT2Server:FILTER=LWT!~([Oo]nline|Connected)")}

in der Kommandozeile eingebe, erhalte ich ein Listing des nicht verbundnenen Devices. Ich habe DoIf auch schon im Perl modus ausprobiert. Es funzt alles nicht. Was mache ich noch falsch?

Danke vorab!
Titel: Antw:LWT von allen MQTT2-Device auslesen und ggf. Warnhinweis geben
Beitrag von: xenos1984 am 26 Juni 2020, 06:29:34
Dein DOIF hat keinen Ereignistrigger:

http://fhem.de/commandref_DE.html#DOIF_Ereignissteuerung_ueber_Auswertung_von_Events

Du willst vermutlich sowas:

http://fhem.de/commandref_DE.html#DOIF_aggregation

Anwendungsbeispiel im gleichen Abschnitt:

define di_Fenster DOIF (["^Window:open"])
(push "Fenster $DEVICE wurde geöffnet. Es sind folgende Fenster offen: [@"^Window":state:"open"]")
DOELSEIF ([#"^Window:closed":state:"open"] == 0)
(push "alle Fenster geschlossen")
Titel: Antw:LWT von allen MQTT2-Device auslesen und ggf. Warnhinweis geben
Beitrag von: Mihca am 26 Juni 2020, 12:15:51
Danke für den Tip. Danach habe ich nun dieses DoIf, das aber auch nicht das gewünschte Ergebnis liefert:

([#:d0:"TYPE=MQTT2_DEVICE":LWT|"Offline|Connection Lost": > 0])
(
set StoerungMQTT2 on
)
DOELSE
(
set StoerungMQTT2 off
)


Der Gedanke ist, dass

#:d0:"TYPE=MQTT2_DEVICE":LWT|"Offline|Connection Lost":

die Anzahl der Offline-Devices liefert, was aber anscheinend nicht der Fall ist. Das DoIf landet immer bei "set StoerungMQTT2 off" unabhängig davon, wieviele Devices Offline sind.

Hat jemand eine Idee, was dort noch "faul" ist.

Vielen Dank vorab!
Titel: Antw:LWT von allen MQTT2-Device auslesen und ggf. Warnhinweis geben
Beitrag von: Beta-User am 26 Juni 2020, 12:49:49
Interessehalber habe ich eben nochmal die notify-Variante durchgespielt (DOIF kapiere ich nicht und will es auch nicht mehr lernen).

Mit einer etwas anderen devspec im notify und einem Pseudotrigger sieht das so aus:
defmod N_Test notify Pool.Pumpe:testreading.* { my $counts = fhem( "count TYPE=MQTT2_DEVICE:FILTER=LWT!~([Oo]nline|Connected) raw" );; fhem("setreading N_Test count_disconnected $counts") }

Triggere ich das Ding jetzt mit sowas (im Prinzip ist der Wert beliebig),
trigger Pool.Pumpe testreading 1steht hinterher folgendes in der RAW-definition des notify:
setstate N_Test 2020-06-26 12:47:04
setstate N_Test 2020-06-26 12:47:04 count_disconnected 11
Titel: Antw:LWT von allen MQTT2-Device auslesen und ggf. Warnhinweis geben
Beitrag von: Mihca am 26 Juni 2020, 13:46:09
@Beta-User
danke, das mit der Anzahl der Offline-Geräte funktioniert so. Das Ganze soll automatisch getriggert werden, wenn ein Device Offline ist. Könnte man mit einem Timer alle paar Minuten machen, kommt mir aber irgendwie unelegant vor. Hast Du da noch was Elegantes auf Lager?
Titel: Antw:LWT von allen MQTT2-Device auslesen und ggf. Warnhinweis geben
Beitrag von: xenos1984 am 26 Juni 2020, 13:48:28
Ich würde es so versuchen (ungetestet):
([#"":LWT:"Offline|Connection Lost" and $TYPE eq "MQTT2_DEVICE"] > 0)
(
set StoerungMQTT2 on
)
DOELSE
(
set StoerungMQTT2 off
)
Titel: Antw:LWT von allen MQTT2-Device auslesen und ggf. Warnhinweis geben
Beitrag von: Beta-User am 26 Juni 2020, 13:55:52
MMn. sollte das immer dann getriggert werden, wenn irgendein Device bei LWT irgendwas meldet, sonst bekommst du ja nicht mit, wenn alles online ist. Nun kenne ich dein Namensschema nicht, und sowas wie ".*:LWT:.*" dürfte zwar funktionieren, sollte aber verbessert werden...

Den Wert würde ich übrigens beim IO vorhalten (TYPE=MQTT2_(SERVER|CLIENT)), insgesamt kommt es aber darauf an, was überhaupt Sinn macht. Eine Benachrichtigung würde ich z.B. nicht bei jeder Änderung machen, sondern nur, wenn es von 0 auf irgendwas geht.

Zur Inspiration, wie man sowas auch verzögern kann, empfehle ich Benni's "globale und flexible Fenster- und Tür-offen..." (der Spur nach; bitte bei Interesse suchen, ist ein recht interessantes und instruktives Beispiel, wie man generalisierten Perl-Code nutzen kann ;) ).
Titel: Antw:LWT von allen MQTT2-Device auslesen und ggf. Warnhinweis geben
Beitrag von: Mihca am 26 Juni 2020, 14:22:14
@xenos1984
ja, so funktioniert es! Danke! :)

@Beta-User
da ich den Notify nicht automatisch getriggert bekomme, und der DoIf-Weg funktioniert, mache ich da jetzt nicht weiter. Vielen Dank Dir mal wieder für Geduld und tolle Unterstützung.  :)

Viele Grüße
Achim
Titel: Antw:[gelöst] LWT von allen MQTT2-Device auslesen und ggf. Warnhinweis geben
Beitrag von: Beta-User am 26 Juni 2020, 14:31:21
...ist ok und Danke für die Rückmeldung.

Ich gebe nur zu Bedenken, dass das DOIF (fast) genau das .*:LWT:.*-Schema nutzt, um getriggert zu werden (jedenfalls nach meinem möglicherweise falschen Verständnis das Moduls). Du solltest solche Konstruktionen, die über alle Devices gehen, mMn. sehr kritisch im Auge behalten, da sowas schnell dazu führen _kann_, dass das System langsam wird, vor allem dann, wenn (möglicherweise indirekt) umfangreichere Aktionen daran anknüpfen.

Von daher kann ich nur nochmal meine allgemeine Empfehlung wiederholen, dich mit devspec und regex intensiver auseinanderzusetzen, sonst kommen irgendwann seltsame Effekte und der Frust ist größer, wie wenn du auf diesen Aspekt etwas mehr Wert gelegt hättest...
Titel: Antw:[gelöst] LWT von allen MQTT2-Device auslesen und ggf. Warnhinweis geben
Beitrag von: Mihca am 26 Juni 2020, 14:46:46
Noch nicht ganz gelöst. Es funktioniert bei LWT=Offline, aber nicht bei LWT=Connection Lost
Titel: Antw:[gelöst] LWT von allen MQTT2-Device auslesen und ggf. Warnhinweis geben
Beitrag von: Mihca am 26 Juni 2020, 15:25:17
@Beta-User

habe auch das Notify jetzt mit dem Trigger über einen Tasmota-Switch hingekriegt:

4CH_Switch_E_Keller:Uptime.*
{
my $counts = fhem( "count TYPE=MQTT2_DEVICE:FILTER=LWT!~([Oo]nline|Connected) raw" );

if ($counts > 0.5 )
{
fhem("set StoerungMQTT2 on")
}
else
{
fhem("set StoerungMQTT2 off")
};

fhem("setreading StoerungMQTT2 DisconnectedDevices $counts")
}


Das Notify reagiert auch auf "Connected"

Danke :)
Titel: Antw:[gelöst] LWT von allen MQTT2-Device auslesen und ggf. Warnhinweis geben
Beitrag von: Beta-User am 26 Juni 2020, 15:37:38
...immer noch nicht optimal: Wenn du auf ein anderes (!) Event von einem speziellen Device reagierst, und genau diese Hardware fällt aus, passiert: nichts...
Dann kannst du gleich einen Timer (at) anlegen, das ist dann sicherer (und vermutlich leichtgewichtiger, wie auf alle passenden Events zu reagieren)! Du solltest dann aber auf einen Statuswechsel prüfen und das Reading nur erneuern, wenn es sich ändert.

Die Prüfung auf $counts kann übrigens auch kürzer sein:
if ($counts)Das schlägt nur dann nicht an, wenn $counts=0 oder $counts nicht definiert ist ;) . (Aber schon ab 0.0000...1).
Titel: Antw:[gelöst] LWT von allen MQTT2-Device auslesen und ggf. Warnhinweis geben
Beitrag von: Mihca am 26 Juni 2020, 16:01:47
Da hast Du natürlich Recht mit dem Trigger. Habe es jetzt als Timer. Für alle, die es nachmachen möchten, hier die endgültige Version:

defmod StoerungMQTT2at at +*00:05\
{ \
my $counts = fhem( "count TYPE=MQTT2_DEVICE:FILTER=LWT!~([Oo]nline|Connected) raw" );;\
\
if ($counts) \
{\
fhem("set StoerungMQTT2 on")\
}\
else\
{\
fhem("set StoerungMQTT2 off")\
};; \
\
fhem("setreading StoerungMQTT2 DisconnectedDevices $counts") \
}