From 08ddb1bfb2badf9261f99c7c55a1932a7c525e67 Mon Sep 17 00:00:00 2001 From: andig Date: Sun, 26 Jun 2022 23:13:50 +0200 Subject: [PATCH] Add more site apis (#3721) --- core/site.go | 2 + core/site/api.go | 5 ++ core/site_api.go | 40 +++++++++++++++ server/http.go | 15 +++--- server/http_handler.go | 114 +++++++++++++++++------------------------ server/mqtt.go | 12 +++++ 6 files changed, 114 insertions(+), 74 deletions(-) diff --git a/core/site.go b/core/site.go index 707e937ae..40b1c3958 100644 --- a/core/site.go +++ b/core/site.go @@ -429,7 +429,9 @@ func (site *Site) prepare() { site.publish("gridConfigured", site.gridMeter != nil) site.publish("pvConfigured", len(site.pvMeters) > 0) site.publish("batteryConfigured", len(site.batteryMeters) > 0) + site.publish("bufferSoC", site.BufferSoC) site.publish("prioritySoC", site.PrioritySoC) + site.publish("residualPower", site.ResidualPower) site.publish("currency", site.tariffs.Currency.String()) site.publish("savingsSince", site.savings.Since().Unix()) diff --git a/core/site/api.go b/core/site/api.go index 83962dcd6..bb15686a8 100644 --- a/core/site/api.go +++ b/core/site/api.go @@ -6,5 +6,10 @@ import "github.com/evcc-io/evcc/core/loadpoint" type API interface { Healthy() bool LoadPoints() []loadpoint.API + GetBufferSoC() float64 + SetBufferSoC(float64) error + GetPrioritySoC() float64 SetPrioritySoC(float64) error + GetResidualPower() float64 + SetResidualPower(float64) error } diff --git a/core/site_api.go b/core/site_api.go index 843799cd3..b15969fa6 100644 --- a/core/site_api.go +++ b/core/site_api.go @@ -29,3 +29,43 @@ func (site *Site) SetPrioritySoC(soc float64) error { return nil } + +// GetBufferSoC returns the BufferSoC +func (site *Site) GetBufferSoC() float64 { + site.Lock() + defer site.Unlock() + return site.BufferSoC +} + +// SetBufferSoC sets the BufferSoC +func (site *Site) SetBufferSoC(soc float64) error { + site.Lock() + defer site.Unlock() + + if len(site.batteryMeters) == 0 { + return errors.New("battery not configured") + } + + site.BufferSoC = soc + site.publish("bufferSoC", site.BufferSoC) + + return nil +} + +// GetResidualPower returns the ResidualPower +func (site *Site) GetResidualPower() float64 { + site.Lock() + defer site.Unlock() + return site.ResidualPower +} + +// SetResidualPower sets the ResidualPower +func (site *Site) SetResidualPower(power float64) error { + site.Lock() + defer site.Unlock() + + site.ResidualPower = power + site.publish("residualPower", site.ResidualPower) + + return nil +} diff --git a/server/http.go b/server/http.go index bd457a9b5..ae3f873ac 100644 --- a/server/http.go +++ b/server/http.go @@ -44,8 +44,11 @@ type HTTPd struct { // NewHTTPd creates HTTP server with configured routes for loadpoint func NewHTTPd(addr string, site site.API, hub *SocketHub, cache *util.Cache) *HTTPd { routes := map[string]route{ - "health": {[]string{"GET"}, "/health", healthHandler(site)}, - "state": {[]string{"GET"}, "/state", stateHandler(cache)}, + "health": {[]string{"GET"}, "/health", healthHandler(site)}, + "state": {[]string{"GET"}, "/state", stateHandler(cache)}, + "buffersoc": {[]string{"POST", "OPTIONS"}, "/buffersoc/{value:[0-9.]+}", floatHandler(site.SetBufferSoC, site.GetBufferSoC)}, + "prioritysoc": {[]string{"POST", "OPTIONS"}, "/prioritysoc/{value:[0-9.]+}", floatHandler(site.SetPrioritySoC, site.GetPrioritySoC)}, + "residualpower": {[]string{"POST", "OPTIONS"}, "/residualpower/{value:[0-9.]+}", floatHandler(site.SetResidualPower, site.GetResidualPower)}, } router := mux.NewRouter().StrictSlash(true) @@ -81,10 +84,10 @@ func NewHTTPd(addr string, site site.API, hub *SocketHub, cache *util.Cache) *HT routes := map[string]route{ "mode": {[]string{"POST", "OPTIONS"}, "/mode/{value:[a-z]+}", chargeModeHandler(lp)}, - "targetsoc": {[]string{"POST", "OPTIONS"}, "/targetsoc/{value:[0-9]+}", targetSoCHandler(lp)}, - "minsoc": {[]string{"POST", "OPTIONS"}, "/minsoc/{value:[0-9]+}", minSoCHandler(lp)}, - "mincurrent": {[]string{"POST", "OPTIONS"}, "/mincurrent/{value:[0-9]+}", minCurrentHandler(lp)}, - "maxcurrent": {[]string{"POST", "OPTIONS"}, "/maxcurrent/{value:[0-9]+}", maxCurrentHandler(lp)}, + "targetsoc": {[]string{"POST", "OPTIONS"}, "/targetsoc/{value:[0-9]+}", intHandler(pass(lp.SetTargetSoC), lp.GetTargetSoC)}, + "minsoc": {[]string{"POST", "OPTIONS"}, "/minsoc/{value:[0-9]+}", intHandler(pass(lp.SetMinSoC), lp.GetMinSoC)}, + "mincurrent": {[]string{"POST", "OPTIONS"}, "/mincurrent/{value:[0-9]+}", floatHandler(pass(lp.SetMinCurrent), lp.GetMinCurrent)}, + "maxcurrent": {[]string{"POST", "OPTIONS"}, "/maxcurrent/{value:[0-9]+}", floatHandler(pass(lp.SetMaxCurrent), lp.GetMaxCurrent)}, "phases": {[]string{"POST", "OPTIONS"}, "/phases/{value:[0-9]+}", phasesHandler(lp)}, "targetcharge": {[]string{"POST", "OPTIONS"}, "/targetcharge/{soc:[0-9]+}/{time:[0-9TZ:.-]+}", targetChargeHandler(lp)}, "targetcharge2": {[]string{"DELETE", "OPTIONS"}, "/targetcharge", targetChargeRemoveHandler(lp)}, diff --git a/server/http_handler.go b/server/http_handler.go index 2976ff5ec..c03debf60 100644 --- a/server/http_handler.go +++ b/server/http_handler.go @@ -80,6 +80,52 @@ func healthHandler(site site.API) http.HandlerFunc { } } +// pass converts a simple api without return value to api with nil error return value +func pass[T any](f func(T)) func(T) error { + return func(v T) error { + f(v) + return nil + } +} + +// floatHandler updates float-param api +func floatHandler(set func(float64) error, get func() float64) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + + val, err := strconv.ParseFloat(vars["value"], 64) + if err == nil { + err = set(val) + } + + if err != nil { + jsonError(w, http.StatusBadRequest, err) + return + } + + jsonResult(w, get()) + } +} + +// intHandler updates int-param api +func intHandler(set func(int) error, get func() int) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + + val, err := strconv.ParseInt(vars["value"], 10, 32) + if err == nil { + err = set(int(val)) + } + + if err != nil { + jsonError(w, http.StatusBadRequest, err) + return + } + + jsonResult(w, get()) + } +} + // stateHandler returns current charge mode func stateHandler(cache *util.Cache) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { @@ -108,74 +154,6 @@ func chargeModeHandler(lp loadpoint.API) http.HandlerFunc { } } -// targetSoCHandler updates target soc -func targetSoCHandler(lp loadpoint.API) http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { - vars := mux.Vars(r) - - soc, err := strconv.ParseInt(vars["value"], 10, 32) - if err == nil { - lp.SetTargetSoC(int(soc)) - } else { - jsonError(w, http.StatusBadRequest, err) - return - } - - jsonResult(w, lp.GetTargetSoC()) - } -} - -// minSoCHandler updates minimum soc -func minSoCHandler(lp loadpoint.API) http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { - vars := mux.Vars(r) - - soc, err := strconv.ParseInt(vars["value"], 10, 32) - if err == nil { - lp.SetMinSoC(int(soc)) - } else { - jsonError(w, http.StatusBadRequest, err) - return - } - - jsonResult(w, lp.GetMinSoC()) - } -} - -// minCurrentHandler updates minimum current -func minCurrentHandler(lp loadpoint.API) http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { - vars := mux.Vars(r) - - current, err := strconv.ParseFloat(vars["value"], 64) - if err == nil { - lp.SetMinCurrent(current) - } else { - jsonError(w, http.StatusBadRequest, err) - return - } - - jsonResult(w, lp.GetMinCurrent()) - } -} - -// maxCurrentHandler updates maximum current -func maxCurrentHandler(lp loadpoint.API) http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { - vars := mux.Vars(r) - - current, err := strconv.ParseFloat(vars["value"], 64) - if err == nil { - lp.SetMaxCurrent(current) - } else { - jsonError(w, http.StatusBadRequest, err) - return - } - - jsonResult(w, lp.GetMaxCurrent()) - } -} - // phasesHandler updates minimum soc func phasesHandler(lp loadpoint.API) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { diff --git a/server/mqtt.go b/server/mqtt.go index 5126cea43..eb4cc3db6 100644 --- a/server/mqtt.go +++ b/server/mqtt.go @@ -109,6 +109,18 @@ func (m *MQTT) Run(site site.API, in <-chan util.Param) { } }) + m.Handler.ListenSetter(fmt.Sprintf("%s/site/bufferSoC/set", m.root), func(payload string) { + if soc, err := strconv.Atoi(payload); err == nil { + _ = site.SetBufferSoC(float64(soc)) + } + }) + + m.Handler.ListenSetter(fmt.Sprintf("%s/site/residualPower/set", m.root), func(payload string) { + if soc, err := strconv.Atoi(payload); err == nil { + _ = site.SetResidualPower(float64(soc)) + } + }) + // number of loadpoints topic = fmt.Sprintf("%s/loadpoints", m.root) m.publish(topic, true, len(site.LoadPoints()))