dblog - falscher Returnwert in userCommandResult

Begonnen von pwlr, 22 Oktober 2018, 11:28:15

Vorheriges Thema - Nächstes Thema

pwlr

Moin,
ich bekomme seit einiger Zeit nach einem set dblog userCommand falsche Infos in userCommandResult. Der Command selbst wird einwandfrei ausgeführt. Aufgefallen ist es mir bei "insert into..." und "delete from..." Befehlen.

Hier mal das list von meinem logdb - Befehl und Result sind dort zu sehen:

Internals:
   COLUMNS    field length used for Device: 64, Type: 64, Event: 512, Reading: 64, Value: 128, Unit: 32
   CONFIGURATION ./db.conf
   DEF        ./db.conf .*:.*
   MODE       synchronous
   MODEL      MYSQL
   NAME       logdb
   NR         44
   NTFY_ORDER 50-logdb
   PID        10999
   REGEXP     .*:.*
   STATE      connected
   TYPE       DbLog
   UTF8       0
   VERSION    3.12.5
   dbconn     mysql:database=fhem;host=localhost;port=3306
   dbuser     pi
   HELPER:
     COLSET     1
     DEVICECOL  64
     EVENTCOL   512
     OLDSTATE   connected
     READINGCOL 64
     TYPECOL    64
     UNITCOL    32
     VALUECOL   128
   READINGS:
     2018-10-22 03:00:00   countCurrent    51
     2018-10-22 03:00:00   countHistory    49200
     2018-05-03 22:52:33   lastRowsDeleted 65913
     2018-10-22 10:58:05   state           connected
     2018-10-22 10:58:05   userCommand     insert into history (DEVICE, TYPE, EVENT, READING, VALUE, UNIT)
values ('bmw_mqtt_0001', 'MQTT_DEVICE', 'definition', 'DEF', 'leer', 'leer')
     2018-10-22 10:58:05   userCommandResult DBD::mysql::db selectrow_array failed: fetch() without execute() at ./FHEM/93_DbLog.pm line 865.

   cache:
     index      0
Attributes:
   DbLogSelectionMode Include
   DbLogType  Current/History
   comment    MySql - Datenbank Nutzung: Zur Sicherung von einzelnen Device- oder Zustandswerten
   devStateIcon connected:general_ok .*:message_attention@red
   event-on-change-reading countHistory
   event-on-update-reading state,userCommandResult,userCommand
   group      MySQL
   room       -System
   suppressAddLogV3 0
   verbose    3


Habt ihr ne Idee was falsch sein könnte ?

Moin und schon mal vielen Dank für Eure Hilfe !
Bernd


DS_Starter

Hallo Bernd,

du machst nichts falsch. Der Aufbau des userCommand im DbLog ist sehr einfach aufgebaut.
Bei Selects würde der ermittelte Wert zurück geliefert werden.
Verwende für deine Aufgabe besser das sqlCmd im DbRep. Das ist mehr ausgebaut und non-blocking.

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

pwlr

Moin Heiko,

danke für Deine Hilfe !! - wie immer: schnell und kompetent  :)

Ich habe DbRep installiert und musste mich etwas einlesen und testen. Das ist ja wirklich ein mächtiges Modul.
Funktioiert alles  -  set <name> sqlCmd
insert into history (DEVICE, TYPE, EVENT, READING, VALUE, UNIT) values ('bmw_mqtt_0001', 'MQTT_DEVICE', 'definition', 'DEF', 'DbRep', 'hallo'

select MAX(TIMESTAMP) from history where device='bmw_mqtt_0001' and READING='DEF';

delete from history where device = 'bmw_mqtt_0001' and UNIT = 'hallo';

update history set UNIT='neu' where DEVICE='bmw_mqtt_0001' and TIMESTAMP = '2018-10-22 13:35:02';



Jetzt habe ich nur noch das Problem mit den Return-Werten, da die Befehle ja non-blocking ablaufen. Ich muss irgenwie auf die Return-Werte warten, ohne das ganze fhem lahm zu legen bzw. kurz per delay zu blockieren.

DANKE und moin
Bernd

DS_Starter

#3
Moin Bernd,

danke und freut mich dass du nun dein Ziel erreichen kannst.  :D
Ja, ich gebe zu dass DbRep anfangs etwas gewöhnungsbedürftig ist. Aber es ist eben ein Datenbank-Frontend was
etwas anders als herkömmliche Module funktioniert.

Zitat
Jetzt habe ich nur noch das Problem mit den Return-Werten, da die Befehle ja non-blocking ablaufen. Ich muss irgenwie auf die Return-Werte warten, ohne das ganze fhem lahm zu legen bzw. kurz per delay zu blockieren.

Blockieren ist nicht nötig bzw. macht die non-blocking Vorteile ja zunichte. Um die Returnwerte in die eigenen Abläufe sequentiell einzubinden gibt es eine spezielle Schnittstelle die man mit dem Attribut "userExitFn" aktiviert.
Jetzt weiß ich nicht inwieweit du in der Perl-Programmierung drin steckst, aber wenn du mir genauer erläuterst wie du die Return-Werte weiter verarbeiten willst, können wir das ja mal zusammen machen und daraus eventuell gleich einen Wiki-Eintrag erstellen.
Nur heute Abend nicht mehr  ;)

EDIT: Der Vollständigkeit halber ... es gibt noch das Kommando "get ... dbValue" welches es erlaubt wie sqlCmd benutzerspezifische SQL's abzuarbeiten, aber grundsätzlich blockierend arbeitet. Du kannst also wählen was für deinen speziellen Anwendungsfall die beste Möglichkeit ist.

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

pwlr

#4
Moin Heiko,

tja, also grundsätzlich möchte ich die Datenbank völlig unabhängig von irgentwelchen Devices oder Readings etc. in meiner 99_Utils nutzen. Ich denke, dass bei der hohen Flexibilität von fhem auch so ein flexibles, für individuelle Anforderungen nutzbares, DB-Tool ganz nützlich wäre und innovativ genutzt werden könnte.
Klar, entstanden sind DbLog und DbRep primär für das Logging und für Auswertungen.

Anstoss waren diese HM-LC-Bl1PBU-FM, die bei PowerOn beharrlich auf 50% stehen und sich die tatsächliche Lage der Jalousien angeblich nicht merken können und ggf. sogar noch Justierfahrten machen (da sollte eQ3 mal nachbessern). Wenn das nachts passiert gibt es Ärger mit der besten Ehefrau von allen  :'( und ich finde das auch nicht lustig.
Oder der Heizungshauptschalter, der nach Stromausfall auf off geht, weil er nix anderes kann und damit wird die Bude kalt.
Oder ein harter Crash von fhem (das Problem befindet sich ja meist vor der Tastatur) und beim Restart sind dann alle Einstellungen
(active | inactive) der notify, at, dummy und Co und auch alle OldreadingsVal weg.
And so on..

Jedenfalls habe ich mal mein Konzept für ein PowerOn Recovery auf die DB gestützt, um möglichst viele verschiedene Ausfälle für möglichst viele Device-Typen absichern zu können.
Ich glaube, dass die DB einen Crash besser überlebt... vielleicht irre ich mich, ist aber bisher meine Erfahrung.

Grober Ablauf:
1. bei den fraglichen Devices wir per dbLogInclude je nach Typ der aktuelle state, pct oder level gespeichert
2. das Reading powerOn eines beliebigen Devices ruft per notify eine sub in meiner 99_Utils auf
3. in der sub suche ich in der Db mit select MAX(TIMESTAMP) den Timestamp des letzten powerOn (könnte man auch aus dem Reading lesen...)
4. in der sub suche ich in der Db den vorletzten Wert pct mit  select VALUE from history where device='xxx' and READING='pct' and TIMESTAMP='...kleiner powerOn-time...';
5. dann in der sub: set device mit diesem vorletzten Wert für pct oder state oder was auch immer.
Dazu brauche ich natürlich jeweils direkt die Ergebnisse der Datenbankbefehle, zum Beispiel den Timestamp oder den Wert des Readings.

ZitatJetzt weiß ich nicht inwieweit du in der Perl-Programmierung drin steckst,

Meine Programmierkenntnisse stützen sich auf Kenntnisse aus längst vergangenen Zeiten.
Bin ein IT-Oldtimer :'( und damit ein Linux-Perl-Depp. Aber ich arbeite daran

ZitatDer Vollständigkeit halber ... es gibt noch das Kommando "get ... dbValue" welches es erlaubt wie sqlCmd benutzerspezifische SQL's abzuarbeiten, aber grundsätzlich blockierend arbeitet.
Ich habe jetzt viel getestet und das get dbValue scheint die Lösung zu sein !! Hier mal ein Auzug aus der Testroutine - geht super !
# MariaDB is the name of my DbRep-Device
#
# return_codes from CommandGet :
# operation  OK -> return_code = number of affected lines
# operation NOK -> return_code empty
#
$return_code = CommandGet(undef,"MariaDB dbValue insert into history (DEVICE, TYPE, EVENT, READING, VALUE, UNIT)
values ('$device', '$model', 'definition', 'DEF', 'Hugo', 'Emma')");
Log3 $name, 5, "$name $sub_name: insert = $return_code";

$return_code = CommandGet(undef,"MariaDB dbValue select VALUE from history where device='$device' and READING='DEF' LIMIT 1;");
Log3 $name, 5, "$name $sub_name: select value =  $return_code";

$return_code = CommandGet(undef,"MariaDB dbValue update history set UNIT='neu' where DEVICE='$device' and TIMESTAMP = '2018-10-23 23:18:37'");
Log3 $name, 5, "$name $sub_name: update =  $return_code";

$return_code = CommandGet(undef,"MariaDB dbValue delete from history where device = '$device' and UNIT = 'Emma'; ");
Log3 $name, 5, "$name $sub_name: delete =  $return_code";


Jetzt muss ich nur noch den alten Code umschreiben.

Schwachstelle ist im Konzept die Nummer 2, weil das Reading powerOn nicht zuverlässig gesetzt wird.

Danke für Deine Hilfe und Deine Anregungen !!!
Moin
Bernd



DS_Starter

Moin Bernd,

na das hört sich doch schon gut an  :)

Wenn ich morgen dazu komme und daran denke, gebe ich dir noch ein Beispiel wie man eine solche Verkettung mit dem non-blocking sqlCmd und einer 99_myUtils machen kann, also auch völlig unabhängig von anderen Devices.

Bin übrigens selbst auch so ein IT-Oldie und habe mir die Perl-Programmierung selbst beigebracht ;)
Lerne auch ständig immer wieder neu dazu.

LG,
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

DS_Starter

Hallo Bernd,

hier wie versprochen ein Beispiel einer Chain mit dem non-blocking setCmd.

Lege dir zunächst 4 identische DbRep-Devices an. Sie unterscheiden sich nur durch den Namen.
Einfach eins anlegen und dann nur noch kopieren (das DbLog-Device heißt im Beispiel "LogDB").
Die vier DbRep heißen:

Rep.insert, Rep.select, Rep.update, Rep.delete


define Rep.insert DbRep LogDB
attr Rep.insert allowDeletion 1
attr Rep.insert showproctime 1
attr Rep.insert userExitFn chain


In deine 99_myUtils fügst du dann diese Testroutine ein:


