1p3p: let charger handle session stop/restart (#7723)
This commit is contained in:
parent
38777d1e61
commit
dd787ce52f
3 changed files with 20 additions and 16 deletions
|
|
@ -1,6 +1,7 @@
|
|||
package charger
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/evcc-io/evcc/api"
|
||||
|
|
@ -30,6 +31,7 @@ func NewConfigurableFromConfig(other map[string]interface{}) (api.Charger, error
|
|||
Status, Enable, Enabled, MaxCurrent provider.Config
|
||||
Identify, Phases1p3p *provider.Config
|
||||
Wakeup *provider.Config
|
||||
Tos bool
|
||||
}
|
||||
|
||||
if err := util.DecodeOther(other, &cc); err != nil {
|
||||
|
|
@ -66,6 +68,10 @@ func NewConfigurableFromConfig(other map[string]interface{}) (api.Charger, error
|
|||
// decorate phases
|
||||
var phases1p3p func(int) error
|
||||
if cc.Phases1p3p != nil {
|
||||
if !cc.Tos {
|
||||
return nil, errors.New("1p3p does no longer handle disable/enable. Use tos: true to confirm you understand the consequences")
|
||||
}
|
||||
|
||||
phases1p3pS, err := provider.NewIntSetterFromConfig("phases", *cc.Phases1p3p)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("phases: %w", err)
|
||||
|
|
|
|||
|
|
@ -52,7 +52,8 @@ const (
|
|||
minActiveCurrent = 1.0 // minimum current at which a phase is treated as active
|
||||
minActiveVoltage = 208 // minimum voltage at which a phase is treated as active
|
||||
|
||||
guardGracePeriod = 60 * time.Second // allow out of sync during this timespan
|
||||
guardGracePeriod = 60 * time.Second // allow out of sync during this timespan
|
||||
phaseSwitchDuration = 60 * time.Second // do not measure phases during this timespan
|
||||
)
|
||||
|
||||
// elapsed is the time an expired timer will be set to
|
||||
|
|
@ -131,6 +132,7 @@ type Loadpoint struct {
|
|||
guardUpdated time.Time // Charger enabled/disabled timestamp
|
||||
socUpdated time.Time // Soc updated timestamp (poll: connected)
|
||||
vehicleDetect time.Time // Vehicle connected timestamp
|
||||
phasesSwitched time.Time // Phase switch timestamp
|
||||
vehicleDetectTicker *clock.Ticker
|
||||
vehicleIdentifier string
|
||||
|
||||
|
|
@ -921,21 +923,16 @@ func (lp *Loadpoint) scalePhases(phases int) error {
|
|||
}
|
||||
|
||||
if lp.GetPhases() != phases {
|
||||
// disable charger - this will also stop the car charging using the api if available
|
||||
if err := lp.setLimit(0, true); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// switch phases
|
||||
if err := cp.Phases1p3p(phases); err != nil {
|
||||
return fmt.Errorf("switch phases: %w", err)
|
||||
}
|
||||
|
||||
// prevent premature measurement of active phases
|
||||
lp.phasesSwitched = lp.clock.Now()
|
||||
|
||||
// update setting and reset timer
|
||||
lp.setPhases(phases)
|
||||
|
||||
// allow pv mode to re-enable charger right away
|
||||
lp.elapsePVTimer()
|
||||
}
|
||||
|
||||
return nil
|
||||
|
|
@ -1063,11 +1060,7 @@ func (lp *Loadpoint) pvMaxCurrent(mode api.ChargeMode, sitePower float64, batter
|
|||
// switch phases up/down
|
||||
if _, ok := lp.charger.(api.PhaseSwitcher); ok {
|
||||
availablePower := -sitePower + lp.chargePower
|
||||
|
||||
// in case of scaling, keep charger disabled for this cycle
|
||||
if lp.pvScalePhases(availablePower, minCurrent, maxCurrent) {
|
||||
return 0
|
||||
}
|
||||
_ = lp.pvScalePhases(availablePower, minCurrent, maxCurrent)
|
||||
}
|
||||
|
||||
// calculate target charge current from delta power and actual current
|
||||
|
|
@ -1202,7 +1195,7 @@ func (lp *Loadpoint) updateChargeCurrents() {
|
|||
lp.log.DEBUG.Printf("charge currents: %.3gA", lp.chargeCurrents)
|
||||
lp.publish("chargeCurrents", lp.chargeCurrents)
|
||||
|
||||
if lp.charging() {
|
||||
if lp.charging() && lp.phaseSwitchCompleted() {
|
||||
var phases int
|
||||
for _, i := range lp.chargeCurrents {
|
||||
if i > minActiveCurrent {
|
||||
|
|
@ -1411,6 +1404,11 @@ func (lp *Loadpoint) guardGracePeriodElapsed() bool {
|
|||
return time.Since(lp.guardUpdated) > guardGracePeriod
|
||||
}
|
||||
|
||||
// phaseSwitchCompleted returns true if phase switch has completed
|
||||
func (lp *Loadpoint) phaseSwitchCompleted() bool {
|
||||
return time.Since(lp.phasesSwitched) > phaseSwitchDuration
|
||||
}
|
||||
|
||||
// Update is the main control function. It reevaluates meters and charger state
|
||||
func (lp *Loadpoint) Update(sitePower float64, autoCharge, batteryBuffered, batteryStart bool, greenShare float64, effPrice, effCo2 *float64) {
|
||||
lp.processTasks()
|
||||
|
|
|
|||
|
|
@ -85,7 +85,7 @@ func (lp *Loadpoint) activePhases() int {
|
|||
active := min(expect(vehicle), expect(physical), expect(measured))
|
||||
|
||||
// sanity check - we should not assume less active phases than actually measured
|
||||
if measured > 0 && active < measured && lp.guardGracePeriodElapsed() {
|
||||
if measured > 0 && active < measured {
|
||||
lp.log.WARN.Printf("phase mismatch between %dp measured for %dp vehicle and %dp charger", measured, vehicle, physical)
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue