SFML Eure Erfahrungen sind gefragt // Eure eigenen Karten und Visualieiserungen

danke für den Hinweis. Ich hatte es schon geahnt. 2 Wetter APP machen ja auch nicht wirklich Sinn. Jetzt ist mir dann auch klar, warum die sensor.ml_weather_cloud_cover_XXX fehlen. Ich betreibe meine eigene Wetterstation schon länger mit weather-fusion-ai und auch mal wieder ein wirklich großartiges Tool :smiley: Leider liegt die Regenprogrnose öfters mal daneben … aber dafür habe ich ja meinen Regenradar, da sehe ich es dann ja frühzeitig, wenn ich z.B. mit dem Hund raus muss.

1 „Gefällt mir“

Das geht auch „schöner“ …

Aber zurück zu Statistics-Karte: muss ich die Wolken und Radiation Sensoren denn nun rauswerfen? Haben die noch die richtige Funktion? Da waren ja früher mehr Sensoren drin.

1 „Gefällt mir“

Super Chart!
Kannst Du noch verraten wie Du die beiden Sensoren genau angelegt hast?

sensor.sunrise_hour
sensor.sunset_hour

Jaap.. da Du zu den ersten gehört hast (und gehörst) .. kannst Du alles o lassen :slight_smile:

2 „Gefällt mir“

Ja, sun2 Integration aus HACS laden

Und dann

1 „Gefällt mir“

Danke! Die sun integration habe ich bereits für die horizon-card installiert gehabt.

1 „Gefällt mir“

Für alle die “basteln” wollen.. hier mal die “alte ML-Version” aus dem März diesen Jahres - bevor ich sie eingestellt habe.. KEIN SUPPORT IST EINGESTELLT!

ml_weather.zip.txt (22,3 KB)

Viel Spaß damit :wink: „Oldie but Goldie“

Im Endeffekt holt ML-Weather nur die Daten der Wetter KI aus dem Code und bereitet sie auf… es ist KEINE Wettervorhersage wie Weather Fusion AI. sondern eine sehr frühe Visualisierung was die Wetter-KI am Vorabend für ein Wetter am laufenden Tag berechnet hat.. das ist ein Wichtiger Unterschied!.. Aktuell macht STATS das, daher ist die “Integration” eingestellt worden und da es zu immer mehr Verwechslungen kann, einige dachten das ML-Weather eine Wettervorhersage ist.. was nur in Teilen richtig ist.

2 „Gefällt mir“

(Beitrag vom Verfasser gelöscht)

Das ist gut, denn sonst müsste man sich wohl mit den Daten aus der solar.forecast.db und SQlite rumschlagen - das kann ich nicht!

Die Statistics Karte ist komplett GUI - Ich liebe es!

Wie kommt man denn wohl grafisch an die Vergangenheitsdaten der solar.forecast.db?

Ach, und was bedeutet

1 „Gefällt mir“

Vor einigen Monaten habe ich mir im Rahmen der derzeitigen Möglichkeiten, das mal gebaut (ist auch, glaube ich, weiter oben).

Vermutlich musst Du ihn erst von Github laden. GitHub - pnbruckner/ha-sun2: Home Assistant Sun2 Sensor · GitHub

Habe wohl die Standard sun Integration. Die Sensornamen waren leicht anders, aber es läuft.

@Tom-HA Weil es gerade passt - Da kann ich die ML Weather (Korrigierte Wetterdaten) Version 8.2.0 jetzt deinstallieren und den Ordner sfml_stats_weather löschen oder? Habe keine lokale Wetterstation, daher auch keine installierte Weather Fusion Ai. Im STATS \ Sensoren \ Wetter hatte ich bereits auf die HA Integration Weather forecast von met.no verlinkt. Danke

Hallo @harix

Ja, dass kannst Du machen, aber… wenn Du dann später mal Daten aus der SQL-DB für andere Zwecke benötigst, musst Du ein eigenes SQL-Skript schreiben. Also meine ehrliche Meinung: Frist kein Brot keine Ressourcen und besser man hat als man hätte… - ich habe es bei mir drauf und wie man an dem Beitrag von @Joachim-xo gut sehen kann, kann es immer mal passieren das man viel später doch noch etwas bauen möchte

