Hallo Zusammen,
im WIKI SolarForecast - Solare Prognose (PV Erzeugung) und Verbrauchersteuerung steht im Abschnitt https://wiki.fhem.de/wiki/SolarForecast_-_Solare_Prognose_(PV_Erzeugung)_und_Verbrauchersteuerung#Praxisbeispiele_und_L%C3%B6sungsans%C3%A4tze_f%C3%BCr_Steuerungen
ein Beispiel wie die SolarForecast-Vorhersagedaten per API von evcc abgerufen werden können.
Wenn ich das wie im WIKI beschrieben mache stürzt evcc ab bzw. läuft nicht hoch.
Ausgangslage: fhem und evcc laufen auf gleichem RPI5.
Der zusätzliche Web-Server:
efine WEBapi FHEMWEB 8089
attr WEBapi csrfToken noneist eingerichtet. Die UserReadings mit den JSON Daten werden erzeugt und sehen auch irgendwie plausibel aus.
Der evcc-Konfig unter tariffs läßt sich "nur" über die YAML Datei erstellen.
Die Version direkt über die Konfig in der Webseite geht überhaupt nicht.
Hat noch Jemand Erfahrungen damit gesammelt?
LG WDS
Hallo Dieter,
bei mir funktioniert die Einbindung der SF Solarprognose in EVCC
solar: # list of pv generation forecast (additive)
type: custom
interval: 2m
forecast:
source: http
uri: http://192.168.178.44:8086/fhem?cmd=%7BReadingsVal%28%27solErtrag%27%2C%27jsonReading%27%2C%27%27%29%7D&XHR=1Gruß, Dieter
oder meinst du die Konfiguration für den neuen UI-Konfig-Editor? DAMIT habe ich nun auch Schwierigkeiten, bin aber dran.
## PV production forecast
tariff: solar
forecast: # hourly solar production forecast (W)
source: js
script: |
var rates = [];
var now = new Date();
for (var i = 0; i < 48; i++) {
var start = new Date(now.getTime() + i * 3600000);
rates.push({
start: start.toISOString(),
end: new Date(start.getTime() + 3600000).toISOString(),
value: 2000 // W
});
}
JSON.stringify(rates);
## HTTP example (uncomment to use)
#forecast: # hourly solar production forecast (W)
# source: http
# uri: https://example.com/api/solar
# jq: |
# map({
# "start": .start,
# "end": .end,
# "value": .power
# }) | tostring
Zitat von: grappa24 am 26 März 2026, 00:03:53bei mir funktioniert die Einbindung der SF Solarprognose in EVCC
wie gesagt, zunächst auch (nur) mit der evcc.yaml.
Aber mir ist da noch etwas eingefallen, ich hab die "Befüllung" des jsonReading in ein sub ausgelagert:
Definition als userReading:
jsonReading:nextCycletime.* { main::forecast_json() }Hier die sub:
#####################################################################################################################
# Wandelt die Forecast-Werte in JSON und ins UTC-Zeitformat um, zur Verwendung durch evcc
# Für die Kommunikation wird der Webserver WEBapi benutzt (8086, kein HTTPS, kein csrfToken)
# evcc.yaml siehe tariffs: solar: ...
# uri: http://192.168.178.44:8086/fhem?cmd=%7BReadingsVal%28%27[b]<SF-Device>[/b]%27%2C%27jsonReading%27%2C%27%27%29%7D&XHR=1
#####################################################################################################################
sub forecast_json {
my $hour = 0;
my @output;
# Parser für Datum mit CET/CEST
my $parser = DateTime::Format::Strptime->new(
pattern => '%Y-%m-%d %H:%M:%S',
time_zone => 'Europe/Berlin',
);
# Alle NextHour-Daten durchsuchen
while ($hour < 100) {
my $hour_str = sprintf('NextHour%02d', $hour);
my $start_str = FHEM::SolarForecast::NexthoursVal ('solErtrag', $hour_str, 'starttime', 'na');
my $pvfc = FHEM::SolarForecast::NexthoursVal ('solErtrag', $hour_str, 'pvfc', 'na');
# Schleife beenden, wenn keine Werte mehr vorhanden sind
last if $start_str eq 'na' or $pvfc eq 'na';
# parse und konvertiere Zeit
my $start_dt = $parser->parse_datetime($start_str);
my $end_dt = $start_dt->clone->add(hours => 1);
# nach UTC konvertieren
$start_dt->set_time_zone('UTC');
$end_dt->set_time_zone('UTC');
push @output, {
start => $start_dt->iso8601() . 'Z',
end => $end_dt->iso8601() . 'Z',
value => 0 + $pvfc,
};
$hour++;
}
# Ausgabe als JSON
my $json = JSON->new->utf8->pretty->encode(\@output);
return $json;
}
hier mal meine aktuelle EVCC Konfiguration für die Solar-Vorhersage nach neuen UI-Standard und Zugriff auf das jsonReading aus SF:
tariff: solar
forecast:
source: http
uri: http://192.168.178.44:8086/fhem?cmd=%7BReadingsVal%28%27solErtrag%27%2C%27jsonReading%27%2C%27%27%29%7D&XHR=1
jq: |
map({
"start": .start,
"end": .end,
"value": .power
}) | tostring
Die EVCC-Syntax Prüfung läuft durch, es wird aber keine Graphik erzeugt.
Wenn man "tostring" weglässt kommt der Fehler "invalid character 'm' looking for beginning of value".
Der Input (das jsonReading) sieht eigentlich gut aus:
[
{
"start" : "2026-03-27T22:00:00Z",
"end" : "2026-03-27T23:00:00Z",
"value" : 0
},
{
"value" : 0,
"start" : "2026-03-27T23:00:00Z",
"end" : "2026-03-28T00:00:00Z"
},
{
"end" : "2026-03-28T01:00:00Z",
"start" : "2026-03-28T00:00:00Z",
"value" : 0
},
{
"value" : 0,
"start" : "2026-03-28T01:00:00Z",
"end" : "2026-03-28T02:00:00Z"
},
{
"end" : "2026-03-28T03:00:00Z",
"start" : "2026-03-28T02:00:00Z",
"value" : 0
},
{
"value" : 0,
"start" : "2026-03-28T03:00:00Z",
"end" : "2026-03-28T04:00:00Z"
},
{
"value" : 0,
"end" : "2026-03-28T05:00:00Z",
"start" : "2026-03-28T04:00:00Z"
},
{
"value" : 27,
"end" : "2026-03-28T06:00:00Z",
"start" : "2026-03-28T05:00:00Z"
},
Probiert mal:
tariff:
solarforecast:
source: http
uri: http://192.168.178.44:8086/fhem?cmd=%7BReadingsVal%28%27solErtrag%27%2C%27jsonReading%27%2C%27%27%29%7D&XHR=1
jq: |
map({
"start": .start,
"end": .end,
"power": .value
})
Veränderte Syntax und ohne tostring am Ende.
Falls das neue UI dennoch keine Grafik zeigt, wäre ein Blick in die EVCC-Logs (evcc --log debug) hilfreich – dort sieht man, ob die Daten ankommen und ob das Format akzeptiert wird.
Zitat von: DS_Starter am 28 März 2026, 07:57:54Probiert mal:
tariff:
solarforecast:
source: http
uri: http://192.168.178.44:8086/fhem?cmd=%7BReadingsVal%28%27solErtrag%27%2C%27jsonReading%27%2C%27%27%29%7D&XHR=1
jq: |
map({
"start": .start,
"end": .end,
"power": .value
})
Veränderte Syntax und ohne tostring am Ende.
Falls das neue UI dennoch keine Grafik zeigt, wäre ein Blick in die EVCC-Logs (evcc --log debug) hilfreich – dort sieht man, ob die Daten ankommen und ob das Format akzeptiert wird.
das geht leider auch nicht, werde dann mal einen Blick in die Logs werfen, danke
cannot create tariff type 'custom': decoding failed due to the following error(s): 'tariff' expected type 'api.TariffType', got unconvertible type 'map[string]interface {}'Diese (yaml-)Syntax ist brutal :'( noch schlimmer als perl ;)
jetzt hab ich aus versehen die Lösung doch im original SF-Thread gepostet, egal:
https://forum.fhem.de/index.php?msg=1360618
Moin Dieter,
ich war 2 Tage weg... Hier meine bisherigen Versuche:
Ich habe es so wie du beschrieben hast eingebaut.
Das jsonReading in 99myUtils ausgelagert, wie so viele andere Berechnungen.
Mein Problem ist wen ich
userReadings jsonReading:nextCycletime.* { main::forecast_json() }eingeben gibt es keine Fehlermeldung aber auch keine Daten im Reading.
Viele andere userReadings arbeiten so bei mir einwandfrei.
Wo ist den da nun der Fehler?
LG WDS
Hallo WDS,
ZitatMein Problem ist wen ich
Code Auswählen
userReadings jsonReading:nextCycletime.* { main::forecast_json() }
eingeben gibt es keine Fehlermeldung aber auch keine Daten im Reading.
Viele andere userReadings arbeiten so bei mir einwandfrei.
Wo ist den da nun der Fehler?
Ich gehe davon aus, dass der Code für das userReading wie im Wiki beschrieben direkt in SF angelegt ist.
Dadurch ist die Variable $NAME, die im Code verwendet wird, impliziert definiert.
Bei deinem Code außerhalb des Moduls fehlt sie.
Du müsstest also ergänzen:
forecast_json:nextCycletime.* {
use strict;
use warnings;
use JSON;
use DateTime;
use DateTime::Format::Strptime;
my ($NAME) = @_; <--- ergänzt
my $hour = 0;
my $last_start_ts;
my @output;
.....
Und dann so userReadings definieren:
userReadings jsonReading:nextCycletime.* { main::forecast_json($name) }
oder
userReadings jsonReading:nextCycletime.* { main::forecast_json($NAME) }
Das sollte dann klappen.
meine sub sieht so aus
##############################################
# 99_myUtils.pm
##############################################
package main;
use strict;
use warnings;
use POSIX;
use JSON;
use DateTime;
use DateTime::Format::Strptime;
#####################################################################################################################
# Wandelt die Forecast-Werte in JSON und ins UTC-Zeitformat um, zur Verwendung durch evcc
# Für die Kommunikation wird der Webserver WEBapi benutzt (8086, kein HTTPS, kein csrfToken)
# evcc.yaml siehe tariffs: solar: ...
# uri: http://192.168.178.44:8086/fhem?cmd=%7BReadingsVal%28%27solErtrag%27%2C%27jsonReading%27%2C%27%27%29%7D&XHR=1
#####################################################################################################################
sub forecast_json {
my $hour = 0;
my @output;
# Parser für Datum mit CET/CEST
my $parser = DateTime::Format::Strptime->new(
pattern => '%Y-%m-%d %H:%M:%S',
time_zone => 'Europe/Berlin',
);
# Alle NextHour-Daten durchsuchen
while ($hour < 100) {
my $hour_str = sprintf('NextHour%02d', $hour);
my $start_str = FHEM::SolarForecast::NexthoursVal ('solErtrag', $hour_str, 'starttime', 'na');
my $pvfc = FHEM::SolarForecast::NexthoursVal ('solErtrag', $hour_str, 'pvfc', 'na');
# Schleife beenden, wenn keine Werte mehr vorhanden sind
last if $start_str eq 'na' or $pvfc eq 'na';
# parse und konvertiere Zeit
my $start_dt = $parser->parse_datetime($start_str);
my $end_dt = $start_dt->clone->add(hours => 1);
# nach UTC konvertieren
$start_dt->set_time_zone('UTC');
$end_dt->set_time_zone('UTC');
push @output, {
start => $start_dt->iso8601() . 'Z',
end => $end_dt->iso8601() . 'Z',
value => 0 + $pvfc,
};
$hour++;
}
# Ausgabe als JSON
my $json = JSON->new->utf8->pretty->encode(\@output);
#Variante für die Nutzung in der evcc.yaml
return $json;
}
1;
und der Aufruf in SF
attr <SF-Device> userReadings jsonReading:nextCycletime.* { main::forecast_json() }
Ja, hier sieht man es schon, grappa24 hat $NAME fest durch 'solErtrag' ersetzt.
Das ist genau der angeprochene Punkt.
Also jetzt verstehe ich nichts mehr:
Ich habe die Version genauso wie von Grappa24 im Vorletzten Post #10 in 99_myUtils.pm eingetragen.
Funktioniert leider nicht.
Es werden keine Werte ins Reading geschrieben.
Der Aufruf ist auch so erstellt.
LG WDS
ZitatIch habe die Version genauso wie von Grappa24 im Vorletzten Post #10 in 99_myUtils.pm eingetragen.
Du hast hoffentlich 'solErtrag' durch '<Dein SF-Name>' ersetzt?
Wenn du etwas sehen willst, fügst du dir einfach ein paar Log ein. Zum Beispiel:
...
my $sf_dev = '<Dein SF-Name>';
while ($hour < 100) {
my $hour_str = sprintf('NextHour%02d', $hour);
my $start_str = FHEM::SolarForecast::NexthoursVal ($sf_dev, $hour_str, 'starttime', 'na');
my $pvfc = FHEM::SolarForecast::NexthoursVal ($sf_dev, $hour_str, 'pvfc', 'na');
Log3 ($sf_dev, 1 , "$sf_dev - hour: $hour_str, Start: $start_str, pvfc: $pvfc")
# Schleife beenden, wenn keine Werte mehr vorhanden sind
last if $start_str eq 'na' or $pvfc eq 'na';
LG,
Heiko
Soo - war ein längerer Weg.....
Es läuft!
Du verwendest einen anderen SF Namen als z.B. im WIKI.
Das ist gut, nur man muss darauf erstmal kommen.
Wenn man das seit locker 1.5 Jahren nutzt und alle Posts eigentlich
vom gleichen Namen ausgehen, wird so ein Fehler leider erst spät erkannt.
Egal, vielen Dank für Eure Hilfe und bitte die Änderungen ins WIKI eintrtagen.
LG WDS
Ich würde nochmal dafür plädieren den Code und den Aufruf wie von mir in #9 zu ändern. Dann wäre der Code im Wiki universell verwendbar nach der Änderung.
Könnt ihr gern mal anpassen und Rückantwort geben.
Ich füge hier nochmal meine Einstellungen an.
userReading im Modul mit Namen Forecast:
userReadings jsonReading:nextCycletime.* { main::forecast_json($NAME) }Eintrag in 99_myUtils.pm:
#####################################################################################################################
# Wandelt die Forecast-Werte in JSON und ins UTC-Zeitformat um, zur Verwendung durch evcc
# Für die Kommunikation wird der Webserver WEBapi benutzt (8086, kein HTTPS, kein csrfToken)
# evcc.yaml siehe tariffs: solar: ...
# uri: http://192.168.178.44:8086/fhem?cmd=%7BReadingsVal%28%27[b]<SF-Device>[/b]%27%2C%27jsonReading%27%2C%27%27%29%7D&XHR=1
#####################################################################################################################
package main;
use strict;
use warnings;
use POSIX;
use JSON;
use DateTime;
use DateTime::Format::Strptime;
sub forecast_json {
my $hour = 0;
my @output;
# Parser für Datum mit CET/CEST
my $parser = DateTime::Format::Strptime->new(
pattern => '%Y-%m-%d %H:%M:%S',
time_zone => 'Europe/Berlin',
);
# Alle NextHour-Daten durchsuchen
while ($hour < 100) {
my $hour_str = sprintf('NextHour%02d', $hour);
my $start_str = FHEM::SolarForecast::NexthoursVal ('Forecast', $hour_str, 'starttime', 'na');
my $pvfc = FHEM::SolarForecast::NexthoursVal ('Forecast', $hour_str, 'pvfc', 'na');
# Schleife beenden, wenn keine Werte mehr vorhanden sind
last if $start_str eq 'na' or $pvfc eq 'na';
# parse und konvertiere Zeit
my $start_dt = $parser->parse_datetime($start_str);
my $end_dt = $start_dt->clone->add(hours => 1);
# nach UTC konvertieren
$start_dt->set_time_zone('UTC');
$end_dt->set_time_zone('UTC');
push @output, {
start => $start_dt->iso8601() . 'Z',
end => $end_dt->iso8601() . 'Z',
value => 0 + $pvfc,
};
$hour++;
}
# Ausgabe als JSON
my $json = JSON->new->utf8->pretty->encode(\@output);
return $json;
} dann die Einstellungen in evcc Titel: <irgendwas> Anbieter: Benutzerdefiniertes Gerät
tariff: solar
forecast:
source: http
uri: http://192.168.178.25:8089/fhem?cmd=%7BReadingsVal%28%27Forecast%27%2C%27jsonReading%27%2C%27%27%29%7D&XHR=1
jq: |
map({
"start": .start,
"end": .end,
"value": .value
}) | tostring
Wenn du den Aufruf so machst:
userReadings jsonReading:nextCycletime.* { main::forecast_json($NAME) }
Dann kannst du deine festen Namen im Code durch $NAME ersetzen und es passt immer:
#####################################################################################################################
# Wandelt die Forecast-Werte in JSON und ins UTC-Zeitformat um, zur Verwendung durch evcc
# Für die Kommunikation wird der Webserver WEBapi benutzt (8086, kein HTTPS, kein csrfToken)
# evcc.yaml siehe tariffs: solar: ...
# uri: http://192.168.178.44:8086/fhem?cmd=%7BReadingsVal%28%27[b]<SF-Device>[/b]%27%2C%27jsonReading%27%2C%27%27%29%7D&XHR=1
#####################################################################################################################
sub forecast_json {
my ($NAME) = @_;
my $hour = 0;
my @output;
# Parser für Datum mit CET/CEST
my $parser = DateTime::Format::Strptime->new(
pattern => '%Y-%m-%d %H:%M:%S',
time_zone => 'Europe/Berlin',
);
# Alle NextHour-Daten durchsuchen
while ($hour < 100) {
my $hour_str = sprintf('NextHour%02d', $hour);
my $start_str = FHEM::SolarForecast::NexthoursVal ($NAME, $hour_str, 'starttime', 'na');
my $pvfc = FHEM::SolarForecast::NexthoursVal ($NAME, $hour_str, 'pvfc', 'na');
# Schleife beenden, wenn keine Werte mehr vorhanden sind
last if $start_str eq 'na' or $pvfc eq 'na';
# parse und konvertiere Zeit
my $start_dt = $parser->parse_datetime($start_str);
my $end_dt = $start_dt->clone->add(hours => 1);
# nach UTC konvertieren
$start_dt->set_time_zone('UTC');
$end_dt->set_time_zone('UTC');
push @output, {
start => $start_dt->iso8601() . 'Z',
end => $end_dt->iso8601() . 'Z',
value => 0 + $pvfc,
};
$hour++;
}
# Ausgabe als JSON
my $json = JSON->new->utf8->pretty->encode(\@output);
return $json;
}
So ist es richtig, das muss ins WIKI aber:
Für die Erstellung des Webservers WEBapi:
defmod WEBapi FHEMWEB IPV6:8089 global
attr WEBapi csrfToken noneohne die IPV6 lief das Teil bei mir nicht.
Ich verwende IPV6 auch im Hausnetz.
LG WDS
Schaut es euch jetzt mal im Wiki (https://wiki.fhem.de/wiki/SolarForecast_-_Solare_Prognose_(PV_Erzeugung)_und_Verbrauchersteuerung#PV-Vorhersage_an_evcc_%C3%BCbertragen_%28PV-%C3%9Cberschussladen_von_E-Autos_%C3%BCber_steuerbare_Wallboxen%29) an.
Sollte nun alles drin sein an Infos.
@Dieter: Schön, dass es jetzt läuft
@Heiko: Danke für die Arbeit am wiki und insb. für die "Normierung"
Nach einem Tag Arbeit und Recherche an diesem "doofen" evcc Template war ich so froh, dass ich diesen blöden Fehler (.power anstatt .value) gefunden hatte, dass ich nicht mehr an die Abstrahierung des Codes gedacht habe - obwohl, ein wenig Transferleistung hat ja noch niemandem geschadet. ;)
Wir haben uns viel zu sehr daran gewöhnt, schlüsselfertige Lösungen zu übernehmen ohne sie zu verstehen und zu hinterfragen. Das ist eine Erfahrung, die ich insb. auch im Umgang mit KI gemacht habe.
Noch ein Tipp ...
wenn euch der Inhalt des userReadings zu viel wird und deswegen die Ansicht des Device zu unübersichtlich, könnt ihr auch ein versteckes Reading verwenden.
Das geht mit einem "." vor dem Readingnamen, also so:
userReadings .jsonReading:nextCycletime.* { main::forecast_json($NAME) }
Das Reading ist normal vorhanden, aber in der Detailansicht nicht aufgeführt. Mit einem "list" sieht man den Inhalt. Beim Abruf ist natürlich auch ".jsonReading" zu verwenden.
genau der Tipp hat mir noch gefehlt ;)
noch ein joke am Rande:
nachdem ich nun evccc mit dem jsonReading zwecks Erstellung der PV-Vorhersage gefüttert hatte, hat es sich evcc nicht nehmen lassen, jeden einzelnen Wert (start, end, value) via MQTT zu veröffentlichen und in FHEM letztlich als Reading anzulegen.
Mehr noch, insgesamt hat mir evcc auf diesem Weg über 1000 (Tausend) Readings angelegt ::) und mir mein FHEM lahmgelegt.
Ich hab dann das komplette MQTT-evcc Device gelöscht und mit nur den benötigten Readings neu angelegt, autocreate auf 0 gesetzt und event-on-change-reading benutzt. Plötzlich war Ruhe im Karton.
Zitat von: DS_Starter am 29 März 2026, 23:16:43Das Reading ist normal vorhanden, aber in der Detailansicht nicht aufgeführt. Mit einem "list" sieht man den Inhalt. Beim Abruf ist natürlich auch ".jsonReading" zu verwenden.
mit list <SF-Device> sieht man die Inhalte nicht, aber hiermit z.B.:
{ ReadingsVal("<SF-Device>",".jsonReading","not found") }
Äh ja, hast recht.
In der Detailansicht unten mit "Raw definition" kann man sich den Inhalt auch komfortabel schnell mal ansehen.