evcc-io/tariff/slots.go

64 lines
1.4 KiB
Go

package tariff
import (
"time"
"github.com/evcc-io/evcc/api"
)
const SlotDuration = 15 * time.Minute
type SlotWrapper struct {
api.Tariff
}
// Rates converts arbitrary slot lengths (e.g. 1h, 30m) to 15m slots.
// Slot length must be multiple of SlotDuration.
// For price tariffs, the value is constant over all sub-slots.
// For solar/co2, linear interpolation is used between slot boundaries.
func (t *SlotWrapper) Rates() (api.Rates, error) {
rates, err := t.Tariff.Rates()
if err != nil {
return nil, err
}
var res api.Rates
if len(rates) > 0 {
// assume all slots of equal length
res = make(api.Rates, 0, len(rates)*max(int(rates[0].End.Sub(rates[0].Start)/SlotDuration), 1))
}
now := time.Now().Truncate(SlotDuration)
for i, r := range rates {
if !r.End.After(now) { // only keep slots >= now
continue
}
numSlots := max(int(r.End.Sub(r.Start)/SlotDuration), 1)
for j := range numSlots {
start := r.Start.Add(time.Duration(j) * SlotDuration)
end := start.Add(SlotDuration)
val := r.Value
switch t.Type() {
case api.TariffTypeSolar: //, api.TariffTypeCo2
if i+1 < len(rates) {
start0 := r.Start
start1 := rates[i+1].Start
frac := float64(start.Sub(start0)) / float64(start1.Sub(start0))
val = r.Value + frac*(rates[i+1].Value-r.Value)
}
}
res = append(res, api.Rate{
Start: start,
End: end,
Value: val,
})
}
}
return res, nil
}