1 „Gefällt mir“

(Beitrag vom Verfasser gelöscht)

Bei mir läuft seit gestern Abend eine MARSTEK Venus E Gen 3.0 Plug-in Batterie und STATS habe ich soeben angepasst. Da mein SUNNY BOY 5.0 keine Akkus unterstützt, war dies eigentlich die einzige Lösung für unseren 2 Personen Haushalt.

Mein Freund Frank hat gestern den SHELLY 3 PRO EM im Sicherungskasten montiert, dem Akku habe ich mitgeteilt, dass er sich am SHELLY orientieren soll, läuft. Der Akku läuft im Modus “Eigenverbrauch”. Ist dann heute morgen gegen 7 Uhr “leer” (12%) gewesen. Dazu muss ich sagen, dass gestern Abend, unsere WW-Wärmepumpe noch ihr Legionellenprogramm gestartet hat, zieht gut Saft.

Laut diverser KIs, soll sich der Akku in 3,5 bis 4 Jahren rechnen! Lasset die Spiele beginnen…

3 „Gefällt mir“

Ich möchte euch meine Art der Restprognosenberechnung teilen:

{% set hf = state_attr('sensor.prognose_heute', 'hourly_forecast') or {} %}
{% set anteil = (60 - now().minute) / 60 %}
{% set ns = namespace(s = (hf.get('%02d:00' % now().hour, 0) | float(0)) * anteil) %}
{% for h in range(now().hour + 1, 24) %}
  {% set ns.s = ns.s + (hf.get('%02d:00' % h, 0) | float(0)) %}
{% endfor %}
{{ ns.s | round(2) }}

SFML passt die zukünftigen Stundenwerte mit an, falls es einen Cutoff gibt, somit steht hier immer die Wahrheit der Rest-Prognose drin. Die aktuelle Stunde wird anteilig gerechnet, damit der Wert flüssig weiterläuft und nicht erst zur Stunde springt.

Dieses Prinzip nutze ich auch, um mit Prognose und Lastprofil abzuschätzen, ob mein Akku ausreicht oder ob ich drüber bin. Das dann als Trigger, um verschiebbare Verbraucher gezielt zu starten. Ich hab Claude mal zusammentragen lassen, was dahinter steckt:

Akku-Überschusswarnung auf Basis der SFML-Stundenprognose

Zeigt an, wie viele kWh heute voraussichtlich ungenutzt bleiben, weil der
Akku vollläuft, bevor die PV-Erzeugung endet. Damit weiß ich mittags, ob ich
Waschmaschine/Trockner/Spülmaschine noch starten kann, ohne Netzstrom zu kaufen.

Die Warnung simuliert den restlichen Tag stundenweise:

freie Kapazität = (100 - SOC) / 100 * Akkukapazität

Dann je Reststunde Überschuss = PV-Prognose − erwartete Last. Positiver
Überschuss lädt den Akku, bis er voll ist; alles darüber ist Verlust und
wird aufsummiert. Negativer Überschuss entlädt (begrenzt auf die Kapazität).
Die laufende Stunde wird anteilig nach Restminuten gerechnet und nutzt die
Ist-Messwerte statt der Prognose.

Zwei Details, die den Unterschied machen

1. Direkt auf der Stundenkurve. Gelesen wird
state_attr('sensor.prognose_heute', 'hourly_forecast') — das Dict
{"00:00": kWh, ...}. Kein prognose_heute_rest, kein total_upcoming. Wer
daneben noch einen Restertrags-Sensor anzeigt, sollte den aus derselben Quelle
speisen, sonst zeigt die Karte einen Restertrag an, mit dem sie gar nicht
gerechnet hat.

2. Lastkorrektur k. Das 14-Tage-Lastprofil ist ein Mittel — es weiß nicht,
ob heute Homeoffice oder Büro ist, ob die Klimaanlage läuft, ob Ferien sind.
Ohne Korrektur ist die Warnung an Bürotagen systematisch zu pessimistisch.
k = Ist-Last der letzten 4 h ÷ Profil derselben 4 h, begrenzt auf
[0,35 … 1,3]. Bei mir sind allein die PCs 5,3 kWh/Tag von 12,7 kWh Profil —
an Bürotagen fällt k auf ~0,6, und erst dann feuert die Warnung überhaupt.


