Hilfe Daten in mariaDB nonblocking schreiben

Begonnen von TimoD, 19 November 2024, 10:25:39

Vorheriges Thema - Nächstes Thema

TimoD

Hilfe, ich bekomme es nicht hin meine MariaDB (auf einem zweiten Raspberry) ohne dass ich mir mein fhem mit blocking blocke zu verwenden. Leider fehlt mir hier die Kenntnis und ich hoffe Ihr könnt mir weiterhelfen :-)

Zu meinem Setup:

Ich habe ein logdb:   
MODE       asynchronous
   MODEL      MYSQL
   NAME       logdb

Ein LogDB Client:
MODEL Client
NAME LogDBRep_TeslaPW_SQL

Und Aufruf die ich im Device mache, wenn neue Daten verfügbar sind z.B.
CodeAuswählen Erweitern
current_hour_home_consumption:aggregates-load-energy_imported.* {
    # 1. Aktuellen Wert von aggregates-load-energy_imported abrufen
    my $current_value = ReadingsVal("TeslaPW", "aggregates-load-energy_imported", 0);
    my $current_timestamp = ReadingsVal("TeslaPW", "current_hour_timestamp", "");

    # 2. Wert der letzten Stunde aus der Datenbank abrufen
    my $last_hour_value = ::CommandGet(undef, "LogDBRep_TeslaPW_SQL sqlCmdBlocking
        SELECT VALUE FROM history
        WHERE DEVICE='TeslaPW'
        AND READING='aggregates-load-energy_imported'
        AND TIMESTAMP = DATE_SUB('$current_timestamp', INTERVAL 1 HOUR)
        LIMIT 1;");

   # 3. Stündlichen Hausverbrauch berechnen und runden, nur wenn ein gültiger last_hour_value vorhanden ist
   my $hourly_home_consumption = ($last_hour_value ne "" && $last_hour_value =~ /^\d+(\.\d+)?$/)
       ? int($current_value - $last_hour_value)
       : 0;

    # 4. Wert in die Datenbank schreiben
    ::CommandGet(undef, "LogDBRep_TeslaPW_SQL sqlCmdBlocking
        INSERT INTO history (TIMESTAMP, DEVICE, TYPE, READING, VALUE, UNIT)
        VALUES ('$current_timestamp', 'TeslaPW', 'state', 'hourly_home_consumption', '$hourly_home_consumption', 'wh')
        ON DUPLICATE KEY UPDATE VALUE='$hourly_home_consumption';");

    # 5. Aktuellen Wert von aggregates-load-energy_imported in die Datenbank schreiben (ohne Duplikate)
    ::CommandGet(undef, "LogDBRep_TeslaPW_SQL sqlCmdBlocking
        INSERT INTO history (TIMESTAMP, DEVICE, TYPE, READING, VALUE, UNIT)
        VALUES ('$current_timestamp', 'TeslaPW', 'state', 'aggregates-load-energy_imported', '$current_value', 'w')
        ON DUPLICATE KEY UPDATE VALUE='$current_value';");

    return $hourly_home_consumption;
},

Nun habe ich das Problem, dass fhem während des Eintrags blockiert. Wie muss ich denn den Eintrag in die Datenbank umbauen, dass ich auf meine Daten zugriff habe, ohne das fhem blockiert? Sorry, habe keine Info dazu gefunden, die mir weiter geholfen hat. (Die aktuelle Implementierung besteht hautsächlich aus Copy and Paste und bin überhaupt froh, dass sie funktioniert.

Vorab vielen Lieben DANK!!

Grüße Timo

betateilchen

Dein Code ist ohne code-Tags nahezu unlesbar, deshalb habe ich mich jetzt nicht weiter damit auseinandergesetzt. Außerdem steht Deine Frage im falschen Unterforum (zu DbLog bzw. DbRep)

Aber einzelne Werte aus dem DbLog zu lesen, geht auch einfacher und ohne eigene SQL Kommandos benutzen zu müssen. Genauso gibt es vorgefertigte Befehle, um auch wieder Daten von DbLog selbst in die Datenbank schreiben zu lassen.

Vielleicht nochmal die commandref zu den beiden benutzten Modulen lesen?

-----------------------
Formuliere die Aufgabe möglichst einfach und
setze die Lösung richtig um - dann wird es auch funktionieren.
-----------------------
Lesen gefährdet die Unwissenheit!

TimoD

Ich hatte es erst in einem anderen Unterforum, weswegen es die Formatierung zerschossen hat. Leider hat mir die commandref mit meinem wenigen Wissen nicht geholfen. Hier nochmal formatiert und schon mal vielen Dank:

Insert bisher blocking:

total_grid_consumption_year:aggregates-battery-instant_average_current.* {
## Berechnung des Tageswertes
::CommandGet(undef, "LogDBRep_TeslaPW_SQL sqlCmdBlocking
           SELECT CAST(SUM(VALUE) AS DECIMAL(8,2)) AS VALUE
           FROM history
           WHERE DEVICE='TeslaPW'
             AND READING='hourly_grid_consumption'
             AND YEAR(TIMESTAMP) = YEAR(curdate()) ;") ;
},

bzw.
total_cost_day:aggregates-battery-instant_average_current.* {
## Berechnung des Tageswertes
::CommandGet(undef, "LogDBRep_TeslaPW_SQL sqlCmdBlocking
           SELECT CAST(SUM(VALUE) AS DECIMAL(8,2)) AS VALUE
           FROM history
           WHERE DEVICE='TeslaPW'
             AND READING='hourly_grid_cost'
             AND DAY(TIMESTAMP) = DAY(curdate())
             AND MONTH(TIMESTAMP) = MONTH(curdate())
             AND YEAR(TIMESTAMP) = YEAR(curdate()) ;") ;
},

oder
current_hour_grid_cost:aggregates-site-energy_imported.* {
  # 1. Aktuellen Wert von hourly_grid_consumption abrufen
  my $hourly_grid_consumption = ReadingsVal("TeslaPW", "current_hour_grid_consumption", 0);

  # 2. Aktuellen Strompreis abrufen
  my $current_price = ReadingsVal("TeslaPW", "current_cost", 0);

  # 3. Stündliche Kosten berechnen
  my $hourly_grid_cost = sprintf("%.4f", $hourly_grid_consumption / 1000 * $current_price);

  # 4. Aktuellen Zeitstempel abrufen
  my $current_timestamp = ReadingsVal("TeslaPW", "current_hour_timestamp", "");

  # 5. Wert in die Datenbank schreiben
  ::CommandGet(undef, "LogDBRep_TeslaPW_SQL sqlCmdBlocking
    INSERT INTO history (TIMESTAMP, DEVICE, TYPE, READING, VALUE, UNIT)
    VALUES ('$current_timestamp', 'TeslaPW', 'state', 'hourly_grid_cost', '$hourly_grid_cost', '€')
    ON DUPLICATE KEY UPDATE VALUE='$hourly_grid_cost';");

  return $hourly_grid_cost;
},

Als Device habe ich logdb bzw. ein Logdb_device LogDBRep_TeslaPW_SQL

TimoD

Irgendjemand einen Tipp, oder ein Beispiel bei dem ich mich einarbeiten kann? Wäre echt sehr dankbar.

TimoD

Bin nun soweit, dass ich:

defmod TotalGridConsumptionDay DbRep logdb
attr TotalGridConsumptionDay alias Tagesverbrauch Netz
attr TotalGridConsumptionDay device TeslaPW
attr TotalGridConsumptionDay reading hourly_grid_consumption
attr TotalGridConsumptionDay timestamp_begin current_day_begin

setstate TotalGridConsumptionDay done
setstate TotalGridConsumptionDay 2024-11-20 11:44:52 .associatedWith TeslaPW
setstate TotalGridConsumptionDay 2024-11-20 13:03:14 2024-11-20__TeslaPW__hourly_grid_consumption__SUM__no_aggregation 12070.0000
setstate TotalGridConsumptionDay 2024-11-20 13:03:14 state done


die Daten über ein DbRep Device direkt auslesen kann. Nun verstehe ich aber noch nicht,

1. wie ich mehrere meiner Datenbankoperationen ausführen kann (z.B. Avg Tag / Monat / Jahr) muss ich hier für jedes ein eigenes DbRep anlegen oder die attr. zur Laufzeit ändern.
2. Verwende ich das DbRep zur Speicherung / Darstellung meiner Daten oder sollte ich Dummy Device anlegen? (Ich bekomme die Daten ja nicht als readings in mein TeslaPW Device !?)
3. Wenn ich DbRep zur Anzeige meiner Daten verwende, wie kann ich die Namen anpassen: "2024-11-20__TeslaPW__hourly_grid_consumption__SUM__no_aggregation"
4. Zusätzlich möchte ich nicht nur Daten summieren / anzeigen sondern auch berechnen und wieder in die Datenbank zurückschreiben:
current_hour_grid_supply:0_update.* {
    # 1. Aktuellen Wert von aggregates-site-energy_exported abrufen
    my $current_value = ReadingsVal("TeslaPW", "aggregates-site-energy_exported", 0);
    my $current_timestamp = ReadingsVal("TeslaPW", "current_hour_timestamp", "");

    # 2. Wert der letzten Stunde aus der Datenbank abrufen
    my $last_hour_value = ::CommandGet(undef, "LogDBRep_TeslaPW_SQL sqlCmdBlocking
        SELECT VALUE FROM history
        WHERE DEVICE='TeslaPW'
        AND READING='aggregates-site-energy_exported'
        AND TIMESTAMP = DATE_SUB('$current_timestamp', INTERVAL 1 HOUR)
        LIMIT 1;");

# 3. Stündlichen Hausverbrauch berechnen und runden, nur wenn ein gültiger last_hour_value vorhanden ist
my $hourly_grid_supply = ($last_hour_value ne "" && $last_hour_value =~ /^\d+(\.\d+)?$/)
    ? int($current_value - $last_hour_value)
    : 0;

    # 4. Wert in die Datenbank schreiben
    ::CommandGet(undef, "LogDBRep_TeslaPW_SQL sqlCmdBlocking
        INSERT INTO history (TIMESTAMP, DEVICE, TYPE, READING, VALUE, UNIT)
        VALUES ('$current_timestamp', 'TeslaPW', 'state', 'hourly_grid_supply', '$hourly_grid_supply', 'wh')
        ON DUPLICATE KEY UPDATE VALUE='$hourly_grid_supply';");

    # 5. Aktuellen Wert von aggregates-site-energy_exported in die Datenbank schreiben (ohne Duplikate)
    ::CommandGet(undef, "LogDBRep_TeslaPW_SQL sqlCmdBlocking
        INSERT INTO history (TIMESTAMP, DEVICE, TYPE, READING, VALUE, UNIT)
        VALUES ('$current_timestamp', 'TeslaPW', 'state', 'aggregates-site-energy_exported', '$current_value', 'w')
        ON DUPLICATE KEY UPDATE VALUE='$current_value';");

    return $hourly_grid_supply;
},
muss / kann ich dies über usErexitFn machen (Woher kommen hier die Daten also SELECT), bzw schreibe ich hier die komplette Funktion? (Falls ja, wie führe ich diese dann aus?) Oder bin ich komplett auf dem Holzweg?

Weiter komme ich gerade irgendwie nicht,...
Grüße Timo