marginal fuel

This commit is contained in:
Daniel 2023-02-03 01:01:33 -05:00
parent e9aa9b7d27
commit 28437325f9
5 changed files with 180 additions and 21 deletions

3
go.mod
View file

@ -5,7 +5,10 @@ go 1.18
require (
github.com/fsnotify/fsnotify v1.5.4 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
github.com/magiconair/properties v1.8.6 // indirect
github.com/mazznoer/colorgrad v0.9.0 // indirect
github.com/mazznoer/csscolorparser v0.1.2 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/pelletier/go-toml v1.9.5 // indirect
github.com/pelletier/go-toml/v2 v2.0.1 // indirect

6
go.sum
View file

@ -126,8 +126,14 @@ github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
github.com/magiconair/properties v1.8.6 h1:5ibWZ6iY0NctNGWo87LalDlEZ6R41TqbbDamhfG/Qzo=
github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
github.com/mazznoer/colorgrad v0.9.0 h1:C3Y0l0oIJhXLcbmIRxgmBSUAus4np1t/gUFt7fHukDA=
github.com/mazznoer/colorgrad v0.9.0/go.mod h1:WX2R9wt9B47+txJZVVpM9LY+LAGIdi4lTI5wIyreDH4=
github.com/mazznoer/csscolorparser v0.1.2 h1:/UBHuQg792ePmGFzTQAC9u+XbFr7/HzP/Gj70Phyz2A=
github.com/mazznoer/csscolorparser v0.1.2/go.mod h1:Aj22+L/rYN/Y6bj3bYqO3N6g1dtdHtGfQ32xZ5PJQic=
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8=

View file

@ -6,7 +6,7 @@ import (
)
type Conf struct {
ISOUser string
ISOUser string
ISOPassword string
}
@ -15,13 +15,12 @@ func Config() *Conf {
viper.SetConfigType("yaml")
viper.AddConfigPath(".")
err := viper.ReadInConfig() // Find and read the config file
if err != nil { // Handle errors reading the config file
if err != nil { // Handle errors reading the config file
panic(fmt.Errorf("fatal error config file: %w", err))
}
return &Conf{
ISOUser: viper.Get("iso.user").(string),
ISOUser: viper.Get("iso.user").(string),
ISOPassword: viper.Get("iso.password").(string),
}
}

View file

@ -3,10 +3,14 @@ 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 {
@ -14,34 +18,67 @@ type Energy struct {
}
type LoadProfile struct {
Current int
Peak int
Lowest int
PeakHr int
Time time.Time
Current int
Peak int
Lowest int
PeakHr int
LowestHr int
PctPeak int
HoursAway int
PctPeak int
HoursAway int
HighFuel string
MarginalFuels MarginalFuels
}
func (e *Energy) Compute() {
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 {
panic(err)
return err
}
gphd, err := ic.GetHourlyLoadForecast()
if err != nil {
panic(err)
return err
}
fm, err := ic.GetGenFuelMixes()
if err != nil {
return err
}
lp := LoadProfile{
Current: int(load.LoadMW),
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)
@ -54,21 +91,85 @@ func (e *Energy) Compute() {
}
}
hour := time.Now().Hour()
lp.PctPeak = int(float32(load.LoadMW / float32(lp.Peak)) * 100)
lp.PctPeak = int(float32(load.LoadMW/float32(lp.Peak)) * 100)
lp.HoursAway = int(math.Abs(float64(hour) - float64(lp.PeakHr)))
fmt.Printf("lp %#v\n", lp)
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)
e.Compute()
tick := time.NewTicker(time.Minute * 15)
err := e.Compute()
if err != nil {
log.Println(err)
}
for {
select {
case <-tick.C:
e.Compute()
err := e.Compute()
if err != nil {
log.Println(err)
}
case <-ctx.Done():
return
}

View file

@ -7,6 +7,8 @@ import (
"io/ioutil"
"log"
"net/http"
"os"
"strings"
"time"
"github.com/amigan/energyd/internal/config"
@ -15,6 +17,7 @@ import (
type Client interface {
GetCurrentLoad() (*FiveMinSystemLoad, error)
GetHourlyLoadForecast() (*HourlyLoadForecasts, error)
GetGenFuelMixes() (GenFuelMixes, error)
}
type client struct {
@ -27,6 +30,7 @@ func New(cfg *config.Conf) Client {
c := &client{
user: cfg.ISOUser,
passwd: cfg.ISOPassword,
Debug: os.Getenv("DEBUG") == "true",
}
return c
@ -122,3 +126,49 @@ func (c *client) GetHourlyLoadForecast() (*HourlyLoadForecasts, error) {
return &hlfc.HourlyLoadForecasts, nil
}
type GenFuelMix struct {
BeginDate time.Time `json:"BeginDate"`
GenMW float32 `json:"GenMW"`
FuelCategoryRollup string `json:"FuelCategoryRollup"`
FuelCategory string `json:"FuelCategory"`
Marginal YNFlag `json:"MarginalFlag"`
}
type YNFlag bool
func (ynf *YNFlag) UnmarshalJSON(b []byte) error {
var s string
err := json.Unmarshal(b, &s)
if err != nil {
return err
}
switch strings.ToLower(s) {
case "y":
*ynf = true
case "n":
*ynf = false
}
return nil
}
type GenFuelMixes []GenFuelMix
const GETGENFUELMIXES = "/genfuelmix/current"
func (c *client) GetGenFuelMixes() (GenFuelMixes, error) {
var fm struct {
GenFuelMixes struct {
GenFuelMix GenFuelMixes `json:"GenFuelMix"`
} `json:"GenFuelMixes"`
}
err := c.makeRequest(GETGENFUELMIXES, &fm)
if err != nil {
return nil, err
}
return fm.GenFuelMixes.GenFuelMix, nil
}