Voraussetzungen

Vier Ist-Werte, die jeder durch seine eigenen Entities ersetzen muss:

Was bei mir muss liefern
Hausverbrauch (Leistung) sensor.ef_power_sys_load W, Momentanwert
PV-Erzeugung (Leistung) sensor.ef_pv_sum_all W, Momentanwert
Akku-SOC sensor.stream_battery_soc_total %, 0–100
SFML-Prognose sensor.prognose_heute Attribut hourly_forecast

Dazu kap im Template auf die eigene Akkukapazität setzen (bei mir 5,76 kWh).

Glättungs-Helfer (UI → Helfer → Filter-Sensor)

Rohe Leistungswerte springen zu stark, deshalb vier Filter:

Name Quelle Filter Fenster
Hausverbrauch geglaettet sensor.ef_power_sys_load Gleitender Mittelwert (Zeit) 15 min
PV Erzeugung geglaettet sensor.ef_pv_sum_all Gleitender Mittelwert (Zeit) 15 min
Hausverbrauch 1min Takt sensor.ef_power_sys_load Durchsatzbegrenzung (Zeit) 1 min
Hausverbrauch 4h Mittel sensor.hausverbrauch_1min_takt Gleitender Mittelwert (Zeit) 4 h

Alle mit Genauigkeit 0, Typ „letzter". Der 1-Minuten-Takt vor dem 4-h-Mittel ist
wichtig: ohne ihn frisst das 4-h-Fenster bei jedem Neustart zehntausende
Zustandsänderungen aus der Recorder-DB.

