Hallo,
ich möchte gern folgendes Problem lösen: Viele Devices liefern ein Reading mit sowas wie "EnergyDay", also einen Wert, der ..zig Mal am Tag geliefert wird und immer den bisher am Tag verbrauchten Wert liefert. Man loggt die Werte in die Datenbank, braucht aber eigentlich nur den letzten des Tags. In diesem Beitrag (https://forum.fhem.de/index.php?topic=128605.0) wurde das Problem dadurch angegangen, dass nachträglich von den n Datensätzen n-1 wieder gelöscht werden. Das geht natürlich, erscheint mir aber wenig effektiv.
Ich hatte deshalb die Idee, mit DbLogValueFn den Zeitstempel der zu loggenden Datensätze immer auf die letzte Sekunde des aktuellen Tage zu "verbiegen" in der Hoffnung, dass jeweils der vorherige Datensatz am gleichen Zeitpunkt überschrieben wird und letztlich nur ein Datensatz pro Tag in der DB landet. Leider ist das nicht so. Ich habe genauso viele Datensätze wie vorher, nur alle um 23:59:59.
Deshalb meine Frage: Kann man DbLog irgendwie dazu bringen, statt einem Insert ein Update zu machen, wenn für ein bestimmtes $DEVICE und $READING an dem entsprechenden $TIMESTAMP schon ein Datensatz existiert?
Cool fände ich an so einer Lösung auch, dass man den aktuellen Wert des Tages auch bereits in einem Diagramm über z.B. den laufenden Monat ohne weiteren Aufwand mit darstellen könnte.
Gruß Jörg
Hallo Jörg,
das ist relativ einfach mit addLog im DbLog lösbar.
Du sorgst zunächst dafür, dass die relevanten Readings/Events nicht mehr automatisch geloggt werden indem du das DEF entsprechend anpasst.
Dann erstellst du dir ein at-Device welches einmal am Tag den DbLog Befehl:
set <name> addLog <devspec>:<Reading>
ausführt. In der Online-Hilfe findest du Beispiele.
LG,
Heiko
Hallo Heiko,
danke für Deine Antwort. Dein Vorschlag löst zwar das Problem der Datenflut, dafür habe ich die Information erst am Ende des Tages in der DB. Ich möchte aber, dass zu jeder Tageszeit der bis dahin aufgelaufene Energiebetrag verfügbar ist.
Die Datenbank habe ich auf DbSelectionMode = Include eingestellt und das zu loggende Reading am Zähler-Device HausVerbrauch mit DbLogInclude festgelegt. Nun würde ich als DbLogValueFn sowas wie
attr HausVerbrauch DbLogValueFn
{
if ($READING eq "FroPwrFlow_E_InsHaus_EnergyDay") {
# Ersetze die letzten 7 Zeichen durch '23:59:59'
$TIMESTAMP =~ s/\d{2}:\d{2}:\d{2}$/23:59:59/;
if ($TIMESTAMP eq $LASTTIMESTAMP) {
$IGNORE = 1; # INSERT unterdrücken,
#stattdessen (beispielhaft in SQL-Syntax)
UPDATE history
SET value = $VALUE
WHERE DEVICE = Hausverbrauch AND READING = $READING AND TIMESTAMP = $TIMESTAMP;
}
}
}
verwenden wollen. Ohne das innere "if" hatte ich es wie gesagt schon probiert, was aber nur dazu führte, dass alle Datensätze den Zeitstempel 23:59:59 bekamen. Ich habe nicht probiert, auf die history-Tabelle einen Primärschlüssel bestehend aus TIMESTAMP, DEVICE und READING zu setzen, weil das nach meinem Datenbankverständnis nur dazu geführt hätte, dass lediglich der erste Datensatz geschrieben worden wäre und alle weiteren wegen Schlüsselverletzung ignoriert worden wären. Ich will ja aber den letzten haben.
Wenn mein Ansatz funktionieren würde, könnte man damit genauso das tägliche (oder auch stündliche) Maximum, Minimum usw. eines Readings erzeugen, ohne vorher alle Datensätze des Tages in die DB schreiben zu müssen...
Man bräuchte also was analoges zu "addLog", was statt dem insert ein update macht, wobei ich nicht weiß, ob man set addLog überhaupt aus der DbLogValueFn heraus aufrufen dürfte.
Gruß Jörg
Inzwischen hatte ich die Idee, das Update über ein DbRep-Device auszuführen:
attr HausVerbrauch DbLogValueFn
{
if ($READING eq "FroPwrFlow_E_InsHaus_EnergyDay") {
# Ersetze die letzten 5 Zeichen durch '59:59'
$TIMESTAMP =~ s/\d{2}:\d{2}:\d{2}$/23:59:59/;
if ($TIMESTAMP eq $LASTTIMESTAMP) {
$IGNORE=1;
fhem("set myDbRep sqlCmd UPDATE history set VALUE='$VALUE' WHERE TIMESTAMP='$TIMESTAMP' AND DEVICE='PV_Verbrauch' AND READING='$READING'");
}
}
}Das funktioniert aber auch nicht. Ich erhalte wieder n Datensätze am Ende des aktuellen Tages. Sieht aus als ob der Timestamp-Vergleich nie true liefert.
Kann er auch nicht. Ein Log 1, "$TIMESTAMP $LASTTIMESTAMP" liefert 2025.10.28 20:30:00 1: 2025-10-28 20:59:59 1761678000.20679 Wie kriegt man das denn konvertiert?