Add more site apis (#3721)

This commit is contained in:
andig 2022-06-26 23:13:50 +02:00 • committed by GitHub
parent 1ad8d44a73
commit 08ddb1bfb2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 114 additions and 74 deletions

View file

@ -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())

View file

@ -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
}

View file

@ -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
}

View file

@ -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)},

View file

@ -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) {

View file

@ -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()))