evcc-io/templates/definition/tariff/demo-solar-forecast.yaml
2026-08-26 10:11:40 +02:00

112 lines
3.5 KiB
YAML

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
deprecated: true
render: |
type: custom
tariff: solar
forecast:
source: js
script: |
// Generate realistic solar forecast with bell curve for next 120 hours in 15-minute slots
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 15-minute slots for 5 days
var slotMinutes = 15;
var slotDuration = slotMinutes * 60 * 1000;
var slotsPerHour = 60 / slotMinutes;
var slotsPerDay = 24 * slotsPerHour;
for (var day = 0; day < 5; day++) {
for (var slot = 0; slot < slotsPerDay; slot++) {
var time = new Date(start.getTime() + (day * slotsPerDay + slot) * slotDuration);
var hour = slot / slotsPerHour;
var solarValue = 0;
if (dayLength > 0) {
// Check if slot is within daylight period
var isDaylight = is24HourDaylight || (sunrise <= sunset
? hour >= sunrise && hour <= sunset + 1
: hour >= sunrise || hour <= sunset + 1);
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() + slotDuration).toISOString(),
value: Math.round(Math.max(0, solarValue))
});
}
}
JSON.stringify(rates);