From 697bc88a62dc0db0a0be7bf5d8ae19149a38336e Mon Sep 17 00:00:00 2001 From: andig Date: Fri, 25 Aug 2023 17:41:42 +0200 Subject: [PATCH] Guard soc against invalid values (#9532) --- core/loadpoint_charger.go | 3 ++- core/site.go | 3 ++- core/soc/estimator.go | 4 ++-- core/soc/helper.go | 20 ++++++++++++++++++++ 4 files changed, 26 insertions(+), 4 deletions(-) create mode 100644 core/soc/helper.go diff --git a/core/loadpoint_charger.go b/core/loadpoint_charger.go index 3ad488e8fd..07e142fc93 100644 --- a/core/loadpoint_charger.go +++ b/core/loadpoint_charger.go @@ -4,6 +4,7 @@ import ( "slices" "github.com/evcc-io/evcc/api" + "github.com/evcc-io/evcc/core/soc" ) // chargerHasFeature checks availability of charger feature @@ -27,7 +28,7 @@ func (lp *Loadpoint) publishChargerFeature(f api.Feature) { // chargerSoc returns charger soc if available func (lp *Loadpoint) chargerSoc() (float64, error) { if c, ok := lp.charger.(api.Battery); ok { - return c.Soc() + return soc.Guard(c.Soc()) } return 0, api.ErrNotAvailable } diff --git a/core/site.go b/core/site.go index 7de648808f..56d5d4d03a 100644 --- a/core/site.go +++ b/core/site.go @@ -15,6 +15,7 @@ import ( "github.com/evcc-io/evcc/core/planner" "github.com/evcc-io/evcc/core/prioritizer" "github.com/evcc-io/evcc/core/session" + "github.com/evcc-io/evcc/core/soc" "github.com/evcc-io/evcc/push" "github.com/evcc-io/evcc/server/db" "github.com/evcc-io/evcc/server/db/settings" @@ -483,7 +484,7 @@ func (site *Site) updateMeters() error { // battery soc and capacity var capacity float64 - soc, err := meter.(api.Battery).Soc() + soc, err := soc.Guard(meter.(api.Battery).Soc()) if err == nil { // weigh soc by capacity and accumulate total capacity diff --git a/core/soc/estimator.go b/core/soc/estimator.go index a159ef224f..0558ce238e 100644 --- a/core/soc/estimator.go +++ b/core/soc/estimator.go @@ -107,7 +107,7 @@ func (s *Estimator) Soc(chargedEnergy float64) (float64, error) { var fetchedSoc *float64 if charger, ok := s.charger.(api.Battery); ok { - f, err := charger.Soc() + f, err := Guard(charger.Soc()) // if the charger does or could provide Soc, we always use it instead of using the vehicle API if err == nil || !errors.Is(err, api.ErrNotAvailable) { @@ -128,7 +128,7 @@ func (s *Estimator) Soc(chargedEnergy float64) (float64, error) { } if fetchedSoc == nil { - f, err := s.vehicle.Soc() + f, err := Guard(s.vehicle.Soc()) if err != nil { // required for online APIs with refreshkey if errors.Is(err, api.ErrMustRetry) { diff --git a/core/soc/helper.go b/core/soc/helper.go new file mode 100644 index 0000000000..45bf0f6ddc --- /dev/null +++ b/core/soc/helper.go @@ -0,0 +1,20 @@ +package soc + +import "fmt" + +// Guard checks soc value for validity +func Guard(soc float64, err error) (float64, error) { + switch { + case err != nil: + return soc, err + + case soc < 0: + return 0, fmt.Errorf("invalid soc: %.1f", soc) + + case soc > 100: + return 100, fmt.Errorf("invalid soc: %.1f", soc) + + default: + return soc, nil + } +}