Lastprofil (Integration „SQL")

Kein Template-Helfer, sondern ein SQL-Sensor über die Langzeitstatistik. Er
liefert das 14-Tage-Mittel je Stunde als Attribute h00h23 (W) plus h_now
und samples. Statistik-Mittelwerte statt Rohzustände — deshalb ist die Abfrage
billig und läuft auch auf schwacher Hardware.

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

  • Spalte: h_now
  • Einheit W, Geräteklasse power, Zustandsklasse measurement
  • Abfrage (sensor.ef_power_sys_load durch die eigene ersetzen):
SQL-Abfrage (aufklappen)
SELECT
  ROUND(AVG(CASE WHEN h='00' THEN m END),0) AS h00,
  ROUND(AVG(CASE WHEN h='01' THEN m END),0) AS h01,
  ROUND(AVG(CASE WHEN h='02' THEN m END),0) AS h02,
  ROUND(AVG(CASE WHEN h='03' THEN m END),0) AS h03,
  ROUND(AVG(CASE WHEN h='04' THEN m END),0) AS h04,
  ROUND(AVG(CASE WHEN h='05' THEN m END),0) AS h05,
  ROUND(AVG(CASE WHEN h='06' THEN m END),0) AS h06,
  ROUND(AVG(CASE WHEN h='07' THEN m END),0) AS h07,
  ROUND(AVG(CASE WHEN h='08' THEN m END),0) AS h08,
  ROUND(AVG(CASE WHEN h='09' THEN m END),0) AS h09,
  ROUND(AVG(CASE WHEN h='10' THEN m END),0) AS h10,
  ROUND(AVG(CASE WHEN h='11' THEN m END),0) AS h11,
  ROUND(AVG(CASE WHEN h='12' THEN m END),0) AS h12,
  ROUND(AVG(CASE WHEN h='13' THEN m END),0) AS h13,
  ROUND(AVG(CASE WHEN h='14' THEN m END),0) AS h14,
  ROUND(AVG(CASE WHEN h='15' THEN m END),0) AS h15,
  ROUND(AVG(CASE WHEN h='16' THEN m END),0) AS h16,
  ROUND(AVG(CASE WHEN h='17' THEN m END),0) AS h17,
  ROUND(AVG(CASE WHEN h='18' THEN m END),0) AS h18,
  ROUND(AVG(CASE WHEN h='19' THEN m END),0) AS h19,
  ROUND(AVG(CASE WHEN h='20' THEN m END),0) AS h20,
  ROUND(AVG(CASE WHEN h='21' THEN m END),0) AS h21,
  ROUND(AVG(CASE WHEN h='22' THEN m END),0) AS h22,
  ROUND(AVG(CASE WHEN h='23' THEN m END),0) AS h23,
  ROUND(AVG(CASE WHEN h=strftime('%H','now','localtime') THEN m END),0) AS h_now,
  COUNT(*) AS samples
FROM (
  SELECT strftime('%H', s.start_ts, 'unixepoch', 'localtime') AS h, s.mean AS m
  FROM statistics s
  JOIN statistics_meta sm ON sm.id = s.metadata_id
  WHERE sm.statistic_id = 'sensor.ef_power_sys_load'
    AND s.mean IS NOT NULL
    AND s.start_ts >= CAST(strftime('%s','now','-14 days') AS REAL)
);

Der Sensor

Template-Helfer (Einstellungen → Helfer → Vorlage → Sensor). Zustand:

{% set kap = 5.76 %}
{% set soc = states('sensor.stream_battery_soc_total') | float(0) %}
{% set anteil = (60 - now().minute) / 60 %}
{% set hh = '%02d' % now().hour %}
{% set hf = state_attr('sensor.prognose_heute', 'hourly_forecast') or {} %}
{# Lastkorrektur k: Ist-Last der letzten 4 h gegen Profil derselben 4 h #}
{% set prof_now = state_attr('sensor.lastprofil_14d', 'h_now') | float(0) %}
{% set load_now = states('sensor.hausverbrauch_geglaettet') | float(-1) %}
{% set pv_now = states('sensor.pv_erzeugung_geglaettet') | float(-1) %}
{% set load_4h = states('sensor.hausverbrauch_4h_mittel') | float(-1) %}
{% set ns2 = namespace(p = 0.0) %}
{% for i in range(4) %}
  {% set ns2.p = ns2.p + (state_attr('sensor.lastprofil_14d', 'h%02d' % ((now().hour - i) % 24)) | float(0)) %}
{% endfor %}
{% set prof_4h = ns2.p / 4 %}
{% set k_raw = (load_4h / prof_4h) if (load_4h >= 0 and prof_4h > 0) else ((load_now / prof_now) if (load_now >= 0 and prof_now > 0) else 1.0) %}
{% set k = [[k_raw, 0.35] | max, 1.3] | min %}
{% set ns = namespace(frei = (100 - soc) / 100 * kap, verlust = 0.0) %}
{# laufende Stunde: Ist-Messwerte, anteilig nach Restminuten #}
{% set pv = [(hf.get(hh ~ ':00', 0) | float(0)) * anteil, ([pv_now, 0] | max) / 1000 * anteil] | max %}
{% set last = (([load_now, 0] | max) if load_now >= 0 else prof_now * k) / 1000 * anteil %}
{% set ueber = pv - last %}
{% if ueber > 0 %}
  {% set laden = [ueber, ns.frei] | min %}
  {% set ns.frei = ns.frei - laden %}
  {% set ns.verlust = ns.verlust + (ueber - laden) %}
{% else %}
  {% set ns.frei = [ns.frei - ueber, kap] | min %}
{% endif %}
{# volle Reststunden aus derselben Kurve #}
{% for h in range(now().hour + 1, 24) %}
  {% set lastp = (state_attr('sensor.lastprofil_14d', 'h%02d' % h) | float(0)) * k / 1000 %}
  {% set u = (hf.get('%02d:00' % h, 0) | float(0)) - lastp %}
  {% if u > 0 %}
    {% set laden = [u, ns.frei] | min %}
    {% set ns.frei = ns.frei - laden %}
    {% set ns.verlust = ns.verlust + (u - laden) %}
  {% else %}
    {% set ns.frei = [ns.frei - u, kap] | min %}
  {% endif %}
{% endfor %}
{{ ns.verlust | round(2) }}

Verfügbarkeit:

{{ has_value('sensor.stream_battery_soc_total') and state_attr('sensor.prognose_heute', 'hourly_forecast') is not none and has_value('sensor.lastprofil_14d') }}

Einheit kWh, Zustandsklasse measurement — bewusst keine Geräteklasse
energy, es ist eine Vorhersage und kein Zählerstand.


Karte (Mushroom Template Card)

sensor.prognose_resttag_netto im Sekundärtext ist der Restertrags-Sensor aus meinem anderen Beitrag — wer den nicht hat, kürzt den else-Zweig einfach auf SOC und Last.

type: custom:mushroom-template-card
entity: sensor.pv_ueberschuss_prognose
icon: mdi:solar-power-variant
icon_color: >-
  {% set v = states(entity) | float(0) %}{{ 'red' if v >= 0.6 else 'orange' if v
  >= 0.15 else 'green' }}
primary: >-
  {% set v = states(entity) | float(0) %}{{ (v | round(1)) ~ ' kWh ungenutzt' if
  v >= 0.15 else 'Kein Ueberschuss' }}
secondary: >-
  {% set v = states(entity) | float(0) %}{% set soc =
  states('sensor.stream_battery_soc_total') | float(0) | round(0) %}{% set rest =
  states('sensor.prognose_resttag_netto') | float(0) %}{% set l =
  states('sensor.hausverbrauch_geglaettet') | float(0) | round(0) %}{% if v >=
  0.15 %}Grossverbraucher jetzt starten - Akku {{ soc }} %, Last {{ l }} W{% else
  %}Restertrag {{ rest | round(1) }} kWh - Akku {{ soc }} %, Last {{ l }} W{%
  endif %}

Was man wissen sollte

  • k ist ein einziger Skalar für den ganzen Resttag. Er skaliert auch die
    Abendlast mit, obwohl sich an einem Bürotag vor allem der Tag ändert. Sauberer
    wäre, eine bekannte Grundlast (PCs o. ä.) direkt abzuziehen statt global zu
    skalieren — das steht bei mir noch aus.
  • Die Prognosekurve wird für vergangene Stunden nicht mit Ist-Werten
    überschrieben.
    Für die Restberechnung ist das egal, weil nur die
    Zukunftsstunden gelesen werden — bei einem Vergleich Soll gegen Ist muss man es
    aber wissen.
  • Getestet auf 2 kWp / 5,76 kWh. Die Schwellen 0,15 / 0,6 kWh und der
    k-Klammerbereich [0,35 … 1,3] passen zu dieser Größenordnung, nicht
    automatisch zu einer 10-kWp-Anlage.
1 „Gefällt mir“

Guten Morgen allerseits,

meine Prognose-Karte aus dem Februar hat ein großes Update bekommen: Version 2.0.1 liest jetzt sämtliche Werte aus der SFML-Datenbank. Wechselrichter-, Speicher- und Verbrauchssensoren der eigenen Anlage braucht sie nicht mehr — damit läuft sie unverändert auf jeder SFML-Installation. Auch die Speicherkapazität muss nicht mehr in der Karte stehen, der Ladestand liegt jetzt als Prozent auf der rechten Achse.

Anlass war der Wert, über den Ihr hier gerade diskutiert: „Prognose heute Rest" zeigte bei mir abends 59,5 kWh bei 41,4 kWh Tagesprognose. Bis Toms angekündigter Fix da ist, summiert die Karte die verbleibenden Stundenprognosen selbst aus der Datenbank, anteilig für die laufende Stunde.

Drei neue SQL-Sensoren bringen die Daten in die Karte; sie liegen mit im Repo, dazu eine kurze Umstiegsanleitung in den Release Notes: Release v2.0.4 – Lesbarkeit der Kurven · BMeyendriesch/Solar-Prognose-Card · GitHub

Euch einen schönen Wochenstart
Burkard

4 „Gefällt mir“

Hallo Burkhard,

Deine Prognose-Cards sind eben installiert und eine tolle Ergänzung in meiner SFML Übersichtskarte eingetragen. Die Februar Version hatte ich getestet und zur besseren Übersicht an den Farben gedreht.
Für heute fehlt noch etwas am Graphen - die 3 neuen Sensoren sind erst seit mittags aktiv.
Bin gespannt !
Herzlichen Dank fürs Teilen!!
Grüße,
Dieter

1 „Gefällt mir“

Mal ‘ne Idee für die Leute, die’s nicht so mit SQLite haben. Ich trau mich da nicht ran …

… und deswegen habe ich die hier ausprobiert:

Edit: hier bastel ich noch an einer weiteren Karte mit „gleitendem Durchschnitt“ herum.

Edit 2: man kann damit auch Wetterdaten tracken …

1 „Gefällt mir“