Sensoren ändern weil Total != String1 + String2

Ich möchte gerne meine Sensoren umstellen und hätte gerne eure Meinung, vor allem von Zara.

Ich habe diese Sensoren:
DC Total aus Huawei

  • Vorteil: Zeigt an, sobald Solarstrahlung die Zellen erreicht
  • Nachteil: Ist nicht konsistent zu der Summe der beiden Strings
    DC Total Calculated vom Solarteure
  • Vorteil: ist konsistent zur Summe der beiden Strings (rechnet String1 + String2)
  • Nachteil: Zeigt erst später an, springt am Anfang von 0 auf ca. 200-300W, weil Strings erst ab 0.2A etwas anzeigen.

DC String 1 und 2 aus Huawei

  • Vorteil: zeigt die zur Verfügung stehende Leistung an
  • Nachteil: zeigt erst etwas an, wenn der Strom 0.2A überschreitet → Am Anfang ein Sprung auf ca. 100-150W

Was will ich erreichen?

  • SFML mit korrekten Sensoren bedienen, vor allem wegen Konsistenz von Total = string1 + String2
  • Schatten der beiden Strings beobachten können (Sommer Kamin bei String1; Winter Bäume bei String2)

Ich sehe zwei Lösungen:

  • den Total calculated mit String1/String2 zu benutzen
    bedeutet jedoch, das am Anfang/Ende immer ein Sprung entsteht und SFML fälschlicherweise die Sensoren als AC-Sensoren detektieren könnte.
  • Die Strings selber zu berechnen, das scheint mir die bessere Lösung zu sein.

Lösung zwei würde ich folgendermassen umsetzen:
Differenz = Total - String1 - String2 //gibt mir eine Abweichung von Total zu der Summe beider Strings zurück.
Dann die beiden Strings neu berechnen:
String1 = String1 + Differenz * 0,444 // Die Differenz zum String1 anteilig addieren (16 Module)
String2 = String2 + Differenz * 0,556 // Die Differenz zum String2 anteilig addieren (20 Module)

Vorteil dieser Lösung:

  • Schatten geht korrekt bei den beiden Strings mit ein
  • Total ist konsistent zu den beiden Strings
  • String1 und String2 steigen bereits am Anfang an langsam mit an.

Nachteil dieser Lösung:

  • eine kleine Ungenauigkeit in der wirklich erzeugten Solarleistung in Bezug auf dem Inverter (ca. <1%)

Da es hier jedoch um die Prognose geht und nicht die erzeugte Energie - was dann ja auch AC wäre - kann ICH den Nachteil gut verschmerzen.

Wie sieht es aber dann mit SFML aus? @Tom-HA , macht das Sinn? Kann meine jetzige Konfiguration für die Buckel mit ursächlich sein?

Zur Verdeutlichung ein Ausschnitt von heute morgen:


Bisher benutze ich die blaue Linie als Total und die orangene und Grüne für die Strings.
Neu würde ich die blaue beibehalten und die rosa und Lilane für die Strings benutzen.

Gruß Ralf

1 „Gefällt mir“

Hi @Tom-HA ,

den Fragen von @alteMade möchte ich mich anschließen.
Ich habe heute morgen das log nach warnings durchsucht.

custom_components.solar_forecast_ml.data.data_panel_group_sensor_reader - WARNING - Panel group learning disabled for this hour: group sum 0.600 kWh does not match DC yield 0.500 kWh. Please verify that all panel group sensors and the yield sensor measure the same DC energy basis in kWh, use the same time window, and do not overlap.

Solche Meldungen habe ich ab und an, insbesondere am frühen Morgen und am späten Abend.
Zwei Entitäten die ich verwende stammen direkt aus der Kostalintegration, nur der PV1+2täglich ist ein Verbrachszähler aus dem PV Total Zähler der Kostalintegration.
Allerdings stimmen die Zeitpunkte nicht überein. Die rote Linie müsste ja immer wenn blau oder gelb steigen, ebenfallls eine Treppenstufe bilden. Tut sie aber nicht.

Was ich auch nicht verstehe der Eintrag im log ist von 9:05 Uhr und führt 0.5 und 0.6 kWh auf. Die screenshots zeigen aber 0.6, 0.5 und 1.00

Kostal kann ich ja nicht intelligenter machen. Wäre es jetzt nicht besser statt dem PV1+2täglich einen template Sensor zu verwenden, erstellt aus der Summe von PV1 day + PV2 day?

Gruß Stefan

Hallo Ralf,

Kurz und knapp: Ja, das macht grundsätzlich Sinn!

Für SFML ist nicht der ganz frühe kleine Anstieg das Wichtigste, sondern dass die Werte sauber zueinander passen.
Also: Total und Strings müssen dieselbe Grundlage haben und zusammen stimmig sein, vor allem wenn es um String-Verhalten, Schatten und das Lernen der Gruppen geht.

Deshalb sehe ich deine Überlegung ähnlich wie du:

Die Variante mit DC Total Calculated plus den beiden Huawei-Strings ist zwar auf den ersten Blick sauber, hat aber den Nachteil, dass die Strings morgens und abends erst verspätet anspringen.
Damit verlierst du genau in der Phase etwas Information, die für die Beobachtung von Schatten und weichem Tagesbeginn eigentlich interessant ist. → SFML hat extre Berechnungen für Twilight-Stunden, die dann zickig werden könnte.

Daher ist die zweite Idee der bessere Ansatz:
Also die beiden Strings so zu korrigieren, dass sie zusammen sauber zum Total passen, aber trotzdem ihr jeweiliges Verhalten behalten.
Der Vorteil daran ist, dass SFML dann konsistente Werte bekommt und gleichzeitig die Unterschiede zwischen String 1 und String 2 sichtbar bleiben. Genau das ist für die Schattenbetrachtung wichtig und löst das Problem nachhaltig und ist das was Du möchtest.

Der kleine Nachteil mit der leichten rechnerischen Ungenauigkeit halte ich dabei für vertretbar. Wir reden hier nicht über eine geeichte Abrechnung, sondern über eine Prognose- und Lernbasis. Wenn du damit auf rund 1-2 Prozent Abweichung bleibst, ist das aus deutlich weniger problematisch als inkonsistente Sensoren.

Zu deiner Frage wegen der Buckel:
Ja, das kann durchaus ein Grund sein. Wenn Total und Strings nicht sauber zusammenpassen, ist das für SFML keine ideale Datengrundlage. Dann können unsaubere Effekte entstehen. Daher ist es plausibel, dass die aktuelle Konstellation dazu beiträgt. Ich hatte mir das ja schon mal angesehen, aber Probleme das zu reproduzieren.

Fazit

  • Wenn du bei SFML mit String-Sensoren arbeiten willst, ist Konsistenz wichtiger als der “perfekte originale” Einzelwert.
  • Für dein Ziel mit Schattenbeobachtung ist die zweite Lösung deutlich sinnvoller.
  • Die Strings künstlich so anzupassen, dass sie zusammen wieder sauber dem Total entsprechen, ist in diesem Fall aus meiner Sicht legitim, solange der Unterschied max 1-2% beträgt.-> Das ist aber ein Wert ins Blaue geraten!
  • Grundsätzlich: Iieber eine kleine, kontrollierte Rechenkorrektur als dauerhaft widersprüchliche Sensorwerte.

Wenn du es möglichst einfach halten willst, wäre meine Empfehlung also:
Nimm die Lösung, bei der String 1 und String 2 so korrigiert werden, dass die Summe wieder sauber zum Total passt und die String-Unterschiede trotzdem erhalten bleiben.

Ich bin sehr gespannt!!!

1 „Gefällt mir“

Hallo Stefan,
Ja das macht 100% Sinn. Die Abweichungen sind zwar Minimal, aber summieren sich natürlich in ein Muster auf. Entscheidet ist hier nicht der Wert selber, sondern die prozentuale Abweichung! Die ist gerade bei kleinen Werten enorm.
Diese Abweichungen kommen meistens von HA selbst (Rundungsfehler, Zeitmuster, Aktualisieungen, Delta, ..) im Kontext mit Werten aus der benutzen Integration selbst.
Dein Vorschlag den “Yield-Sensor” aus den beiden Gruppensensoren zu bilden ist eine saubere Lösung! würde für die von Dir beschriebene Stunde 10% der Fehler auf einen Schlag eleminieren!
→ Ich hatte das selbe Problem, als ich die orgiginalen Anker Sensoren genommen habe… katastrophe! Ich addiere mittels der HA eigenen SQL Integrationen die Gruppenwerte direkt aus der HA DB und im selben Atemzug erstelle ich daraus einen Riemann.. seit dem ist Ruhe. Weiterer Vorteil: Sensorausfälle und Co werden besser kompensiert.

Hier der SQL-Code.. den Du natürlich anpassen musst:

Riemann Gruppe 2 als Beispiel bei mir:

WITH riemann_calc AS (
  SELECT 
    CAST(state AS DECIMAL(10,2)) as watt,
    last_updated_ts,
    LEAD(last_updated_ts) OVER (ORDER BY last_updated_ts) as next_ts
  FROM states
  WHERE metadata_id = 53
    AND FROM_UNIXTIME(last_updated_ts) >= CURDATE()
    AND state NOT IN ('unknown', 'unavailable')
    AND state REGEXP '^[0-9]+(\\.[0-9]*)?$'
)
SELECT 
  ROUND(COALESCE(SUM(
    watt * 
    (COALESCE(next_ts, last_updated_ts + 300) - last_updated_ts) / 3600.0 / 1000.0
  ), 0), 2) as state
FROM riemann_calc
WHERE watt >= 0;

Das ergibt einen sauberen Riemann ohne Lücken und resistent..

1 „Gefällt mir“

ich hab auch eine huawei anlage und nur einen gesamt dc. darum berechne ich meine strings aus v und a der strings und addiere sie zu gesamt:

  - sensor:
      - name: PV-String Ost Watt
        unique_id: pv_string_ost_watt
        unit_of_measurement: W
        device_class: power
        state_class: measurement
        icon: mdi:solar-panel
        state: >
          {% set v  = states('sensor.wechselrichter_pv_1_spannung') | float(0) %}
          {% set a  = states('sensor.wechselrichter_pv_1_strom')    | float(0) %}
          {{ (a * v) | max | round(0) }}

        availability: "{{ true }}"

  - sensor:
      - name: PV-String West Watt
        unique_id: pv_string_west_watt
        unit_of_measurement: W
        device_class: power
        state_class: measurement
        icon: mdi:solar-panel
        state: >
          {% set v  = states('sensor.wechselrichter_pv_2_spannung') | float(0) %}
          {% set a  = states('sensor.wechselrichter_pv_2_strom')    | float(0) %}
          {{ (a * v) | max | round(0) }}

        availability: "{{ true }}"

  - sensor:
      - name: PV-Strings Gesamt Watt
        unique_id: pv_strings_gesamt_watt
        unit_of_measurement: W
        device_class: power
        state_class: measurement
        icon: mdi:solar-panel
        state: >
          {% set a  = states('sensor.pv_string_ost_watt') | float(0) %}
          {% set b  = states('sensor.pv_string_west_watt') | float(0) %}
          {{ (a + b) | max | round(0) }}

        availability: "{{ true }}" 
1 „Gefällt mir“

Das ist smart, so verhinderst Du, dass sie auseinander driften!! Clever!!!

Ich habe einfach die Sensoren der beiden Strings in einem template Sensor addiert.
Alle anderen Methoden sind mir zu schwierig :see_no_evil_monkey:

Ich glaube das geht.
{{ states('sensor.kostal_wechselrichter_energy_pv1_day') | float(0)
 + states('sensor.kostal_wechselrichter_energy_pv2_day') | float(0) }}
1 „Gefällt mir“

Klar, das ist eigentlich genau das Gleiche :slight_smile:

1 „Gefällt mir“

Ich glaube HA hat einfach Probleme mit Rechenoperationen. Heute morgen im log:

2026-05-21 06:05:00 - custom_components.solar_forecast_ml.data.data_panel_group_sensor_reader - INFO - Panel group daily sensor baseline reset for group 'Gruppe 1': previous baseline from 2026-05-20, current 0.0000 kWh stored as new baseline; no hourly delta learned
2026-05-21 06:05:00 - custom_components.solar_forecast_ml.data.data_panel_group_sensor_reader - INFO - Panel group daily sensor baseline reset for group 'Gruppe 2': previous baseline from 2026-05-20, current 0.0000 kWh stored as new baseline; no hourly delta learned
2026-05-21 06:05:00 - custom_components.solar_forecast_ml.data.data_panel_group_sensor_reader - WARNING - Panel group learning disabled: 0/2 panel groups produced a valid hourly kWh delta. Every panel group must provide a valid cumulative DC energy sensor in kWh.

Wenn ich mir die beiden folgenden screenshots anschaue sehe ich, dass HA den Gesamtwert 1+2 nicht addiert. Obwohl sich PV erhöht um 0,1 steigt PV gesamt nicht.
Keine Ahnung wieso, weshalb, warum

Gruß Stefan

Hallo Stefan,

das Verhalten ist leider ziemlich unschön: Das entspricht 100 % Fehler für diese Stunde. Das ist vermutlich kein reines SFML-Problem, sondern fällt dort nur besonders sichtbar auf. Für SFML bedeutet es dann sinngemäß: „Diese Stunde wird nicht sinnvoll betrachtet.“

Ich würde dir als Gegentest empfehlen, einen SQL-Sensor direkt auf die Home-Assistant-Recorder-Datenbank anzulegen. Das geht am einfachsten mit der HA-eigenen SQL-Integration.

Ein SQL-Riemann-Sensor, der aus einem DC-Leistungssensor die Tagesenergie berechnet und sich jeden Tag um lokaler Mitternacht wieder auf 0 setzt. Das ist sauber und funktioinert immer! Leider scheint es für, jemden der es noch nie gemacht hat etwas kompliziert, ist aber in wirklichkeit einfacher als die JinJa2 Template-Krempel sache. Zumal auch Sensoren mit Startwerten, Vergleichen,… ect super einfach erstellen kann. In diesem Fall aber ein Rieman der sich um 24:00 Uhr zurücksetzt. Simpel und einfach ohne das man x Helfer und Gedöns erstellen muss.

Schritte

  1. DB-Zugriff über die SQL-Integration nutzen
  2. metadata_id des Quellsensors ermitteln
  3. SQL-Sensor über metadata_id erstellen
  4. Sensorwert täglich ab lokaler Mitternacht berechnen

1. DB-Zugriff

Die Home-Assistant-SQL-Integration nutzt automatisch die Recorder-Datenbank, wenn das Feld Database URL leer bleibt. Bei einer normalen SQLite-Installation liegt diese DB typischerweise unter:

/config/home-assistant_v2.db

Home Assistant speichert die Entity-Zuordnung in der Tabelle:

states_meta

Die eigentlichen Zustände liegen in:

states

Die Verknüpfung erfolgt über:

metadata_id

2. metadata_id des DC-Sensors ermitteln

In Home Assistant:

Entwicklerwerkzeuge → Aktionen → sql.query

Dort folgende Query ausführen:

SELECT
  metadata_id,
  entity_id
FROM states_meta
WHERE entity_id = 'DEIN_GRUPPEN_ODER_GESAMT_SENSOR_VOM_WR_DIREKT';

Beispiel:

SELECT
  metadata_id,
  entity_id
FROM states_meta
WHERE entity_id = 'sensor.wr_dc_power_total';

Das Ergebnis sieht z. B. so aus:

metadata_id: 1234
entity_id: sensor.wr_dc_power_total

Die Zahl 1234 wird anschließend in der Riemann-Query eingesetzt.


3. SQL-Sensor in der HA-SQL-Integration einrichten

Einstellungen → Geräte & Dienste → Integration hinzufügen → SQL

Dann einen neuen SQL-Sensor erstellen.

Felder:

Name:
WR DC Energie Heute SQL
Database URL:
leer lassen

Wichtig:
Das funktioniert so für die Standard-SQLite-Datenbank von Home Assistant. Bei MariaDB muss die Query angepasst werden, weil MariaDB kein strftime(...) kennt.

Als Query folgenden Code verwenden und 1234 durch die echte metadata_id ersetzen:

WITH params AS (
  SELECT
    CAST(strftime('%s', datetime('now', 'localtime', 'start of day', 'utc')) AS REAL) AS start_ts,
    CAST(strftime('%s', 'now') AS REAL) AS now_ts
),

midnight_state AS (
  SELECT
    params.start_ts AS ts,
    CAST(states.state AS REAL) AS watts
  FROM states
  CROSS JOIN params
  WHERE states.metadata_id = 1234
    AND states.last_updated_ts < params.start_ts
    AND states.state NOT IN ('unknown', 'unavailable', 'none')
  ORDER BY states.last_updated_ts DESC
  LIMIT 1
),

today_states AS (
  SELECT
    states.last_updated_ts AS ts,
    CAST(states.state AS REAL) AS watts
  FROM states
  CROSS JOIN params
  WHERE states.metadata_id = 1234
    AND states.last_updated_ts >= params.start_ts
    AND states.state NOT IN ('unknown', 'unavailable', 'none')
),

samples AS (
  SELECT ts, watts FROM midnight_state
  UNION ALL
  SELECT ts, watts FROM today_states
),

intervals AS (
  SELECT
    ts,
    watts,
    LEAD(ts) OVER (ORDER BY ts) AS next_ts
  FROM samples
)

SELECT
  ROUND(
    COALESCE(
      SUM(
        watts * (
          COALESCE(next_ts, (SELECT now_ts FROM params)) - ts
        )
      ) / 3600000.0,
      0
    ),
    4
  ) AS kwh_today
FROM intervals;

Danach in der SQL-Integration eintragen:

Column:
kwh_today
Unit of measurement:
kWh
Device class:
energy
State class:
total

Wichtig:
Nicht total_increasing, weil sich der Sensor jeden Tag um Mitternacht wieder auf 0 zurücksetzt.


4. Ergebnis

Der Sensor berechnet dann die Energie seit lokaler Mitternacht aus dem Leistungssensor.

Wenn der Quellsensor in Watt liefert, ist diese Umrechnung korrekt:

W × Sekunden / 3.600.000 = kWh

Deshalb steht in der Query:

/ 3600000.0

Falls der Quellsensor bereits in kW liefert, müsste die Division stattdessen lauten:

/ 3600.0

Fertig.

1 „Gefällt mir“

Danke Tom,
leider reicht mein knowhow nicht für SQL, ich wüßte nicht einmal, welches Datenbankfeld ich abfragen müsste. :see_no_evil_monkey:
Ich warte mal bis ich meinen jüngsten Sohn im Juni wiedersehe.Informatiker.
Beste Grüße Stefan

Gerade Deine Antwort komplett gelesen, werde es mal versuchen!

@nightrunner Du warst schneller :slight_smile: Ich habe Dir eine Schrit für Schritt Anleitung gebaut… gern hier auch noch mal in Screenshots:

Glaube mir.. das ist deutlich einfacher als dieser Template und Yaml Kram… :wink: und hat x-vorteile! Du kannst alle mögichen " Abfragen, Berechnungen, … " super easy erstellern (oder mit einer KI deiner Wahl den Text erzeugen lassen…)

Ich empfehle es jeden lieber Sensoren auf diese Art und Weise zu erstellen als mit dem Template oder Yaml Zeug… :wink:

Beim Template oder Yaml-Zeug muss man aber nicht alle Sensoren überarbeiten wenn die Datenbank wechselt oder bei einem Update/Upgrade sich die Syntax von SQL ändert :slight_smile:

@nightrunner

Hier mal ein Beispiel:

Prompt (Grok) Webseite

Hey Grok.. erstelle mir einen SQL Abfrage für den Home Assistant. Es soll kein Yaml-Gefrickel sein, sondern die Home Assistant eigene Integration. Der Sensor soll den Unterschied zwischen 2 Sensoren (MetaID 54 und MetaID 55) pro Tag ausgeben. Es handelt sich um Watt Sensoren und es soll in Prozent angezeigt werden.

Ausgabe:

SELECT 
  ROUND(
    100.0 * (sum54 - sum55) / NULLIF(sum54, 0),
    1
  ) AS percent_diff
