Statusreport an Telgrambot versenden mit DbLog&SQL-Query

Begonnen von Darrol, 16 Juli 2017, 21:03:24

Vorheriges Thema - Nächstes Thema

Darrol

Hallo allerseits,

ich habe gerade Schwierigkeiten auszuklabüstern wie ich mehrere Readings von verschiedenen Devices zusammenfasse und als eine einzige Nachricht an meinen Telegram-Bot verschicke.
Konkret möchte ich den Zustand aller Fenster-/Türsensoren(HM-SEC-SCo) abfragen können.

Ich habe mir zur Kommunikation mit dem Bot ein Notify erstellt und für die Lampenschaltung erfolgreich testen können.

telebot:msgText.* {
if ($EVTPART1 eq 'Lichter') {
        if ($EVENT =~ 'an') {
            fhem("set sideboard_led,leuchtschlauch_blau,wohnwand_led,laserpod on");
fhem("set telebot send Habe alle Lichter angeschaltet");
        }
        elsif ($EVENT =~ 'aus') {
            fhem("set sideboard_led,leuchtschlauch_blau,wohnwand_led,laserpod off");
fhem("set telebot send Habe alle Lichter ausgeschaltet");
        }
}
elsif ($EVTPART1 eq 'Status'){
if ($EVENT =~ 'Fenster'){
fhem("set telebot send $MEIN_STATUSREPORT ");
}
}
}


Jetzt hätte ich gerne an der Stelle wo  $MEIN_STATUSREPORT steht  eine Übersicht über die betreffenden Geräte wie sie Beispielsweise der unten stehende SQL-Select liefern würde habe aber keine
Idee wie ich das umsetzen kann oder wo ich nachlesen sollte.

Select DEVICE, CASE VALUE WHEN 'open' THEN 'offen' ELSE 'geschlossen' END as Status
from current
where device like ('fenster_%');





Update:
Ich bin nun mittlerweile  auf das auf das Modul DbRep gestoßen, welches eine frei definierbare Abfrage an die Datenbank senden kann und das Ergebnis in den Readings parat hält. Allerdings kann das Ergebnis einer solchen DB-Abfrage nicht innerhalb eines Notify-Events verarbeitet werden.

D.h.  wenn ich probiere die Ergebnisse direkt abzuholen, dann erhalte ich als Ausgabe 0 Zeile(n) und 0 :
elsif ($EVTPART1 eq 'Status'){
if ($EVENT =~ 'Fenster'){
fhem("set Reports sqlCmd Select DEVICE, CASE VALUE WHEN 'open' THEN 'offen' ELSE 'geschlossen' END as Status from current where device like ('fenster_%');");
my $numRows = ReadingsVal("Reports","sqlResultNumRows",0) . " Zeile(n) \r\n";
my $msg = $numRows . ReadingsVal("Reports","SqlResult",0);
fhem("set telebot send $receiver $msg ");
}


Lasse ich dagegen die Zeile "fhem("set Reports sqlCmd ..." weg, dann werden wie erwartet angegebenen Readings abgeholt.
D.h. für mich, dass ich für dieses Szenario mein "Reports"-Device so anlegen muss, dass es in regelmäßigen Abständen seine Abfrage macht um eine Information zu liefern falls irgendwann mal danach gefragt wird.

Deshalb die neue Frage: Gibt es einen Weg um etwas schneller und dynamischer auf meine Log-Datenbank zuzugreifen?

IntelNUC
-Fhem 5.8 in Ubuntu 16.04-Container
-dbLog & configDB auf Postgres-DB

Darrol

Okay, meine Frage ist zwar nach wie vor unbeantwortet allerdings konnte ich mir mittlerweile eine brauchbare Lösung zusammenschustern. Evtl. ist das auch ein bischen zu weit greifend für die Anfängerfragen.

Voraussetzung: configDB und DbLog sind in der selben Datenbank platziert

Es gibt nach wie vor das notify, welches Input von vom Telegrambot verarbeitet. aber statt zu versuchen die ausgabe direkt zu machen wird zunächst bloß eine
Datenbankabfrage über mein DbRep-Device verschickt.

telebot:msgText.* {
my $msgFrom = ReadingsVal("telebot","msgPeer",0);
my $receiver = "@@" . $msgFrom . AttrVal("telebot","peerSuffix",0);#peerSuffix ist ein userAttribut
my $teleCmd = "send"; #Fuer Plots auf cmdSend umschreiben
my $msg = "Ich habe keine Ahnung was du von mir willst."; #Standardantwort
     
        if ($EVTPART1 eq 'Status'){
if ($EVENT =~ 'Fenster'){
fhem("set Reports sqlCmd SELECT uebersicht FROM fhem.fenster_view");
$msg = "Ich schau mal nach";
}
}
 
fhem("set telebot $teleCmd $receiver $msg ");
}


Wie zu sehen ist, ist die Query durch den Einsatz einer View etwas kompakter geworden.
Die View(MySQL) ist folgendermaßen aufgesetzt:

CREATE
VIEW `fenster_view` AS
    SELECT
        CONCAT(`room`.`P2`,
                ' - ',
                `fc`.`P2`,
                ' ist ',
                (CASE `cur`.`VALUE`
                    WHEN 'closed' THEN 'geschlossen'
                    ELSE 'offen'
                END)) AS `Uebersicht`,
        MAX(`fc`.`VERSION`) AS `configversion`
    FROM
        (((`current` `cur`
        JOIN `fhemconfig` `fc` ON ((`fc`.`DEVICE` = `cur`.`DEVICE`)))
        JOIN `fhemconfig` `model` ON ((`model`.`DEVICE` = `fc`.`DEVICE`)))
        JOIN `fhemconfig` `room` ON ((`room`.`DEVICE` = `model`.`DEVICE`)))
    WHERE
        ((`fc`.`COMMAND` = 'attr')
            AND (`fc`.`P1` = 'alias')
            AND (`model`.`COMMAND` = 'attr')
            AND (`model`.`P1` = 'model')
            AND (`model`.`P2` = 'HM-SEC-SCo')
            AND (`room`.`COMMAND` = 'attr')
            AND (`room`.`P1` = 'room'))

Ausschlaggebend ist die drittletzte Zeile, hier wird die Ausgabe auf alle meine Fensterkontakte festgenagelt.

Sobald das Ergebnis der Abfrage eingeht, wird das Ergebnis von einem weiteren Notify abgefangen und an meinen Telegramaccount verschickt.

defmod telebotDbQuery notify Reports:SqlResult.* {\
my $msgFrom = ReadingsVal("telebot","msgPeer",0);;\
my $receiver = "@@" . $msgFrom . AttrVal("telebot","peerSuffix",0);;\
my $teleCmd = "send";;\
my $msg = "Ich habe keine Ahnung was du von mir willst.";;\
$msg = ReadingsVal("Reports","SqlResult",0);;\
fhem("set telebot $teleCmd $receiver $msg");;\
}


Ich hatte damit zunächst arge Performanceprobleme, da die Datenbank teilweise >300s  zum verarbeiten der Query gebraucht hat.
Die konnte ich aber zuletzt beheben indem ich meine fhemconfig-Tabelle entrümpelt habe:
configdb attr maxversions 5
und anschließend
configdb reorg 5

Die Query braucht nun auf meinem Cubietruck knapp eine Sekunde bis die Antwort kommt

IntelNUC
-Fhem 5.8 in Ubuntu 16.04-Container
-dbLog & configDB auf Postgres-DB

DS_Starter

Hallo d.mrugalla,

ich habe mir deinen Code jetzt nicht im Einzelnen angeschaut, aber ich wollte dir einen Tipp bezüglich DbRep geben.

Die Sache mit:
ZitatAllerdings kann das Ergebnis einer solchen DB-Abfrage nicht innerhalb eines Notify-Events verarbeitet werden.

ist dadurch bedingt, dass DbRep grundsätzlich asynchron (nicht blockierend) arbeitet. Deswegen ist nach Absetzen eines Befehles das Ergebnis u.U. noch nicht vorhanden. Dein Code läuft allerdings weiter und holt sich falsche/nicht vorhandene Daten.

Um solche "Synchronprobleme" recht einfach lösen zu können, hat das DbRep-Device ein Attribut / Schnittstelle "userExitFn" zur Verfügung. Diese Schnittstelle wird immer (mit jedem erzeugten Reading) aufgerufen wenn DbRep seine FUnktion ausgeführt hat.

Ein recht anschauliches Beispiel für die Arbeitsweise findest du im Wiki unter: https://wiki.fhem.de/wiki/DbRep_-_Reporting_und_Management_von_DbLog-Datenbankinhalten#finden_von_alten_Devicenamen_in_der_DB_und_versenden.2Floggen_einer_Negativliste

Vielleicht es dir dein Anliegen zu vereinfachen.

Grüße
Heiko
Proxmox+Debian+MariaDB, PV: SMA, Victron MPII+Pylontech+CerboGX
Maintainer: SSCam, SSChatBot, SSCal, SSFile, DbLog/DbRep, Log2Syslog, SolarForecast,Watches, Dashboard, PylonLowVoltage
Kaffeekasse: https://www.paypal.me/HMaaz
Contrib: https://svn.fhem.de/trac/browser/trunk/fhem/contrib/DS_Starter

Darrol

Zitat von: DS_Starter am 24 Juli 2017, 21:46:39
Hallo d.mrugalla,

ich habe mir deinen Code jetzt nicht im Einzelnen angeschaut, aber ich wollte dir einen Tipp bezüglich DbRep geben.

Die Sache mit:
ist dadurch bedingt, dass DbRep grundsätzlich asynchron (nicht blockierend) arbeitet. Deswegen ist nach Absetzen eines Befehles das Ergebnis u.U. noch nicht vorhanden. Dein Code läuft allerdings weiter und holt sich falsche/nicht vorhandene Daten.

Um solche "Synchronprobleme" recht einfach lösen zu können, hat das DbRep-Device ein Attribut / Schnittstelle "userExitFn" zur Verfügung. Diese Schnittstelle wird immer (mit jedem erzeugten Reading) aufgerufen wenn DbRep seine FUnktion ausgeführt hat.

Ein recht anschauliches Beispiel für die Arbeitsweise findest du im Wiki unter: https://wiki.fhem.de/wiki/DbRep_-_Reporting_und_Management_von_DbLog-Datenbankinhalten#finden_von_alten_Devicenamen_in_der_DB_und_versenden.2Floggen_einer_Negativliste

Vielleicht es dir dein Anliegen zu vereinfachen.

Grüße
Heiko
Super, das klingt doch schon mal sehr nach der Funktionalität, die ich gesucht habe.
Das werde ich mir später mal genauer ansehen.
Vielen Dank

Gesendet von meinem YD201 mit Tapatalk

IntelNUC
-Fhem 5.8 in Ubuntu 16.04-Container
-dbLog & configDB auf Postgres-DB

aisberg

Gibt es eine einfachere Möglichkeit, den Status meiner Lampen und Steckdosen auszulesen und an Telegram zu schicken? Also ohne eine Abfrage auf ein DbRep-Device? Mir würde ja die Information reichen, die auch im Web in meinem Raum "licht" angezeigt wird. Also so was wie:
licht_DG1 an
licht_DG2 aus
...


Um im Beispiel hier im Thema zu bleiben:
$MEIN_STATUSREPORT soll letztendlich einen Text enthalten, mit Zeilenumbrüchen. Die Liste der angezeigten Objekte kann gerne dynamisch aus dem Raum kommen, ich hätte aber auch kein Problem, eine statische Liste zu bilden in der Art
NameObjekt01 StatusObjekt01\r\n
NameObjekt02 StatusObjekt02\r\n
...


Vieleicht ist das irgendwas mit ReadingsVal, oder mit getstate, aber da fangen die Fragen bei mir schon an. Und wenn man nicht täglich mit FHEM arbeitet (und ich habe das vor 2 Jahren eingerichtet, es läuft stabil, und ich habe seitdem nichts wesentliches geändert), dann braucht man für solche "Kleinigkeiten" wieder eine Menge Zeit zum ausprobieren. Ich weiß auch nicht, wie ich mal einfach die Ausgabe eines Kommandos über die Eingabe der "Kommandozeile" teste

displayattr licht_DG1
das funktioniert rein formal (ich kann es in der Kommandozeile eingeben), allerdings gibt es ja kein Attribut mit dem Status, also kann ich den Status nicht aus einem Attribut auslesen

ReadingsVal("licht_DG1","STATE","?")
Kann oder muss ich das irgendwie verwenden?

Irgendwo in der Wiki habe ich so was gefunden:
define Mail_Aussentemperatur notify Aussentemperatur {\
my ($val);;\
$val = fhem "getstate $NAME";;\
system("wmail \"$NAME: $val\"");;\
}


Ist das der richtige Weg?