Loadpoint: add asleep messaging event if wakeup fails (#23116)
This commit is contained in:
parent
4b0524e392
commit
0f70bb3106
7 changed files with 63 additions and 27 deletions
|
|
@ -17,6 +17,9 @@
|
|||
# guest:
|
||||
# title: Unknown vehicle
|
||||
# msg: Unknown vehicle, guest connected?
|
||||
# asleep:
|
||||
# title: Vehicle asleep
|
||||
# msg: Charge release, vehicle {{ if .vehicleTitle }}{{ .vehicleTitle }} {{ end }}not charging.
|
||||
|
||||
#services:
|
||||
#- type: pushover
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ const (
|
|||
evVehicleDisconnect = "disconnect" // vehicle disconnected
|
||||
evVehicleSoc = "soc" // vehicle soc progress
|
||||
evVehicleUnidentified = "guest" // vehicle unidentified
|
||||
evVehicleAsleep = "asleep" // vehicle doesn't charge
|
||||
|
||||
pvTimer = "pv"
|
||||
pvEnable = "enable"
|
||||
|
|
@ -1220,6 +1221,9 @@ func (lp *Loadpoint) scalePhases(phases int) error {
|
|||
|
||||
// update setting and reset timer
|
||||
lp.SetPhases(phases)
|
||||
|
||||
// some vehicles may hang on phase switch
|
||||
lp.startWakeUpTimer()
|
||||
}
|
||||
|
||||
return nil
|
||||
|
|
@ -1972,8 +1976,13 @@ func (lp *Loadpoint) Update(sitePower, batteryBoostPower float64, consumption, f
|
|||
// Wake-up checks
|
||||
if lp.enabled && lp.status == api.StatusB &&
|
||||
// TODO take vehicle api limits into account
|
||||
int(lp.vehicleSoc) < lp.EffectiveLimitSoc() && lp.wakeUpTimer.Expired() {
|
||||
lp.wakeUpVehicle()
|
||||
!lp.chargerHasFeature(api.IntegratedDevice) && int(lp.vehicleSoc) < lp.EffectiveLimitSoc() {
|
||||
switch lp.wakeUpTimer.Elapsed() {
|
||||
case WakeUpTimerElapsed:
|
||||
lp.wakeUpVehicle()
|
||||
case WakeUpTimerFinished:
|
||||
lp.pushEvent(evVehicleAsleep)
|
||||
}
|
||||
}
|
||||
|
||||
// effective disabled status
|
||||
|
|
|
|||
|
|
@ -399,6 +399,7 @@ func TestPvScalePhasesTimer(t *testing.T) {
|
|||
|
||||
lp := &Loadpoint{
|
||||
log: util.NewLogger("foo"),
|
||||
wakeUpTimer: NewTimer(),
|
||||
clock: clock,
|
||||
charger: charger,
|
||||
minCurrent: minA,
|
||||
|
|
@ -453,8 +454,9 @@ func TestScalePhasesIfAvailable(t *testing.T) {
|
|||
phaseCharger := api.NewMockPhaseSwitcher(ctrl)
|
||||
|
||||
lp := &Loadpoint{
|
||||
log: util.NewLogger("foo"),
|
||||
clock: clock.NewMock(),
|
||||
log: util.NewLogger("foo"),
|
||||
clock: clock.NewMock(),
|
||||
wakeUpTimer: NewTimer(),
|
||||
charger: struct {
|
||||
*api.MockCharger
|
||||
*api.MockPhaseSwitcher
|
||||
|
|
|
|||
|
|
@ -741,11 +741,12 @@ func TestPVHysteresisAfterPhaseSwitch(t *testing.T) {
|
|||
|
||||
Voltage = 100
|
||||
lp := &Loadpoint{
|
||||
log: util.NewLogger("foo"),
|
||||
clock: clock,
|
||||
charger: charger,
|
||||
minCurrent: minA,
|
||||
maxCurrent: maxA,
|
||||
log: util.NewLogger("foo"),
|
||||
wakeUpTimer: NewTimer(),
|
||||
clock: clock,
|
||||
charger: charger,
|
||||
minCurrent: minA,
|
||||
maxCurrent: maxA,
|
||||
Disable: loadpoint.ThresholdConfig{
|
||||
Delay: dt,
|
||||
},
|
||||
|
|
|
|||
|
|
@ -7,9 +7,18 @@ import (
|
|||
"github.com/benbjohnson/clock"
|
||||
)
|
||||
|
||||
const wakeupTimeout = 30 * time.Second
|
||||
const (
|
||||
wakeupTimeout = 30 * time.Second
|
||||
wakeupAttempts = 6
|
||||
)
|
||||
|
||||
const wakeupAttempts = 6 // wakeupAttempts is the count of wakeup attempts
|
||||
type WakeUpEvent int
|
||||
|
||||
const (
|
||||
WakeUpTimerInactive WakeUpEvent = iota
|
||||
WakeUpTimerElapsed
|
||||
WakeUpTimerFinished
|
||||
)
|
||||
|
||||
// Timer measures active time between start and stop events
|
||||
type Timer struct {
|
||||
|
|
@ -48,20 +57,22 @@ func (m *Timer) Stop() {
|
|||
m.started = time.Time{}
|
||||
}
|
||||
|
||||
// Expired checks if the timer has elapsed and if resets its status
|
||||
func (m *Timer) Expired() bool {
|
||||
// Elapsed checks if the timer has elapsed and if resets its status
|
||||
func (m *Timer) Elapsed() WakeUpEvent {
|
||||
m.Lock()
|
||||
defer m.Unlock()
|
||||
|
||||
res := !m.started.IsZero() && (m.clck.Since(m.started) >= wakeupTimeout)
|
||||
if res {
|
||||
m.wakeupAttemptsLeft--
|
||||
if m.wakeupAttemptsLeft == 0 {
|
||||
m.started = time.Time{}
|
||||
} else {
|
||||
m.started = m.clck.Now()
|
||||
}
|
||||
if m.started.IsZero() || m.clck.Since(m.started) < wakeupTimeout {
|
||||
return WakeUpTimerInactive
|
||||
}
|
||||
|
||||
return res
|
||||
if m.wakeupAttemptsLeft == 0 {
|
||||
m.started = time.Time{}
|
||||
return WakeUpTimerFinished
|
||||
}
|
||||
|
||||
m.wakeupAttemptsLeft--
|
||||
|
||||
m.started = m.clck.Now()
|
||||
return WakeUpTimerElapsed
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,15 +16,22 @@ func TestTimer(t *testing.T) {
|
|||
|
||||
// start
|
||||
at.Start()
|
||||
|
||||
// maximum 2 attempts
|
||||
at.wakeupAttemptsLeft = 2
|
||||
|
||||
clck.Add(10 * time.Second)
|
||||
require.False(t, at.Expired())
|
||||
require.Equal(t, WakeUpTimerInactive, at.Elapsed())
|
||||
|
||||
// wait another 20 sec to expire the timer - this will reset the timer as well
|
||||
clck.Add(wakeupTimeout + 10*time.Second)
|
||||
require.True(t, at.Expired())
|
||||
require.Equal(t, WakeUpTimerElapsed, at.Elapsed())
|
||||
|
||||
// start
|
||||
at.Start()
|
||||
// elapse
|
||||
clck.Add(time.Minute)
|
||||
require.True(t, at.Expired())
|
||||
require.Equal(t, WakeUpTimerElapsed, at.Elapsed())
|
||||
|
||||
// elapse
|
||||
clck.Add(time.Minute)
|
||||
require.Equal(t, WakeUpTimerFinished, at.Elapsed())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -214,6 +214,9 @@ messaging:
|
|||
guest: # vehicle could not be identified
|
||||
title: Unknown vehicle
|
||||
msg: Unknown vehicle, guest connected?
|
||||
asleep: # vehicle doesn't start charging
|
||||
title: Vehicle asleep
|
||||
msg: Charge release, vehicle {{ if .vehicleTitle }}{{ .vehicleTitle }} {{ end }}not charging.
|
||||
services:
|
||||
# - type: pushover
|
||||
# app: # app id
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue