From 6b1b8bf8ae07709b7c227ff62b614cf683152d55 Mon Sep 17 00:00:00 2001 From: andig Date: Tue, 27 Feb 2024 21:46:49 +0100 Subject: [PATCH] Retry pv meter reads on error (#12514) --- core/helper.go | 10 ++++++++++ core/site.go | 35 +++++++++++++---------------------- 2 files changed, 23 insertions(+), 22 deletions(-) diff --git a/core/helper.go b/core/helper.go index e03a7f19f..471523d2a 100644 --- a/core/helper.go +++ b/core/helper.go @@ -1,6 +1,9 @@ package core import ( + "time" + + "github.com/cenkalti/backoff/v4" "github.com/evcc-io/evcc/util" ) @@ -12,6 +15,13 @@ var ( Voltage float64 ) +// bo returns an exponential backoff for reading meter power quickly +func bo() *backoff.ExponentialBackOff { + bo := backoff.NewExponentialBackOff() + bo.MaxElapsedTime = time.Second + return bo +} + // powerToCurrent is a helper function to convert power to per-phase current func powerToCurrent(power float64, phases int) float64 { if Voltage == 0 { diff --git a/core/site.go b/core/site.go index 12d8b1cfa..81487ea19 100644 --- a/core/site.go +++ b/core/site.go @@ -400,9 +400,9 @@ func (site *Site) publishDelta(key string, val interface{}) { } // updatePvMeters updates pv meters. All measurements are optional. -func (site *Site) updatePvMeters() { +func (site *Site) updatePvMeters() error { if len(site.pvMeters) == 0 { - return + return nil } var totalEnergy float64 @@ -413,8 +413,7 @@ func (site *Site) updatePvMeters() { for i, meter := range site.pvMeters { // pv power - power, err := meter.CurrentPower() - + power, err := backoff.RetryWithData(meter.CurrentPower, bo()) if err == nil { // ignore negative values which represent self-consumption site.pvPower += max(0, power) @@ -422,8 +421,8 @@ func (site *Site) updatePvMeters() { site.log.WARN.Printf("pv %d power: %.0fW is negative - check configuration if sign is correct", i+1, power) } } else { - err = fmt.Errorf("pv %d power: %v", i+1, err) - site.log.ERROR.Println(err) + // power is required- return on error + return fmt.Errorf("pv %d power: %v", i+1, err) } // pv energy (production) @@ -447,6 +446,8 @@ func (site *Site) updatePvMeters() { site.publish(keys.PvPower, site.pvPower) site.publish(keys.PvEnergy, totalEnergy) site.publish(keys.Pv, mm) + + return nil } // updateBatteryMeters updates battery meters. Power is retried, other measurements are optional. @@ -455,9 +456,6 @@ func (site *Site) updateBatteryMeters() error { return nil } - bo := backoff.NewExponentialBackOff() - bo.MaxElapsedTime = time.Second - var totalCapacity, totalEnergy float64 site.batteryPower = 0 @@ -466,9 +464,7 @@ func (site *Site) updateBatteryMeters() error { mm := make([]batteryMeasurement, len(site.batteryMeters)) for i, meter := range site.batteryMeters { - bo.Reset() - - power, err := backoff.RetryWithData(meter.CurrentPower, bo) + power, err := backoff.RetryWithData(meter.CurrentPower, bo()) if err == nil { site.batteryPower += power if len(site.batteryMeters) > 1 { @@ -549,10 +545,7 @@ func (site *Site) updateGridMeter() error { return nil } - bo := backoff.NewExponentialBackOff() - bo.MaxElapsedTime = time.Second - - res, err := backoff.RetryWithData(site.gridMeter.CurrentPower, bo) + res, err := backoff.RetryWithData(site.gridMeter.CurrentPower, bo()) if err == nil { site.gridPower = res site.log.DEBUG.Printf("grid meter: %.0fW", res) @@ -601,15 +594,13 @@ func (site *Site) updateGridMeter() error { // updateMeter updates and publishes single meter func (site *Site) updateMeters() error { - // errors ignored - site.updatePvMeters() - - // power errors returned + // TODO parallelize once modbus supports that + if err := site.updatePvMeters(); err != nil { + return err + } if err := site.updateBatteryMeters(); err != nil { return err } - - // power errors returned return site.updateGridMeter() }