Discriminate between mode empty and invalid (#1410)

This commit is contained in:
andig 2021-08-22 20:03:55 +02:00 • committed by GitHub
parent 77552ad722
commit 8834e26adf
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 47 additions and 27 deletions

View file

@ -9,6 +9,7 @@ type ChargeMode string
// Charge modes
const (
ModeEmpty ChargeMode = ""
ModeOff ChargeMode = "off"
ModeNow ChargeMode = "now"
ModeMinPV ChargeMode = "minpv"

View file

@ -1,19 +1,38 @@
package api
import "strings"
import (
"encoding"
"fmt"
"strings"
)
// ChargeModeString converts string to ChargeMode
func ChargeModeString(mode string) ChargeMode {
func ChargeModeString(mode string) (ChargeMode, error) {
switch strings.ToLower(mode) {
case string(ModeEmpty):
return ModeEmpty, nil // undefined
case string(ModeNow):
return ModeNow
return ModeNow, nil
case string(ModeMinPV):
return ModeMinPV
return ModeMinPV, nil
case string(ModePV):
return ModePV
return ModePV, nil
case string(ModeOff):
return ModeOff
return ModeOff, nil
default:
return ""
return "", fmt.Errorf("invalid value: %s", mode)
}
}
var _ encoding.TextUnmarshaler = (*ChargeMode)(nil)
func (c *ChargeMode) UnmarshalText(text []byte) error {
casted, err := ChargeModeString(string(text))
if err != nil {
return err
}
*c = casted
return nil
}

View file

@ -142,10 +142,6 @@ func NewLoadPointFromConfig(log *util.Logger, cp configProvider, other map[strin
return nil, err
}
// set sane defaults
lp.Mode = api.ChargeModeString(string(lp.Mode))
lp.OnDisconnect.Mode = api.ChargeModeString(string(lp.OnDisconnect.Mode))
// set vehicle polling mode
switch lp.SoC.Poll.Mode = strings.ToLower(lp.SoC.Poll.Mode); lp.SoC.Poll.Mode {
case pollCharging:
@ -401,7 +397,7 @@ func (lp *LoadPoint) evChargeCurrentWrappedMeterHandler(current float64) {
// applyAction executes the action
func (lp *LoadPoint) applyAction(action ActionConfig) {
if action.Mode != "" && lp.GetMode() != api.ModeOff {
if action.Mode != "" && lp.GetMode() != api.ModeEmpty {
lp.SetMode(action.Mode)
}
if action.TargetSoC != 0 {

View file

@ -167,11 +167,12 @@ func ChargeModeHandler(loadpoint core.LoadPointAPI) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
modeS, ok := vars["mode"]
mode := api.ChargeModeString(modeS)
if mode == "" || string(mode) != modeS || !ok {
modeS := vars["mode"]
mode, err := api.ChargeModeString(modeS)
if err != nil {
w.WriteHeader(http.StatusBadRequest)
jsonResponse(w, r, errorJSON{Error: "invalid mode"})
jsonResponse(w, r, errorJSON{Error: err.Error()})
return
}
@ -195,14 +196,14 @@ func TargetSoCHandler(loadpoint core.LoadPointAPI) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
socS, ok := vars["soc"]
socS := vars["soc"]
soc, err := strconv.ParseInt(socS, 10, 32)
if ok && err == nil {
if err == nil {
err = loadpoint.SetTargetSoC(int(soc))
}
if !ok || err != nil {
if err != nil {
w.WriteHeader(http.StatusBadRequest)
jsonResponse(w, r, errorJSON{Error: err.Error()})
return
@ -226,14 +227,14 @@ func MinSoCHandler(loadpoint core.LoadPointAPI) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
socS, ok := vars["soc"]
socS := vars["soc"]
soc, err := strconv.ParseInt(socS, 10, 32)
if ok && err == nil {
if err == nil {
err = loadpoint.SetMinSoC(int(soc))
}
if !ok || err != nil {
if err != nil {
w.WriteHeader(http.StatusBadRequest)
jsonResponse(w, r, errorJSON{Error: err.Error()})
return
@ -257,14 +258,14 @@ func PhasesHandler(loadpoint core.LoadPointAPI) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
phasesS, ok := vars["phases"]
phasesS := vars["phases"]
phases, err := strconv.ParseInt(phasesS, 10, 32)
if ok && err == nil {
if err == nil {
err = loadpoint.SetPhases(int(phases))
}
if !ok || err != nil {
if err != nil {
w.WriteHeader(http.StatusBadRequest)
jsonResponse(w, r, errorJSON{Error: err.Error()})
return
@ -418,7 +419,7 @@ func NewHTTPd(url string, site core.SiteAPI, hub *SocketHub, cache *util.Cache)
"getphases": {[]string{"GET"}, "/phases", CurrentPhasesHandler(lp)},
"setphases": {[]string{"POST", "OPTIONS"}, "/phases/{phases:[0-9]+}", PhasesHandler(lp)},
"settargetcharge": {[]string{"POST", "OPTIONS"}, "/targetcharge/{soc:[0-9]+}/{time:[0-9TZ:-]+}", TargetChargeHandler(lp)},
"remotedemand": {[]string{"POST", "OPTIONS"}, "/remotedemand/{demand:[a-z]+}/{source}", RemoteDemandHandler(lp)},
"remotedemand": {[]string{"POST", "OPTIONS"}, "/remotedemand/{demand:[a-z]+}/{source::[0-9a-zA-Z_-]+}", RemoteDemandHandler(lp)},
}
for _, r := range routes {

View file

@ -10,7 +10,10 @@ func DecodeOther(other interface{}, cc interface{}) error {
Result: cc,
ErrorUnused: true,
WeaklyTypedInput: true,
DecodeHook: mapstructure.StringToTimeDurationHookFunc(),
DecodeHook: mapstructure.ComposeDecodeHookFunc(
mapstructure.StringToTimeDurationHookFunc(),
mapstructure.TextUnmarshallerHookFunc(),
),
}
decoder, err := mapstructure.NewDecoder(decoderConfig)