energyd/pkg/energy/energy.go

184 lines
3.2 KiB
Go
Raw Normal View History

2022-06-25 22:13:35 -04:00
package energy
import (
2022-07-02 13:19:33 -04:00
"context"
2022-06-25 22:13:35 -04:00
"fmt"
2023-02-03 01:01:33 -05:00
"log"
2022-06-25 22:13:35 -04:00
"math"
2023-02-03 01:01:33 -05:00
"strings"
2022-06-25 22:13:35 -04:00
"time"
"github.com/amigan/energyd/pkg/isoclient"
2023-02-03 01:01:33 -05:00
"github.com/lucasb-eyer/go-colorful"
"github.com/mazznoer/colorgrad"
2022-06-25 22:13:35 -04:00
)
2022-07-02 13:19:33 -04:00
type Energy struct {
iso isoclient.Client
}
2022-06-25 22:13:35 -04:00
type LoadProfile struct {
2023-02-03 01:01:33 -05:00
Time time.Time
Current int
Peak int
Lowest int
PeakHr int
2022-06-25 22:13:35 -04:00
LowestHr int
2023-02-03 01:01:33 -05:00
PctPeak int
HoursAway int
HighFuel string
MarginalFuels MarginalFuels
2022-06-25 22:13:35 -04:00
}
2023-02-03 01:01:33 -05:00
type MarginalFuels []string
func (mf MarginalFuels) String() string {
return strings.Join(mf, ", ")
}
func (e *Energy) Compute() error {
2022-07-02 13:19:33 -04:00
ic := e.iso
2022-06-25 22:13:35 -04:00
load, err := ic.GetCurrentLoad()
if err != nil {
2023-02-03 01:01:33 -05:00
return err
2022-06-25 22:13:35 -04:00
}
gphd, err := ic.GetHourlyLoadForecast()
if err != nil {
2023-02-03 01:01:33 -05:00
return err
}
fm, err := ic.GetGenFuelMixes()
if err != nil {
return err
2022-06-25 22:13:35 -04:00
}
lp := LoadProfile{
2023-02-03 01:01:33 -05:00
Time: load.BeginDate,
Current: int(load.LoadMW),
2022-06-25 22:13:35 -04:00
LowestHr: -1,
}
2023-02-03 01:01:33 -05:00
if len(fm) > 0 {
highGen := int(fm[0].GenMW)
highFuel := fm[0]
for _, mix := range fm {
if int(mix.GenMW) > highGen {
highGen = int(mix.GenMW)
highFuel = mix
}
if mix.Marginal {
lp.MarginalFuels = append(lp.MarginalFuels, mix.FuelCategory)
}
}
lp.HighFuel = highFuel.FuelCategory
}
2022-06-25 22:13:35 -04:00
for h, hf := range gphd.HourlyLoadForecast {
if int(hf.LoadMW) > lp.Peak {
lp.Peak = int(hf.LoadMW)
lp.PeakHr = h
}
if int(hf.LoadMW) < lp.Lowest || lp.LowestHr == -1 {
lp.LowestHr = h
lp.Lowest = int(hf.LoadMW)
}
}
hour := time.Now().Hour()
2023-02-03 01:01:33 -05:00
lp.PctPeak = int(float32(load.LoadMW/float32(lp.Peak)) * 100)
2022-06-25 22:13:35 -04:00
lp.HoursAway = int(math.Abs(float64(hour) - float64(lp.PeakHr)))
2023-02-03 01:01:33 -05:00
fmt.Println(lp.String())
return nil
}
type Colors struct {
Mix [2]colorful.Color
Peak [2]colorful.Color
}
func vaporwavePalette() []string {
return []string{
"#01cdfe", // blue
"#05ffa1", // green
"#fffb96", // gold
"#ff71ce", // pinkred
"#b967ff", // purple
}
}
func outrunPalette() []string {
return []string{
"#2de2e6", // blue
"#00ff1b", // green
"#ff6c11", // gold
"#ff3864", // pinkred
"#7930ff", // purple
}
}
func (lp *LoadProfile) PeakScaleColors() []string {
var scale []string
palette := outrunPalette()
nowHr := time.Now().Hour() // XXX: get this from lp
//if lp.HoursAway >
_, _ = palette, nowHr
return scale
}
func (lp *LoadProfile) String() string {
return fmt.Sprintf("%s\tC: %d\tP: %d\tL: %d\tPeakHr: %d\tLowestHr: %d\t%%Pk: %d\tHrAway: %d\tPkFuel: %s\tMarginal: %s",
lp.Time.String(), lp.Current, lp.Peak, lp.Lowest, lp.PeakHr, lp.LowestHr, lp.PctPeak, lp.HoursAway, lp.HighFuel, lp.MarginalFuels)
}
func (lp *LoadProfile) Colors() Colors {
c := Colors{}
peak, err := colorgrad.NewGradient().Domain(float64(lp.Lowest), float64(lp.Peak)).HtmlColors(lp.PeakScaleColors()...).Build()
if err != nil {
panic(err)
}
c.Peak[0] = peak.At(float64(time.Now().Hour()))
return c
2022-07-02 13:19:33 -04:00
}
2022-06-25 22:13:35 -04:00
2022-07-02 13:19:33 -04:00
func (e *Energy) Go(ctx context.Context) {
2023-02-03 01:01:33 -05:00
tick := time.NewTicker(time.Minute * 15)
err := e.Compute()
if err != nil {
log.Println(err)
}
2022-07-02 13:19:33 -04:00
for {
select {
case <-tick.C:
2023-02-03 01:01:33 -05:00
err := e.Compute()
if err != nil {
log.Println(err)
}
2022-07-02 13:19:33 -04:00
case <-ctx.Done():
return
}
}
}
func New(ic isoclient.Client) *Energy {
return &Energy{
iso: ic,
}
2022-06-25 22:13:35 -04:00
}