Loadpoint: sync charger phases on vehicle connect (#32962)
This commit is contained in:
parent
c745672437
commit
72b7e27057
2 changed files with 50 additions and 29 deletions
|
|
@ -561,6 +561,11 @@ func (lp *Loadpoint) evVehicleConnectHandler() {
|
||||||
// soc update reset
|
// soc update reset
|
||||||
lp.socUpdated = time.Time{}
|
lp.socUpdated = time.Time{}
|
||||||
|
|
||||||
|
// charger may have reconfigured phases internally while disconnected
|
||||||
|
if err := lp.syncChargerPhases(); err != nil {
|
||||||
|
lp.log.ERROR.Println(err)
|
||||||
|
}
|
||||||
|
|
||||||
// set default or start detection
|
// set default or start detection
|
||||||
if !lp.chargerHasFeature(api.IntegratedDevice) {
|
if !lp.chargerHasFeature(api.IntegratedDevice) {
|
||||||
lp.vehicleDefaultOrDetect()
|
lp.vehicleDefaultOrDetect()
|
||||||
|
|
@ -884,35 +889,9 @@ func (lp *Loadpoint) syncCharger() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// sync phases
|
// sync phases
|
||||||
_, isPs := api.Cap[api.PhaseSwitcher](lp.charger)
|
if shouldBeConsistent {
|
||||||
if phases := lp.GetPhases(); isPs && shouldBeConsistent && phases > 0 {
|
if err := lp.syncChargerPhases(); err != nil {
|
||||||
// fallback to active phases from measured phases
|
return err
|
||||||
chargerPhases := lp.measuredPhases
|
|
||||||
if chargerPhases == 2 {
|
|
||||||
chargerPhases = 3
|
|
||||||
}
|
|
||||||
|
|
||||||
pg, isPg := api.Cap[api.PhaseGetter](lp.charger)
|
|
||||||
if isPg {
|
|
||||||
if chargerPhases, err = pg.GetPhases(); err == nil {
|
|
||||||
if chargerPhases > 0 && chargerPhases != phases {
|
|
||||||
lp.log.WARN.Printf("charger logic error: phases mismatch (got %d, expected %d)", chargerPhases, phases)
|
|
||||||
lp.SetPhases(chargerPhases)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if errors.Is(err, api.ErrNotAvailable) {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return fmt.Errorf("charger get phases: %w", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// use measured phase currents for active phases as fallback if charger does not provide phases
|
|
||||||
if !isPg || errors.Is(err, api.ErrNotAvailable) {
|
|
||||||
if chargerPhases > phases {
|
|
||||||
lp.log.WARN.Printf("charger logic error: phases mismatch (got %d measured, expected %d)", chargerPhases, phases)
|
|
||||||
lp.SetPhases(chargerPhases)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,9 @@
|
||||||
package core
|
package core
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
"github.com/evcc-io/evcc/api"
|
"github.com/evcc-io/evcc/api"
|
||||||
"github.com/evcc-io/evcc/core/keys"
|
"github.com/evcc-io/evcc/core/keys"
|
||||||
)
|
)
|
||||||
|
|
@ -161,3 +164,42 @@ func (lp *Loadpoint) getChargerPhysicalPhases() int {
|
||||||
func (lp *Loadpoint) hasPhaseSwitching() bool {
|
func (lp *Loadpoint) hasPhaseSwitching() bool {
|
||||||
return api.HasCap[api.PhaseSwitcher](lp.charger)
|
return api.HasCap[api.PhaseSwitcher](lp.charger)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// syncChargerPhases synchronizes the assumed phase state with the charger's actual state.
|
||||||
|
// Chargers may reconfigure phases internally, i.e. when the vehicle is (dis)connected.
|
||||||
|
func (lp *Loadpoint) syncChargerPhases() error {
|
||||||
|
phases := lp.GetPhases()
|
||||||
|
if !lp.hasPhaseSwitching() || phases <= 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if pg, ok := api.Cap[api.PhaseGetter](lp.charger); ok {
|
||||||
|
chargerPhases, err := pg.GetPhases()
|
||||||
|
if err != nil {
|
||||||
|
if errors.Is(err, api.ErrNotAvailable) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return fmt.Errorf("charger get phases: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if chargerPhases > 0 && chargerPhases != phases {
|
||||||
|
lp.log.WARN.Printf("charger logic error: phases mismatch (got %d, expected %d)", chargerPhases, phases)
|
||||||
|
lp.SetPhases(chargerPhases)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// use measured phase currents for active phases as fallback if charger does not provide phases
|
||||||
|
chargerPhases := lp.GetMeasuredPhases()
|
||||||
|
if chargerPhases == 2 {
|
||||||
|
chargerPhases = 3
|
||||||
|
}
|
||||||
|
|
||||||
|
if chargerPhases > phases {
|
||||||
|
lp.log.WARN.Printf("charger logic error: phases mismatch (got %d measured, expected %d)", chargerPhases, phases)
|
||||||
|
lp.SetPhases(chargerPhases)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue