Don't disable for 1p3p- let charger handle session stop/restart (#8320)
This commit is contained in:
parent
99a63fcf4b
commit
b2b4483bf9
4 changed files with 34 additions and 19 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)
|
||||
|
|
|
|||
|
|
@ -550,7 +550,12 @@ func (c *Easee) Phases1p3p(phases int) error {
|
|||
|
||||
uri := fmt.Sprintf("%s/chargers/%s/settings", easee.API, c.charger)
|
||||
|
||||
err = c.postJSONAndWait(uri, data)
|
||||
if err = c.postJSONAndWait(uri, data); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// disable charger to activate changed settings (loadpoint will reenable it)
|
||||
err = c.Enable(false)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -52,7 +52,9 @@ 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
|
||||
phaseSwitchCommandTimeout = 30 * time.Second // do not sync charger enabled/disabled state 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 +133,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
|
||||
|
||||
|
|
@ -630,9 +633,9 @@ func (lp *Loadpoint) syncCharger() error {
|
|||
return err
|
||||
}
|
||||
|
||||
if enabled != lp.enabled {
|
||||
if (enabled != lp.enabled) && (!lp.enabled || lp.phaseSwitchCommandTimeoutElapsed()) {
|
||||
// ignore disabled state if vehicle was disconnected ^(lp.enabled && ^lp.connected)
|
||||
if lp.guardGracePeriodElapsed() && (!lp.enabled || lp.connected()) {
|
||||
if lp.guardGracePeriodElapsed() && lp.phaseSwitchCompleted() && (!lp.enabled || lp.connected()) {
|
||||
lp.log.WARN.Printf("charger out of sync: expected %vd, got %vd", status[lp.enabled], status[enabled])
|
||||
}
|
||||
return lp.charger.Enable(lp.enabled)
|
||||
|
|
@ -929,21 +932,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
|
||||
|
|
@ -1071,11 +1069,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
|
||||
|
|
@ -1210,7 +1204,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 {
|
||||
|
|
@ -1419,6 +1413,16 @@ func (lp *Loadpoint) guardGracePeriodElapsed() bool {
|
|||
return time.Since(lp.guardUpdated) > guardGracePeriod
|
||||
}
|
||||
|
||||
// phaseSwitchCommandTimeoutElapsed returns true if phase switch command should be already processed by the charger
|
||||
func (lp *Loadpoint) phaseSwitchCommandTimeoutElapsed() bool {
|
||||
return time.Since(lp.phasesSwitched) > phaseSwitchCommandTimeout
|
||||
}
|
||||
|
||||
// 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