diff --git a/go.mod b/go.mod index 7a7a7dc..5a50e74 100644 --- a/go.mod +++ b/go.mod @@ -33,6 +33,7 @@ require ( require ( github.com/inconshreveable/mousetrap v1.1.0 // indirect + github.com/robfig/cron/v3 v3.0.1 github.com/simonvetter/modbus v1.6.0 github.com/spf13/pflag v1.0.5 // indirect github.com/spf13/viper v1.18.2 diff --git a/go.sum b/go.sum index 2540ba5..89b3688 100644 --- a/go.sum +++ b/go.sum @@ -30,6 +30,8 @@ github.com/pelletier/go-toml/v2 v2.1.1/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdU github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs= +github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= diff --git a/home-assistant/addons/sbam/config.json b/home-assistant/addons/sbam/config.json index 1bb77a0..a238342 100644 --- a/home-assistant/addons/sbam/config.json +++ b/home-assistant/addons/sbam/config.json @@ -13,11 +13,12 @@ "apikey": "null", "fronius_ip": "null", "start_hr": "00:00", - "end_hr": "6:00", - "every": "3600", + "end_hr": "06:00", + "crontab": "00 00-05 * * *", "pw_consumption": "11000", "max_charge": "3500", - "pw_batt_reserve": "3000" + "pw_batt_reserve": "3000", + "defaults": "true" }, "schema": { "url": "url", @@ -25,9 +26,10 @@ "fronius_ip": "match(^((25[0-5]|(2[0-4]|1\\d|[1-9]|)\\d)(\\.(?!$)|$)){4}$)", "start_hr": "match(^([01]?[0-9]|2[0-3]):[0-5][0-9]$)", "end_hr": "match(^([01]?[0-9]|2[0-3]):[0-5][0-9]$)", - "every": "int", + "crontab": "match(^((\\*\/[1-5]?[0-9]|(\\*|[1-5]?[0-9]))\\s){4}(\\*\/[1]?[0-9]|(\\*|[1]?[0-9])|(\\*|1[0-2])|(jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec))\\s(\\*\/[0-3]?[0-9]|(\\*|[0-3]?[0-9])|(\\*|l|L|W)?|([1-7]#([1-5]))|(mon|tue|wed|thu|fri|sat|sun))\\s(\\*|\\@reboot|\\@yearly|\\@annually|\\@monthly|\\@weekly|\\@daily|\\@midnight|\\@hourly|[a-zA-Z]+)$)", "pw_consumption": "float", "max_charge": "float", - "pw_batt_reserve": "float" + "pw_batt_reserve": "float", + "defaults": "bool" } } \ No newline at end of file diff --git a/home-assistant/addons/sbam/run.sh b/home-assistant/addons/sbam/run.sh index f3ef953..0891333 100755 --- a/home-assistant/addons/sbam/run.sh +++ b/home-assistant/addons/sbam/run.sh @@ -1,17 +1,14 @@ #!/usr/bin/with-contenv bashio -DEFAULT_LEASE=$(bashio::config 'default_lease') -DOMAIN=$(bashio::config 'domain') -MAX_LEASE=$(bashio::config 'max_lease') - export URL=$(bashio::config 'url') export APIKEY=$(bashio::config 'apikey') -export FRONIUS_IP=$(bashio::config 'pronius_ip') +export FRONIUS_IP=$(bashio::config 'fronius_ip') export START_HR=$(bashio::config 'start_hr') export END_HR=$(bashio::config 'end_hr') -export EVERY=$(bashio::config 'every') +export CRONTAB=$(bashio::config 'crontab') export PW_CONSUMPTION=$(bashio::config 'pw_consumption') export MAX_CHARGE=$(bashio::config 'max_charge') export PW_BATT_RESERVE=$(bashio::config 'pw_batt_reserve') +export DEFAULTS=$(bashio::config 'defaults') sbam schedule \ No newline at end of file diff --git a/pkg/cmd/schedule.go b/pkg/cmd/schedule.go index a4f3b27..a998d71 100644 --- a/pkg/cmd/schedule.go +++ b/pkg/cmd/schedule.go @@ -7,9 +7,11 @@ import ( "sbam/pkg/power" "sbam/pkg/storage" u "sbam/src/utils" + "strconv" "strings" "time" + "github.com/robfig/cron/v3" "github.com/spf13/cobra" "github.com/spf13/viper" ) @@ -27,21 +29,21 @@ var scdCmd = &cobra.Command{ end_hr := viper.GetString("end_hr") max_charge := viper.GetFloat64("max_charge") pw_batt_reserve := viper.GetFloat64("pw_batt_reserve") - every := viper.GetInt("every") + crontab := viper.GetString("crontab") + defaults := viper.GetBool("defaults") - err := checkScheduleschedule(every, apiKey, url, fronius_ip, pw_consumption, max_charge, pw_batt_reserve, start_hr, end_hr) + err := checkScheduleschedule(crontab, apiKey, url, fronius_ip, pw_consumption, max_charge, pw_batt_reserve, start_hr, end_hr) if err != nil { u.Log.Error(err) return } - schedule(apiKey, url, fronius_ip, pw_consumption, max_charge, pw_batt_reserve, start_hr, end_hr) + if crontab != "0 0 0 0 0" { + crontabSchedule(apiKey, url, fronius_ip, pw_consumption, max_charge, pw_batt_reserve, start_hr, end_hr, crontab, defaults) + + } else { + schedule(apiKey, url, fronius_ip, pw_consumption, max_charge, pw_batt_reserve, start_hr, end_hr) - if every > 0 { - tick := time.Tick(time.Duration(every) * time.Second) - for range tick { - schedule(apiKey, url, fronius_ip, pw_consumption, max_charge, pw_batt_reserve, start_hr, end_hr) - } } }, } @@ -51,11 +53,12 @@ func init() { scdCmd.Flags().StringP("apikey", "k", "", "APIKEY") scdCmd.Flags().StringP("fronius_ip", "H", "", "FRONIUS_IP") scdCmd.Flags().StringP("start_hr", "s", "00:00", "START_HR") - scdCmd.Flags().StringP("end_hr", "e", "06:00", "END_HR") - scdCmd.Flags().IntP("every", "t", 0, "EVERY") + scdCmd.Flags().StringP("end_hr", "e", "05:55", "END_HR") + scdCmd.Flags().StringP("crontab", "t", "0 0 0 0 0", "crontab") scdCmd.Flags().Float64P("pw_consumption", "c", 0.0, "PW_CONSUMPTION") scdCmd.Flags().Float64P("max_charge", "m", 3500, "MAX_CHARGE") scdCmd.Flags().Float64P("pw_batt_reserve", "r", 0, "PW_BATT_RESERVE") + scdCmd.Flags().BoolP("defaults", "d", true, "DEFAULTS") viper.BindPFlag("url", scdCmd.Flags().Lookup("url")) viper.BindPFlag("apikey", scdCmd.Flags().Lookup("apikey")) @@ -63,9 +66,10 @@ func init() { viper.BindPFlag("pw_consumption", scdCmd.Flags().Lookup("pw_consumption")) viper.BindPFlag("start_hr", scdCmd.Flags().Lookup("start_hr")) viper.BindPFlag("end_hr", scdCmd.Flags().Lookup("end_hr")) - viper.BindPFlag("every", scdCmd.Flags().Lookup("every")) + viper.BindPFlag("crontab", scdCmd.Flags().Lookup("crontab")) viper.BindPFlag("max_charge", scdCmd.Flags().Lookup("max_charge")) viper.BindPFlag("pw_batt_reserve", scdCmd.Flags().Lookup("pw_batt_reserve")) + viper.BindPFlag("defaults", scdCmd.Flags().Lookup("defaults")) rootCmd.AddCommand(scdCmd) } @@ -114,7 +118,7 @@ func CheckTimeRange(start_hr string, end_hr string) bool { return (now.After(startTime) || now.Equal(startTime)) && (now.Before(endTime) || now.Equal(endTime)) } -func checkScheduleschedule(every int, apiKey string, url string, fronius_ip string, pw_consumption float64, max_charge float64, pw_batt_reserve float64, start_hr string, end_hr string) error { +func checkScheduleschedule(crontab string, apiKey string, url string, fronius_ip string, pw_consumption float64, max_charge float64, pw_batt_reserve float64, start_hr string, end_hr string) error { if len(strings.TrimSpace(fronius_ip)) == 0 { err := errors.New("the --fronius_ip flag must be set") return err @@ -128,12 +132,11 @@ func checkScheduleschedule(every int, apiKey string, url string, fronius_ip stri err := errors.New("start_hr: " + start_hr + " is not before end_hr: " + end_hr) return err } else if !CheckTimeRange(start_hr, end_hr) { - fronius.Setdefaults(fronius_ip) err := errors.New("not in time range: " + start_hr + " <= t <= " + end_hr) return err - } else if every < 0 { - fmt.Printf("every must to be integer > 0 %v", every) - err := errors.New("every must to be integer > 0") + } else if len(crontab) == 0 { + fmt.Printf("the --crontab must be set") + err := errors.New("crontab must to be integer > 0") return err } else if pw_consumption < 0 { err := errors.New("pw_consumption must to be float > 0") @@ -173,3 +176,28 @@ func schedule(apiKey string, url string, fronius_ip string, pw_consumption float panic(err) } } + +func crontabSchedule(apiKey string, url string, fronius_ip string, pw_consumption float64, max_charge float64, pw_batt_reserve float64, start_hr string, end_hr string, crontab string, defaults bool) { + layout := "15:04" + endTime, _ := time.Parse(layout, end_hr) + endTime = endTime.Add(-5 * time.Minute) + end_crontab := strconv.Itoa(endTime.Minute()) + " " + strconv.Itoa(endTime.Hour()) + " * * *" + + c := cron.New() + _, err := c.AddFunc(crontab, func() { + schedule(apiKey, url, fronius_ip, pw_consumption, max_charge, pw_batt_reserve, start_hr, end_hr) + }) + if err != nil { + u.Log.Error(err) + panic(err) + } + if defaults { + _, err = c.AddFunc(end_crontab, func() { + fronius.Setdefaults(fronius_ip) + }) + if err != nil { + u.Log.Error(err) + panic(err) + } + } +}