marginal fuel
This commit is contained in:
parent
e9aa9b7d27
commit
28437325f9
5 changed files with 180 additions and 21 deletions
3
go.mod
3
go.mod
|
@ -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
6
go.sum
|
@ -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=
|
||||
|
|
|
@ -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),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue