Warp: validate charger phases (#13230)

This commit is contained in:
poohnet 2024-03-31 20:39:21 +02:00 • committed by GitHub
parent 1d4a161113
commit 412ec23a77
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 1603 additions and 67 deletions

View file

@ -82,6 +82,10 @@ type PhaseSwitcher interface {
Phases1p3p(phases int) error
}
type PhaseGetter interface {
GetPhases() (int, error)
}
// Diagnosis is a helper interface that allows to dump diagnostic data to console
type Diagnosis interface {
Diagnose()

View file

@ -105,3 +105,7 @@ type EmState struct {
RelayState bool `json:"relay_state"`
ErrorFlags int `json:"error_flags"`
}
type EmLowLevelState struct {
Is3phase bool `json:"is_3phase"`
}

View file

@ -26,6 +26,7 @@ type Warp2 struct {
chargeG func() (string, error)
userconfigG func() (string, error)
emStateG func() (string, error)
emLowLevelG func() (string, error)
maxcurrentS func(int64) error
phasesS func(int64) error
current int64
@ -36,7 +37,7 @@ func init() {
registry.Add("warp-fw2", NewWarp2FromConfig) // deprecated
}
//go:generate go run ../cmd/tools/decorate.go -f decorateWarp2 -b *Warp2 -r api.Charger -t "api.Meter,CurrentPower,func() (float64, error)" -t "api.MeterEnergy,TotalEnergy,func() (float64, error)" -t "api.PhaseCurrents,Currents,func() (float64, float64, float64, error)" -t "api.PhaseVoltages,Voltages,func() (float64, float64, float64, error)" -t "api.Identifier,Identify,func() (string, error)" -t "api.PhaseSwitcher,Phases1p3p,func(int) error"
//go:generate go run ../cmd/tools/decorate.go -f decorateWarp2 -b *Warp2 -r api.Charger -t "api.Meter,CurrentPower,func() (float64, error)" -t "api.MeterEnergy,TotalEnergy,func() (float64, error)" -t "api.PhaseCurrents,Currents,func() (float64, float64, float64, error)" -t "api.PhaseVoltages,Voltages,func() (float64, float64, float64, error)" -t "api.Identifier,Identify,func() (string, error)" -t "api.PhaseSwitcher,Phases1p3p,func(int) error" -t "api.PhaseGetter,GetPhases,func() (int, error)"
// NewWarpFromConfig creates a new configurable charger
func NewWarp2FromConfig(other map[string]interface{}) (api.Charger, error) {
@ -77,13 +78,15 @@ func NewWarp2FromConfig(other map[string]interface{}) (api.Charger, error) {
}
var phases func(int) error
var getPhases func() (int, error)
if cc.EnergyManager != "" {
if res, err := wb.emState(); err == nil && res.ExternalControl != 1 {
phases = wb.phases1p3p
getPhases = wb.getPhases
}
}
return decorateWarp2(wb, currentPower, totalEnergy, currents, voltages, identity, phases), err
return decorateWarp2(wb, currentPower, totalEnergy, currents, voltages, identity, phases, getPhases), err
}
// NewWarp2 creates a new configurable charger
@ -149,6 +152,7 @@ func NewWarp2(mqttconf mqtt.Config, topic, emTopic string, timeout time.Duration
if err != nil {
return nil, err
}
wb.phasesS, err = provider.NewMqtt(log, client,
fmt.Sprintf("%s/power_manager/external_control_update", emTopic), 0).
WithPayload(`{ "phases_wanted": ${phases} }`).
@ -157,6 +161,11 @@ func NewWarp2(mqttconf mqtt.Config, topic, emTopic string, timeout time.Duration
return nil, err
}
wb.emLowLevelG, err = to.StringGetter(mq("%s/power_manager/low_level_state", emTopic))
if err != nil {
return nil, err
}
return wb, nil
}
@ -328,6 +337,18 @@ func (wb *Warp2) emState() (warp.EmState, error) {
return res, err
}
func (wb *Warp2) emLowLevelState() (warp.EmLowLevelState, error) {
var res warp.EmLowLevelState
s, err := wb.emLowLevelG()
if err == nil {
err = json.Unmarshal([]byte(s), &res)
}
return res, err
}
// phases1p3p implements the api.PhaseSwitcher interface
func (wb *Warp2) phases1p3p(phases int) error {
res, err := wb.emState()
if err != nil {
@ -340,3 +361,17 @@ func (wb *Warp2) phases1p3p(phases int) error {
return wb.phasesS(int64(phases))
}
// getPhases implements the api.PhaseGetter interface
func (wb *Warp2) getPhases() (int, error) {
res, err := wb.emLowLevelState()
if err != nil {
return 0, err
}
if res.Is3phase {
return 3, nil
}
return 1, nil
}

File diff suppressed because it is too large Load diff

View file

@ -710,6 +710,19 @@ func (lp *Loadpoint) syncCharger() error {
}
}
// sync phases
phases := lp.GetPhases()
if ps, ok := lp.charger.(api.PhaseGetter); ok && enabled && shouldBeConsistent && phases > 0 {
if chargerPhases, err := ps.GetPhases(); err == nil {
if 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 fmt.Errorf("charger get phases: %w", err)
}
}
case !enabled && !lp.phaseSwitchCompleted():
// some chargers (i.E. Easee in some configurations) disable themselves to be able to switch phases
// -> enable charger