112 lines
3.5 KiB
YAML
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);
|