FROM (
  SELECT 
    COALESCE(SUM(CASE WHEN metadata_id = 54 THEN "sum" ELSE 0 END), 0) AS sum54,
    COALESCE(SUM(CASE WHEN metadata_id = 55 THEN "sum" ELSE 0 END), 0) AS sum55
  FROM statistics
  WHERE metadata_id IN (54, 55)
    AND start_ts >= strftime('%s', 'now', 'start of day')
);

Rest wie gehabt und fertig…

Genau das ist hier nicht der Punkt. Es geht nicht um einen Live-Zustand oder eine einfache Umrechnung, sondern darum, den Recorder direkt auszuwerten. Dafür ist SQL genau das passende Werkzeug.

Ja, bei einem Datenbankwechsel muss eine SQL-Abfrage angepasst werden, da HA neue ID`s vergibt. Aber ein DB-Wechsel ist ein bewusster technischer Eingriff und kein tägliches Ereignis. Der Fix ist super simpel: die “neue” MetaID eintragen und fertig

Auch will ich hier keine Grundsatz-Diskussion lostreten, da viele Wege nach Rom führen und das hier für ich der einfachste und sauberste ist um DC-Sensoren zu erstellen um die KI mit Lernsignalen zu ermöglichen.

Zumal man einen Sicherheitsmechanismus einbauen kann in dem man den Yield-Sensor einfach via SQL aus den Gruppen Sensoren erstellt.. das ist mathematisch sauber und umgeht jeden Rundungs- und Rechenfehler! Datenqualität ist nunmal bei einer KI das Wichtigste..

Auch reduziert es den Aufwand… bei 2 Gruppen sind es genau 3 Sensoren:

1x Gruppe 01
1x Gruppe 02
1x Yield

statt noch Helfer zu bauen.. auch ist es bei den Gruppensensoren nur copy / paste und anpassen der MetaID.. das schließt weitere Fehlerquellen aus

Man muß nicht unbedingt die ID raussuchen, man kann auch direkt in der SQL-Query eine Unterabfrage einbauen. Macht das vor allem für Menschen leichter, die nicht gut mit SQL klarkommen. Meine SQL-Sensoren für so etwas sehen immer gleich aus, ich tausche nur die SensorID aus:

WITH riemann_calc AS (
  SELECT 
    CAST(s.state AS REAL) AS watt,
    s.last_updated_ts,
    LEAD(s.last_updated_ts) OVER (ORDER BY s.last_updated_ts) AS next_ts
  FROM states s
  WHERE s.metadata_id = (
      SELECT sm.metadata_id
      FROM states_meta sm
      WHERE sm.entity_id = 'sensor.inverter_leistung_dc_total'
      LIMIT 1
  )
    AND datetime(s.last_updated_ts, 'unixepoch', 'localtime') >= date('now', 'localtime')
    AND s.state NOT IN ('unknown', 'unavailable')
    AND s.state GLOB '[0-9]*'
    AND s.state NOT GLOB '*[^0-9.]*'
    AND (s.state NOT LIKE '%.%.%')
)
SELECT 
  ROUND(COALESCE(SUM(
    watt * 
    (COALESCE(next_ts, last_updated_ts + 300) - last_updated_ts) / 3600.0 / 1000.0
  ), 0), 2) AS state
FROM riemann_calc
WHERE watt >= 0;

Wichtig ist, das man anstatt deiner 12345 diese Unterabfrage mit einbaut:

WHERE s.metadata_id = (
      SELECT sm.metadata_id
      FROM states_meta sm
      WHERE sm.entity_id = 'sensor.inverter_leistung_dc_total'
      LIMIT 1
  )

SensorID natürlich nach Bedarf austauschen. Das erzeugt auch nicht den riesigen Overheadf um darauf verzichten zu müssen, macht das Ganze aber lesbarer und auch für SQL-Anfänger einfacher zu benutzen.

Dein Sensor sieht wesentlich komplexer aus, aber auch da kann man die Unterabfrage einbauen, muß halt nur den Wert mehrmals ändern.

Was deine Abfrage für Vorteile/Nachteile hat, muß ich mir morgen einmal in ruhe anschauen, aber ich versuche es immer zu vermeiden mit Union zu arbeiten, das erzeugt nach meiner Erfahrung immer einen großen Overhead, aber das kann heute natürlich ganz anders sein. Meine Haupzeit mit SQL ist ja auch schon wieder 30 Jahre her :roll_eyes:
Jaja, alter Mann…

Aber versuche es auch mal bei dir mit der Unterabfrage.

Gruß Ralf

2 „Gefällt mir“

Das ist ein super Punkt! Danke Ralf!!! Ich mache es über die ID da es cleaner ist :slight_smile: Aber Du hast 100% Recht!!!

Hier meine “Original” Abfrage mit Fallback :slight_smile: für 2 Gruppen in einer (addition) indklusive Umrechnung, Fehlertoleranz und Tages-Riemann das kann jeder genaus übernehmen nur MetaID austauschen

WITH riemann_50 AS (
  SELECT 
    CAST(state AS DECIMAL(10,2)) as watt,
    last_updated_ts,
    LEAD(last_updated_ts) OVER (ORDER BY last_updated_ts) as next_ts
  FROM states
  WHERE metadata_id = 50
    AND FROM_UNIXTIME(last_updated_ts) >= CURDATE()
    AND state NOT IN ('unknown', 'unavailable')
    AND state REGEXP '^[0-9]+(\\.[0-9]*)?$'
),
riemann_51 AS (
  SELECT 
    CAST(state AS DECIMAL(10,2)) as watt,
    last_updated_ts,
    LEAD(last_updated_ts) OVER (ORDER BY last_updated_ts) as next_ts
  FROM states
  WHERE metadata_id = 51
    AND FROM_UNIXTIME(last_updated_ts) >= CURDATE()
    AND state NOT IN ('unknown', 'unavailable')
    AND state REGEXP '^[0-9]+(\\.[0-9]*)?$'
),
riemann_52 AS (
  SELECT 
    CAST(state AS DECIMAL(10,2)) as watt,
    last_updated_ts,
    LEAD(last_updated_ts) OVER (ORDER BY last_updated_ts) as next_ts
  FROM states
  WHERE metadata_id = 52
    AND FROM_UNIXTIME(last_updated_ts) >= CURDATE()
    AND state NOT IN ('unknown', 'unavailable')
    AND state REGEXP '^[0-9]+(\\.[0-9]*)?$'
)
SELECT 
  ROUND(
    COALESCE((SELECT SUM(watt * (COALESCE(next_ts, last_updated_ts + 300) - last_updated_ts) / 3600.0 / 1000.0) FROM riemann_50 WHERE watt >= 0), 0) +
    COALESCE((SELECT SUM(watt * (COALESCE(next_ts, last_updated_ts + 300) - last_updated_ts) / 3600.0 / 1000.0) FROM riemann_51 WHERE watt >= 0), 0) +
    COALESCE((SELECT SUM(watt * (COALESCE(next_ts, last_updated_ts + 300) - last_updated_ts) / 3600.0 / 1000.0) FROM riemann_52 WHERE watt >= 0), 0)
  , 2) as state;

Hier eine Gruppe (String) (incl Fehlerbehandlung und Reset um Mitternacht Riemann)

WITH riemann_52 AS (
  SELECT 
    CAST(state AS DECIMAL(10,2)) as watt,
    last_updated_ts,
    LEAD(last_updated_ts) OVER (ORDER BY last_updated_ts) as next_ts
  FROM states
  WHERE metadata_id = 52
    AND FROM_UNIXTIME(last_updated_ts) >= CURDATE()
    AND state NOT IN ('unknown', 'unavailable')
    AND state REGEXP '^[0-9]+(\\.[0-9]*)?$'
)
SELECT ROUND(
  COALESCE(SUM(watt * (COALESCE(next_ts, last_updated_ts + 300) - last_updated_ts) / 3600.0 / 1000.0), 0)
, 2) as state
FROM riemann_52 WHERE watt >= 0;

Einfach copy paste und fertig…

Ein Beispiel was noch easy geht… aber nichts mit der KI zu tun hat:
Außentemperatur vor einem Jahr zu diesem Zeitpunkt:

SELECT 
  CAST(state AS DECIMAL(10,1)) as state
FROM states 
WHERE metadata_id = 464
AND DATE(FROM_UNIXTIME(last_updated_ts)) = DATE_SUB(CURDATE(), INTERVAL 1 YEAR)
AND state IS NOT NULL 
AND state != ''
AND state != 'unavailable'
AND state != 'unknown'
ORDER BY ABS(TIME_TO_SEC(TIME(FROM_UNIXTIME(last_updated_ts))) - TIME_TO_SEC(CURTIME()))
LIMIT 1

Die Möglichkeiten zum Auswerten / Vergleichen / Gegenüberstellen sind schier unendlich

Oder Weather Fuision AI… via SQL:

Oder HW Monitoring:

Besonders Spannend ist es wenn man der Solar-Ertrag zu vovn heute mit dem von vor 1 Jahr direkt gegenüber haben möchte .. oder Jahreerzeugung.. ect..

Aber das führt nun zu weit… :slight_smile: und wird OT.. also @nightrunner um noch mal zurückzukommen… bau dir mal SQL Sensoren zum Vergelich und / oder nehme die in SFML. Du verlierst auch keine Daten, da sie nicht wie ein HA RIeman bei Null anfangen sondern die DB komplett nutzen.

PS: Daher nutzt SFML auch SQL und eine eigene DB..

2 „Gefällt mir“

Du vergisst wohl, das du MariaDB einsetzt, die meisten User werden wohl hier auf die interne SQLite-Datenbank setzen. Da ist deine Umwandlung mit From_Unixtime nicht möglich. Man wird also deine Abfragen so nicht unbedingt direkt benutzen können. Beide Datenbanken sprechen - obwohl beide SQL sind - unterschiedliche Dialekte.

Und das meine ich mit der Unterabfrage, ich würde anstatt

WITH riemann_52 AS (
  SELECT 
    CAST(state AS DECIMAL(10,2)) as watt,
    last_updated_ts,
    LEAD(last_updated_ts) OVER (ORDER BY last_updated_ts) as next_ts
  FROM states
  WHERE metadata_id = 52
    AND FROM_UNIXTIME(last_updated_ts) >= CURDATE()
    AND state NOT IN ('unknown', 'unavailable')
    AND state REGEXP '^[0-9]+(\\.[0-9]*)?$'
)
SELECT ROUND(
  COALESCE(SUM(watt * (COALESCE(next_ts, last_updated_ts + 300) - last_updated_ts) / 3600.0 / 1000.0), 0)
, 2) as state
FROM riemann_52 WHERE watt >= 0;

das Ganze so schreiben, nach SQLite übersetzt und mit der SonsorID-Unterabfrage ergänzt, um es testen zu können:

WITH riemann_52 AS (
  SELECT
    CAST(state AS REAL) AS watt,
    last_updated_ts,
    LEAD(last_updated_ts) OVER (ORDER BY last_updated_ts) AS next_ts
  FROM states
  WHERE metadata_id = (
      SELECT sm.metadata_id
      FROM states_meta sm
      WHERE sm.entity_id = 'sensor.inverter_leistung_dc_total'
      LIMIT 1
  )
    AND datetime(last_updated_ts, 'unixepoch') >= date('now')
    AND state NOT IN ('unknown', 'unavailable')
    AND state GLOB '[0-9]*'
)
SELECT ROUND(
  COALESCE(
    SUM(
      watt * (COALESCE(next_ts, last_updated_ts + 300) - last_updated_ts) / 3600.0 / 1000.0
    ),
    0
  ),
  2
) AS state
FROM riemann_52
WHERE watt >= 0;

Ich kann 'sensor.inverter_leistung_dc_total' besser lesen als 52
Das hört sich wie 42 an :rofl:

PS: für die anderen laßt euch die Abfragen mit der KI eures Vertrauens von Tom nach SQLite übersetzen. Gerade einmal mit Perplexity ausprobiert, die kommt auf die selbe Übersetzung wie ich.

Du hast Recht… aber ich habe in der Anleitung auf die Unterschiede zwischen MariaDB und HADB hingewiesen… und auf GROK als Mittel der Wahl um für sich selber die passende Abfrage zu generieren

1 „Gefällt mir“

@Tom-HA , @Thomassh , @alteMade

Danke an alle! Ihr habt mich motiviert es über die Feiertage mal auszuprobieren!
Ich wünsche allen schöne Pfingsten
Stefan

2 „Gefällt mir“