Add demo solar forecast template (#21971)

Co-authored-by: Michael Geers <michael@geers.tv>
This commit is contained in:
Michael Renner 2025-06-27 08:52:02 +02:00 • committed by GitHub
parent b872dbf23d
commit 6ba804b106
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 114 additions and 0 deletions

View file

@ -262,6 +262,12 @@ tariffs:
feedin:
type: fixed
price: 0.08 # EUR/kWh
solar:
type: template
template: demo-solar-forecast
kwp: 15.5
sunrise: 7
sunset: 17
#co2:
# type: grünstromindex
# zip: 12349

View file

@ -0,0 +1,108 @@
template: demo-solar-forecast
products:
- description:
de: Demo PV Vorhersage
en: Demo PV Forecast
requirements:
description:
de: Zu Demonstrationszwecken. Liefert optimale Solarproduktionskurve mit Spitze zur Mittagszeit.
en: For demonstration purposes. Provides optimal solar production curve peaking at noon.
evcc: ["skiptest"]
group: solar
params:
- name: kwp
type: float
unit: kWp
default: 4.5
description:
en: Maximum generator power
de: Maximale Generatorleistung
- name: sunrise
description:
de: Sonnenaufgang
en: Sunrise hour
type: int
unit: h
default: 6
help:
de: Stunde des Sonnenaufgangs (0-23)
en: Hour of sunrise (0-23)
- name: sunset
description:
de: Sonnenuntergang
en: Sunset hour
type: int
unit: h
default: 18
help:
de: Stunde des Sonnenuntergangs (0-23)
en: Hour of sunset (0-23)
- name: interval
default: 1h
advanced: true
render: |
type: custom
tariff: solar
forecast:
source: js
script: |
// Generate realistic solar forecast with bell curve for next 72 hours
var now = new Date();
var start = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 0, 0, 0);
var rates = [];
var peakPower = parseFloat({{ .kwp }});
var sunrise = parseInt({{ .sunrise }});
var sunset = parseInt({{ .sunset }});
// Calculate day parameters with inclusive hours
// Using modulo to handle midnight-spanning days elegantly
var dayLength = (sunset - sunrise + 1 + 24) % 24 || 24;
var is24HourDaylight = dayLength === 24;
var noon = (sunrise + dayLength / 2) % 24;
// Helper function to calculate position within daylight period
function getPositionInPeriod(hour) {
if (is24HourDaylight) {
// 24-hour daylight: distance from noon with wrap-around
var diff = Math.abs(hour - noon);
return Math.min(diff, 24 - diff);
} else {
// Regular day: hours from sunrise
return hour >= sunrise ? hour - sunrise : 24 - sunrise + hour;
}
}
// Generate hourly rates for 3 days
for (var day = 0; day < 3; day++) {
for (var hour = 0; hour < 24; hour++) {
var time = new Date(start.getTime() + (day * 24 + hour) * 3600000);
var solarValue = 0;
if (dayLength > 0) {
// Check if hour is within daylight period
var isDaylight = is24HourDaylight || (sunrise <= sunset
? hour >= sunrise && hour <= sunset
: hour >= sunrise || hour <= sunset);
if (isDaylight) {
var position = getPositionInPeriod(hour);
var normalized = is24HourDaylight
? position / 12
: (position - dayLength / 2) / (dayLength / 2);
var curve = 1 - normalized * normalized * (is24HourDaylight ? 0.89 : 1);
solarValue = peakPower * 1e3 * curve;
}
}
rates.push({
start: time.toISOString(),
end: new Date(time.getTime() + 3600000).toISOString(),
value: Math.round(Math.max(0, solarValue))
});
}
}
JSON.stringify(rates);
interval: {{ .interval }}