133 lines
3.4 KiB
Go
133 lines
3.4 KiB
Go
package core
|
|
|
|
import (
|
|
"github.com/evcc-io/evcc/api"
|
|
"github.com/evcc-io/evcc/core/keys"
|
|
)
|
|
|
|
// setConfiguredPhases sets the default phase configuration
|
|
func (lp *Loadpoint) setConfiguredPhases(phases int) {
|
|
lp.configuredPhases = phases
|
|
lp.publish(keys.Phases, lp.configuredPhases)
|
|
lp.publish(keys.PhasesConfigured, lp.configuredPhases) // TODO remove
|
|
lp.settings.SetInt(keys.Phases, int64(lp.configuredPhases))
|
|
}
|
|
|
|
// setPhases sets the number of enabled phases without modifying the charger
|
|
func (lp *Loadpoint) setPhases(phases int) {
|
|
if lp.GetPhases() != phases {
|
|
lp.Lock()
|
|
lp.phases = phases
|
|
lp.Unlock()
|
|
|
|
// publish updated phase configuration
|
|
lp.publish(keys.PhasesEnabled, lp.phases)
|
|
|
|
// reset timer to disabled state
|
|
lp.resetPhaseTimer()
|
|
|
|
// measure phases after switching
|
|
lp.resetMeasuredPhases()
|
|
}
|
|
}
|
|
|
|
// resetMeasuredPhases resets measured phases to unknown on vehicle disconnect, phase switch or phase api call
|
|
func (lp *Loadpoint) resetMeasuredPhases() {
|
|
lp.Lock()
|
|
lp.measuredPhases = 0
|
|
lp.Unlock()
|
|
|
|
lp.publish(keys.PhasesActive, lp.ActivePhases())
|
|
}
|
|
|
|
// getMeasuredPhases provides synchronized access to measuredPhases
|
|
func (lp *Loadpoint) getMeasuredPhases() int {
|
|
lp.RLock()
|
|
defer lp.RUnlock()
|
|
return lp.measuredPhases
|
|
}
|
|
|
|
// assume 3p for switchable charger during startup
|
|
const unknownPhases = 3
|
|
|
|
func expect(phases int) int {
|
|
if phases > 0 {
|
|
return phases
|
|
}
|
|
return unknownPhases
|
|
}
|
|
|
|
// ActivePhases returns the number of expectedly active phases for the meter.
|
|
// If unknown for 1p3p chargers during startup it will assume 3p.
|
|
func (lp *Loadpoint) ActivePhases() int {
|
|
physical := lp.GetPhases()
|
|
vehicle := lp.getVehiclePhases()
|
|
measured := lp.getMeasuredPhases()
|
|
charger := lp.getChargerPhysicalPhases()
|
|
|
|
active := min(expect(vehicle), expect(physical), expect(measured), expect(charger))
|
|
|
|
// sanity check - we should not assume less active phases than actually measured
|
|
if measured > 0 && active < measured {
|
|
lp.log.WARN.Printf("phase mismatch between %dp measured for %dp vehicle and %dp charger", measured, vehicle, physical)
|
|
}
|
|
|
|
return active
|
|
}
|
|
|
|
// minActivePhases returns the minimum number of active phases for the loadpoint.
|
|
func (lp *Loadpoint) minActivePhases() int {
|
|
lp.RLock()
|
|
configuredPhases := lp.configuredPhases
|
|
lp.RUnlock()
|
|
|
|
// 1p3p supported or limit 1p
|
|
if lp.hasPhaseSwitching() || configuredPhases == 1 {
|
|
return 1
|
|
}
|
|
|
|
return lp.maxActivePhases()
|
|
}
|
|
|
|
// maxActivePhases returns the maximum number of active phases for the loadpoint.
|
|
func (lp *Loadpoint) maxActivePhases() int {
|
|
physical := lp.GetPhases()
|
|
measured := lp.getMeasuredPhases()
|
|
vehicle := lp.getVehiclePhases()
|
|
charger := lp.getChargerPhysicalPhases()
|
|
|
|
// during 1p or unknown config, 1p measured is not a restriction
|
|
if physical <= 1 || vehicle == 1 || charger == 1 {
|
|
measured = 0
|
|
}
|
|
|
|
// if 1p3p supported then assume configured limit or 3p
|
|
if lp.hasPhaseSwitching() {
|
|
lp.RLock()
|
|
physical = lp.configuredPhases
|
|
lp.RUnlock()
|
|
}
|
|
|
|
return min(expect(vehicle), expect(physical), expect(measured), expect(charger))
|
|
}
|
|
|
|
func (lp *Loadpoint) getVehiclePhases() int {
|
|
if vehicle := lp.GetVehicle(); vehicle != nil {
|
|
return vehicle.Phases()
|
|
}
|
|
|
|
return 0
|
|
}
|
|
|
|
func (lp *Loadpoint) getChargerPhysicalPhases() int {
|
|
if cc, ok := lp.charger.(api.PhaseDescriber); ok {
|
|
return cc.Phases()
|
|
}
|
|
|
|
return 0
|
|
}
|
|
|
|
func (lp *Loadpoint) hasPhaseSwitching() bool {
|
|
_, ok := lp.charger.(api.PhaseSwitcher)
|
|
return ok
|
|
}
|