#############################################################################################
#  sqlCmd Commandchain zur sequentiellen Abarbeitung von non-blocking DbRep-Befehlen
#
#  genutzte werden vier DbRep-Devices:  Rep.insert, Rep.select, Rep.update, Rep.delete
#       
#  Start der Chain im FHEMWEB mit:  {chain("Rep.insert", "chainstart")}
#############################################################################################
sub chain {
my ($name,$reading,$value) = @_;
my $hash   = $defs{$name};
my $device = "Testdevice";
my $model  = "Testmodel";
my $rc;

if ($name eq "Rep.insert" && $reading eq "chainstart") {
     # Start der 1. Operation (insert)
     CommandSet(undef,"Rep.insert sqlCmd insert into history (DEVICE, TYPE, EVENT, READING, VALUE, UNIT)
   values (\"$device\", \"$model\", \"definition\", \"DEF\", \"Hugo\", \"Emma\")");
     Log3 $name, 1, "$name - Start chain with insert";
     return;   
}

if($reading eq "state" && $value eq "done") {
     if ($name eq "Rep.insert") {
         # Auswertung der 1. Operation (insert)
         $rc = ReadingsVal($name, "SqlResultRow_1", "");
         Log3 $name, 1, "$name - number of inserts: $rc";
         
         # Start der 2. Operation (select)
         CommandSet(undef,"Rep.select sqlCmd select VALUE from history where device=\"$device\" and READING=\"DEF\" LIMIT 1;");
     }
   
     if ($name eq "Rep.select") {
         # Auswertung der 2. Operation (select)
         $rc = ReadingsVal($name, "SqlResultRow_1", "");
         Log3 $name, 1, "$name - return of select: $rc";
         
         # Start der 3. Operation (update)
         CommandSet(undef,"Rep.update sqlCmd update history set UNIT=\"neu\" where DEVICE=\"$device\";");
     }
     
     if ($name eq "Rep.update") {
         # Auswertung der 3. Operation (update)
         $rc = ReadingsVal($name, "SqlResultRow_1", "");
         Log3 $name, 1, "$name - number of updates: $rc";
         
         # Start der 4. Operation (delete)
         CommandSet(undef,"Rep.delete sqlCmd delete from history where device = \"$device\" and UNIT = \"neu\";");
     }
     
     if ($name eq "Rep.delete") {
         # Auswertung der 4. Operation (delete)
         $rc = ReadingsVal($name, "SqlResultRow_1", "");
         Log3 $name, 1, "$name - number of deletes: $rc";
     } 
}

return;
}


Die ganze Kette wird einfach mit dem Befehl gestartet:


chain("Rep.insert", "chainstart")


bzw. in der Kommandozeile im FHEMWEB mit:


{chain("Rep.insert", "chainstart")}


Im Log siehst du dann die Ergebnisse der Abarbeitungskette:


2018.10.24 23:57:37.602 1: Rep.insert - Start chain with insert
2018.10.24 23:57:37.815 1: Rep.insert - number of inserts: 1
2018.10.24 23:57:37.901 1: Rep.select - return of select: Hugo
2018.10.24 23:57:38.033 1: Rep.update - number of updates: 1
2018.10.24 23:57:38.176 1: Rep.delete - number of deletes: 1


Dieser Aufbau hat den Vorteil, dass dein FHEM nicht negativ beeinflusst wird wenn deine Datenbank mal nicht so schnell reagiert, oder nicht verfügbar ist (zum Beispiel wegen laufenden Backup o.ä.).

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

pwlr

Moin Heiko,
ah, noch 'ne Nachteule   :)

Ich glaube, dass ich das Pinzip vertanden habe, very tricky Dein Ablauf !! Die sub nach einer DB-Anforderung beenden, über den userExitFn mit Ergebnis wieder neu starten und mit den if dann den richtigen Entrypoint in der sub ansteuern.

Werde ich in Ruhe durchdenken - heute nicht mehr, bin müde... Schade, hab die nächsten Tage viel auf dem Zettel und ich kann mich wohl erst in einigen Tagen wieder melden.

Nochmals Danke ! und moin
Bernd

DS_Starter

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