energyd/pkg/energy/energy.go
2023-02-03 01:01:33 -05:00

183 lines
3.2 KiB
Go

package energy
import (
"context"
"fmt"
"log"
"math"
"strings"
"time"
"github.com/amigan/energyd/pkg/isoclient"
"github.com/lucasb-eyer/go-colorful"
"github.com/mazznoer/colorgrad"
)
type Energy struct {
iso isoclient.Client
}
type LoadProfile struct {
Time time.Time
Current int
Peak int
Lowest int
PeakHr int
LowestHr int
PctPeak int
HoursAway int
HighFuel string
MarginalFuels MarginalFuels
}
type MarginalFuels []string
func (mf MarginalFuels) String() string {
return strings.Join(mf, ", ")
}
func (e *Energy) Compute() error {
ic := e.iso
load, err := ic.GetCurrentLoad()
if err != nil {
return err
}
gphd, err := ic.GetHourlyLoadForecast()
if err != nil {
return err
}
fm, err := ic.GetGenFuelMixes()
if err != nil {
return err
}
lp := LoadProfile{
Time: load.BeginDate,
Current: int(load.LoadMW),
LowestHr: -1,
}
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
}
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()
lp.PctPeak = int(float32(load.LoadMW/float32(lp.Peak)) * 100)
lp.HoursAway = int(math.Abs(float64(hour) - float64(lp.PeakHr)))
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
}
func (e *Energy) Go(ctx context.Context) {
tick := time.NewTicker(time.Minute * 15)
err := e.Compute()
if err != nil {
log.Println(err)
}
for {
select {
case <-tick.C:
err := e.Compute()
if err != nil {
log.Println(err)
}
case <-ctx.Done():
return
}
}
}
func New(ic isoclient.Client) *Energy {
return &Energy{
iso: ic,
}
}