Improve loadpoint api: add dynamic limits (#1058)
This commit is contained in:
parent
adb67a9277
commit
c2425489de
7 changed files with 123 additions and 75 deletions
|
|
@ -64,7 +64,7 @@ type ChargeState interface {
|
|||
Status() (ChargeStatus, error)
|
||||
}
|
||||
|
||||
// Charger is able to provide current charging status and to enable/disabler charging
|
||||
// Charger is able to provide current charging status and enable/disable charging
|
||||
type Charger interface {
|
||||
ChargeState
|
||||
Enabled() (bool, error)
|
||||
|
|
|
|||
|
|
@ -90,8 +90,8 @@ type LoadPoint struct {
|
|||
}
|
||||
Enable, Disable ThresholdConfig
|
||||
|
||||
MinCurrent int64 // PV mode: start current Min+PV mode: min current
|
||||
MaxCurrent int64 // Max allowed current. Physically ensured by the charger
|
||||
MinCurrent float64 // PV mode: start current Min+PV mode: min current
|
||||
MaxCurrent float64 // Max allowed current. Physically ensured by the charger
|
||||
GuardDuration time.Duration // charger enable/disable minimum holding time
|
||||
|
||||
enabled bool // Charger enabled state
|
||||
|
|
@ -363,7 +363,7 @@ func (lp *LoadPoint) evChargeCurrentHandler(current float64) {
|
|||
func (lp *LoadPoint) evChargeCurrentWrappedMeterHandler(current float64) {
|
||||
power := current * float64(lp.Phases) * Voltage
|
||||
|
||||
if !lp.enabled || lp.status != api.StatusC {
|
||||
if !lp.enabled || lp.GetStatus() != api.StatusC {
|
||||
// if disabled we cannot be charging
|
||||
power = 0
|
||||
}
|
||||
|
|
@ -423,7 +423,7 @@ func (lp *LoadPoint) Prepare(uiChan chan<- util.Param, pushChan chan<- push.Even
|
|||
if lp.enabled = enabled; enabled {
|
||||
lp.guardUpdated = lp.clock.Now()
|
||||
// set defined current for use by pv mode
|
||||
_ = lp.setLimit(float64(lp.MinCurrent), false)
|
||||
_ = lp.setLimit(lp.GetMinCurrent(), false)
|
||||
}
|
||||
} else {
|
||||
lp.log.ERROR.Printf("charger: %v", err)
|
||||
|
|
@ -435,11 +435,18 @@ func (lp *LoadPoint) Prepare(uiChan chan<- util.Param, pushChan chan<- push.Even
|
|||
}
|
||||
}
|
||||
|
||||
// syncCharger updates charger status and synchronizes it with expectations
|
||||
func (lp *LoadPoint) syncCharger() {
|
||||
enabled, err := lp.charger.Enabled()
|
||||
if err == nil && enabled != lp.enabled {
|
||||
lp.log.WARN.Printf("charger out of sync: expected %vd, got %vd", status[lp.enabled], status[enabled])
|
||||
err = lp.charger.Enable(lp.enabled)
|
||||
if err == nil {
|
||||
if enabled != lp.enabled {
|
||||
lp.log.WARN.Printf("charger out of sync: expected %vd, got %vd", status[lp.enabled], status[enabled])
|
||||
err = lp.charger.Enable(lp.enabled)
|
||||
}
|
||||
|
||||
if !enabled && lp.GetStatus() == api.StatusC {
|
||||
lp.log.WARN.Println("charger logic error: disabled but charging")
|
||||
}
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
|
|
@ -447,9 +454,10 @@ func (lp *LoadPoint) syncCharger() {
|
|||
}
|
||||
}
|
||||
|
||||
// setLimit applies charger current limits and enables/disables accordingly
|
||||
func (lp *LoadPoint) setLimit(chargeCurrent float64, force bool) (err error) {
|
||||
// set current
|
||||
if chargeCurrent != lp.chargeCurrent && chargeCurrent >= float64(lp.MinCurrent) {
|
||||
if chargeCurrent != lp.chargeCurrent && chargeCurrent >= lp.GetMinCurrent() {
|
||||
if charger, ok := lp.charger.(api.ChargerEx); ok {
|
||||
lp.log.DEBUG.Printf("max charge current: %.2g", chargeCurrent)
|
||||
err = charger.MaxCurrentMillis(chargeCurrent)
|
||||
|
|
@ -467,7 +475,7 @@ func (lp *LoadPoint) setLimit(chargeCurrent float64, force bool) (err error) {
|
|||
}
|
||||
|
||||
// set enabled
|
||||
if enabled := chargeCurrent >= float64(lp.MinCurrent); enabled != lp.enabled && err == nil {
|
||||
if enabled := chargeCurrent >= lp.GetMinCurrent(); enabled != lp.enabled && err == nil {
|
||||
if remaining := (lp.GuardDuration - lp.clock.Since(lp.guardUpdated)).Truncate(time.Second); remaining > 0 && !force {
|
||||
lp.log.DEBUG.Printf("charger %s: contactor delay %v", status[enabled], remaining)
|
||||
return nil
|
||||
|
|
@ -503,12 +511,20 @@ func (lp *LoadPoint) setLimit(chargeCurrent float64, force bool) (err error) {
|
|||
|
||||
// connected returns the EVs connection state
|
||||
func (lp *LoadPoint) connected() bool {
|
||||
return lp.status == api.StatusB || lp.status == api.StatusC
|
||||
status := lp.GetStatus()
|
||||
return status == api.StatusB || status == api.StatusC
|
||||
}
|
||||
|
||||
// charging returns the EVs charging state
|
||||
func (lp *LoadPoint) charging() bool {
|
||||
return lp.status == api.StatusC
|
||||
return lp.GetStatus() == api.StatusC
|
||||
}
|
||||
|
||||
// charging returns the EVs charging state
|
||||
func (lp *LoadPoint) setStatus(status api.ChargeStatus) {
|
||||
lp.Lock()
|
||||
defer lp.Unlock()
|
||||
lp.status = status
|
||||
}
|
||||
|
||||
// targetSocReached checks if target is configured and reached.
|
||||
|
|
@ -662,8 +678,8 @@ func (lp *LoadPoint) updateChargerStatus() error {
|
|||
|
||||
lp.log.DEBUG.Printf("charger status: %s", status)
|
||||
|
||||
if prevStatus := lp.status; status != prevStatus {
|
||||
lp.status = status
|
||||
if prevStatus := lp.GetStatus(); status != prevStatus {
|
||||
lp.setStatus(status)
|
||||
|
||||
// changed from empty (initial startup) - set connected without sending message
|
||||
if prevStatus == api.StatusNone {
|
||||
|
|
@ -703,9 +719,10 @@ func (lp *LoadPoint) effectiveCurrent() float64 {
|
|||
return lp.chargeCurrents[0]
|
||||
}
|
||||
|
||||
if lp.status != api.StatusC {
|
||||
if lp.GetStatus() != api.StatusC {
|
||||
return 0
|
||||
}
|
||||
|
||||
return lp.chargeCurrent
|
||||
}
|
||||
|
||||
|
|
@ -719,17 +736,18 @@ func (lp *LoadPoint) pvMaxCurrent(mode api.ChargeMode, sitePower float64) float6
|
|||
// calculate target charge current from delta power and actual current
|
||||
effectiveCurrent := lp.effectiveCurrent()
|
||||
deltaCurrent := powerToCurrent(-sitePower, lp.Phases)
|
||||
targetCurrent := math.Max(math.Min(effectiveCurrent+deltaCurrent, float64(lp.MaxCurrent)), 0)
|
||||
targetCurrent := math.Max(math.Min(effectiveCurrent+deltaCurrent, lp.GetMaxCurrent()), 0)
|
||||
|
||||
lp.log.DEBUG.Printf("max charge current: %.1fA = %.1fA + %.1fA (%.0fW @ %dp)", targetCurrent, effectiveCurrent, deltaCurrent, sitePower, lp.Phases)
|
||||
|
||||
// in MinPV mode return at least minCurrent
|
||||
if mode == api.ModeMinPV && targetCurrent < float64(lp.MinCurrent) {
|
||||
return float64(lp.MinCurrent)
|
||||
minCurrent := lp.GetMinCurrent()
|
||||
if mode == api.ModeMinPV && targetCurrent < minCurrent {
|
||||
return minCurrent
|
||||
}
|
||||
|
||||
// read only once to simplify testing
|
||||
if mode == api.ModePV && lp.enabled && targetCurrent < float64(lp.MinCurrent) {
|
||||
if mode == api.ModePV && lp.enabled && targetCurrent < minCurrent {
|
||||
// kick off disable sequence
|
||||
if sitePower >= lp.Disable.Threshold {
|
||||
lp.log.DEBUG.Printf("site power %.0fW >= disable threshold %.0fW", sitePower, lp.Disable.Threshold)
|
||||
|
|
@ -748,15 +766,17 @@ func (lp *LoadPoint) pvMaxCurrent(mode api.ChargeMode, sitePower float64) float6
|
|||
lp.log.DEBUG.Printf("pv disable timer remaining: %v", (lp.Disable.Delay - elapsed).Round(time.Second))
|
||||
} else {
|
||||
// reset timer
|
||||
lp.log.DEBUG.Printf("reset pv disable timer: %v", lp.Disable.Delay)
|
||||
lp.pvTimer = lp.clock.Now()
|
||||
}
|
||||
|
||||
return float64(lp.MinCurrent)
|
||||
lp.log.DEBUG.Println("pv enable timer: keep enabled")
|
||||
return minCurrent
|
||||
}
|
||||
|
||||
if mode == api.ModePV && !lp.enabled {
|
||||
// kick off enable sequence
|
||||
if (lp.Enable.Threshold == 0 && targetCurrent >= float64(lp.MinCurrent)) ||
|
||||
if (lp.Enable.Threshold == 0 && targetCurrent >= minCurrent) ||
|
||||
(lp.Enable.Threshold != 0 && sitePower <= lp.Enable.Threshold) {
|
||||
lp.log.DEBUG.Printf("site power %.0fW < enable threshold %.0fW", sitePower, lp.Enable.Threshold)
|
||||
|
||||
|
|
@ -768,15 +788,17 @@ func (lp *LoadPoint) pvMaxCurrent(mode api.ChargeMode, sitePower float64) float6
|
|||
elapsed := lp.clock.Since(lp.pvTimer)
|
||||
if elapsed >= lp.Enable.Delay {
|
||||
lp.log.DEBUG.Println("pv enable timer elapsed")
|
||||
return float64(lp.MinCurrent)
|
||||
return minCurrent
|
||||
}
|
||||
|
||||
lp.log.DEBUG.Printf("pv enable timer remaining: %v", (lp.Enable.Delay - elapsed).Round(time.Second))
|
||||
} else {
|
||||
// reset timer
|
||||
lp.log.DEBUG.Printf("reset pv enable timer: %v", lp.Enable.Delay)
|
||||
lp.pvTimer = lp.clock.Now()
|
||||
}
|
||||
|
||||
lp.log.DEBUG.Println("pv enable timer: keep disabled")
|
||||
return 0
|
||||
}
|
||||
|
||||
|
|
@ -980,7 +1002,7 @@ func (lp *LoadPoint) Update(sitePower float64) {
|
|||
var targetCurrent float64 // zero disables
|
||||
if lp.climateActive() {
|
||||
lp.log.DEBUG.Println("climater active")
|
||||
targetCurrent = float64(lp.MinCurrent)
|
||||
targetCurrent = lp.GetMinCurrent()
|
||||
}
|
||||
err = lp.setLimit(targetCurrent, true)
|
||||
lp.socTimer.Reset() // once SoC is reached, the target charge request is removed
|
||||
|
|
@ -994,11 +1016,11 @@ func (lp *LoadPoint) Update(sitePower float64) {
|
|||
err = lp.setLimit(0, true)
|
||||
|
||||
case lp.minSocNotReached():
|
||||
err = lp.setLimit(float64(lp.MaxCurrent), true)
|
||||
err = lp.setLimit(lp.GetMaxCurrent(), true)
|
||||
lp.pvDisableTimer() // let PV mode disable immediately afterwards
|
||||
|
||||
case mode == api.ModeNow:
|
||||
err = lp.setLimit(float64(lp.MaxCurrent), true)
|
||||
err = lp.setLimit(lp.GetMaxCurrent(), true)
|
||||
|
||||
// target charging
|
||||
case lp.socTimer.StartRequired():
|
||||
|
|
@ -1011,7 +1033,7 @@ func (lp *LoadPoint) Update(sitePower float64) {
|
|||
|
||||
var required bool // false
|
||||
if targetCurrent == 0 && lp.climateActive() {
|
||||
targetCurrent = float64(lp.MinCurrent)
|
||||
targetCurrent = lp.GetMaxCurrent()
|
||||
required = true
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -17,6 +17,9 @@ type LoadPointAPI interface {
|
|||
Name() string
|
||||
HasChargeMeter() bool
|
||||
|
||||
// status
|
||||
GetStatus() api.ChargeStatus
|
||||
|
||||
// settings
|
||||
GetMode() api.ChargeMode
|
||||
SetMode(api.ChargeMode)
|
||||
|
|
@ -28,10 +31,19 @@ type LoadPointAPI interface {
|
|||
RemoteControl(string, RemoteDemand)
|
||||
|
||||
// energy
|
||||
GetMinCurrent() int64
|
||||
GetMaxCurrent() int64
|
||||
GetMinPower() int64
|
||||
GetMaxPower() int64
|
||||
GetMinCurrent() float64
|
||||
SetMinCurrent(float64)
|
||||
GetMaxCurrent() float64
|
||||
SetMaxCurrent(float64)
|
||||
GetMinPower() float64
|
||||
GetMaxPower() float64
|
||||
}
|
||||
|
||||
// GetStatus returns the charging status
|
||||
func (lp *LoadPoint) GetStatus() api.ChargeStatus {
|
||||
lp.Lock()
|
||||
defer lp.Unlock()
|
||||
return lp.status
|
||||
}
|
||||
|
||||
// GetMode returns loadpoint charge mode
|
||||
|
|
@ -158,22 +170,48 @@ func (lp *LoadPoint) HasChargeMeter() bool {
|
|||
return lp.chargeMeter != nil && !isWrapped
|
||||
}
|
||||
|
||||
// GetMinCurrent returns the minimal loadpoint current
|
||||
func (lp *LoadPoint) GetMinCurrent() int64 {
|
||||
// GetMinCurrent returns the min loadpoint current
|
||||
func (lp *LoadPoint) GetMinCurrent() float64 {
|
||||
lp.Lock()
|
||||
defer lp.Unlock()
|
||||
return lp.MinCurrent
|
||||
}
|
||||
|
||||
// GetMaxCurrent returns the minimal loadpoint current
|
||||
func (lp *LoadPoint) GetMaxCurrent() int64 {
|
||||
// SetMinCurrent returns the min loadpoint current
|
||||
func (lp *LoadPoint) SetMinCurrent(current float64) {
|
||||
lp.Lock()
|
||||
defer lp.Unlock()
|
||||
|
||||
if current != lp.MinCurrent {
|
||||
lp.MinCurrent = current
|
||||
lp.publish("minCurrent", lp.MinCurrent)
|
||||
}
|
||||
}
|
||||
|
||||
// GetMaxCurrent returns the max loadpoint current
|
||||
func (lp *LoadPoint) GetMaxCurrent() float64 {
|
||||
lp.Lock()
|
||||
defer lp.Unlock()
|
||||
return lp.MaxCurrent
|
||||
}
|
||||
|
||||
// GetMinPower returns the minimal loadpoint power for a single phase
|
||||
func (lp *LoadPoint) GetMinPower() int64 {
|
||||
return int64(Voltage) * lp.MinCurrent
|
||||
// SetMaxCurrent returns the max loadpoint current
|
||||
func (lp *LoadPoint) SetMaxCurrent(current float64) {
|
||||
lp.Lock()
|
||||
defer lp.Unlock()
|
||||
|
||||
if current != lp.MaxCurrent {
|
||||
lp.MaxCurrent = current
|
||||
lp.publish("maxCurrent", lp.MaxCurrent)
|
||||
}
|
||||
}
|
||||
|
||||
// GetMaxPower returns the minimal loadpoint power taking active phases into account
|
||||
func (lp *LoadPoint) GetMaxPower() int64 {
|
||||
return int64(Voltage) * lp.Phases * lp.MaxCurrent
|
||||
// GetMinPower returns the min loadpoint power for a single phase
|
||||
func (lp *LoadPoint) GetMinPower() float64 {
|
||||
return Voltage * lp.GetMinCurrent()
|
||||
}
|
||||
|
||||
// GetMaxPower returns the max loadpoint power taking active phases into account
|
||||
func (lp *LoadPoint) GetMaxPower() float64 {
|
||||
return Voltage * lp.GetMaxCurrent() * float64(lp.Phases)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,8 +15,8 @@ import (
|
|||
)
|
||||
|
||||
const (
|
||||
minA int64 = 6
|
||||
maxA int64 = 16
|
||||
minA float64 = 6
|
||||
maxA float64 = 16
|
||||
)
|
||||
|
||||
type Null struct{}
|
||||
|
|
@ -62,7 +62,7 @@ func attachListeners(t *testing.T, lp *LoadPoint) {
|
|||
|
||||
if charger, ok := lp.charger.(*mock.MockCharger); ok && charger != nil {
|
||||
charger.EXPECT().Enabled().Return(true, nil)
|
||||
charger.EXPECT().MaxCurrent(lp.MinCurrent).Return(nil)
|
||||
charger.EXPECT().MaxCurrent(int64(lp.MinCurrent)).Return(nil)
|
||||
}
|
||||
|
||||
lp.Prepare(uiChan, pushChan, lpChan)
|
||||
|
|
@ -111,7 +111,7 @@ func TestUpdatePowerZero(t *testing.T) {
|
|||
h.EXPECT().Enable(false)
|
||||
}},
|
||||
{api.StatusB, api.ModeNow, func(h *mock.MockCharger) {
|
||||
h.EXPECT().MaxCurrent(maxA) // true
|
||||
h.EXPECT().MaxCurrent(int64(maxA)) // true
|
||||
}},
|
||||
{api.StatusB, api.ModeMinPV, func(h *mock.MockCharger) {
|
||||
// MaxCurrent omitted since identical value
|
||||
|
|
@ -126,7 +126,7 @@ func TestUpdatePowerZero(t *testing.T) {
|
|||
h.EXPECT().Enable(false)
|
||||
}},
|
||||
{api.StatusC, api.ModeNow, func(h *mock.MockCharger) {
|
||||
h.EXPECT().MaxCurrent(maxA) // true
|
||||
h.EXPECT().MaxCurrent(int64(maxA)) // true
|
||||
}},
|
||||
{api.StatusC, api.ModeMinPV, func(h *mock.MockCharger) {
|
||||
// MaxCurrent omitted since identical value
|
||||
|
|
@ -179,7 +179,7 @@ func TestPVHysteresis(t *testing.T) {
|
|||
type se struct {
|
||||
site float64
|
||||
delay time.Duration // test case delay since start
|
||||
current int64
|
||||
current float64
|
||||
}
|
||||
tc := []struct {
|
||||
enabled bool
|
||||
|
|
@ -325,8 +325,8 @@ func TestPVHysteresis(t *testing.T) {
|
|||
lp.enabled = tc.enabled
|
||||
current := lp.pvMaxCurrent(api.ModePV, se.site)
|
||||
|
||||
if current != float64(se.current) {
|
||||
t.Errorf("step %d: wanted %d, got %.f", step, se.current, current)
|
||||
if current != se.current {
|
||||
t.Errorf("step %d: wanted %.1f, got %.1f", step, se.current, current)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -351,10 +351,8 @@ func TestPVHysteresisForStatusOtherThanC(t *testing.T) {
|
|||
// not connected, test PV mode logic short-circuited
|
||||
lp.status = api.StatusA
|
||||
|
||||
// maxCurrent will read actual current in PV mode
|
||||
|
||||
// maxCurrent will read enabled state in PV mode
|
||||
sitePower := -float64(minA*lp.Phases)*Voltage + 1 // 1W below min power
|
||||
sitePower := -float64(lp.Phases)*minA*Voltage + 1 // 1W below min power
|
||||
current := lp.pvMaxCurrent(api.ModePV, sitePower)
|
||||
|
||||
if current != 0 {
|
||||
|
|
@ -405,7 +403,7 @@ func TestDisableAndEnableAtTargetSoC(t *testing.T) {
|
|||
vehicle.EXPECT().SoC().Return(85.0, nil)
|
||||
charger.EXPECT().Status().Return(api.StatusC, nil)
|
||||
charger.EXPECT().Enabled().Return(lp.enabled, nil)
|
||||
charger.EXPECT().MaxCurrent(maxA).Return(nil)
|
||||
charger.EXPECT().MaxCurrent(int64(maxA)).Return(nil)
|
||||
lp.Update(500)
|
||||
|
||||
t.Log("charging above target - soc deactivates charger")
|
||||
|
|
@ -474,7 +472,7 @@ func TestSetModeAndSocAtDisconnect(t *testing.T) {
|
|||
t.Log("charging at min")
|
||||
charger.EXPECT().Enabled().Return(lp.enabled, nil)
|
||||
charger.EXPECT().Status().Return(api.StatusC, nil)
|
||||
charger.EXPECT().MaxCurrent(maxA).Return(nil)
|
||||
charger.EXPECT().MaxCurrent(int64(maxA)).Return(nil)
|
||||
lp.Update(500)
|
||||
|
||||
t.Log("switch off when disconnected")
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ type Adapter interface {
|
|||
type Timer struct {
|
||||
Adapter
|
||||
log *util.Logger
|
||||
maxCurrent int64
|
||||
maxCurrent float64
|
||||
current float64
|
||||
SoC int
|
||||
Time time.Time
|
||||
|
|
@ -32,7 +32,7 @@ type Timer struct {
|
|||
}
|
||||
|
||||
// NewTimer creates a Timer
|
||||
func NewTimer(log *util.Logger, adapter Adapter, maxCurrent int64) *Timer {
|
||||
func NewTimer(log *util.Logger, adapter Adapter, maxCurrent float64) *Timer {
|
||||
lp := &Timer{
|
||||
log: log,
|
||||
Adapter: adapter,
|
||||
|
|
@ -64,7 +64,7 @@ func (lp *Timer) StartRequired() bool {
|
|||
return false
|
||||
}
|
||||
|
||||
power := float64(lp.maxCurrent*lp.ActivePhases()) * lp.Voltage()
|
||||
power := float64(lp.ActivePhases()) * lp.maxCurrent * lp.Voltage()
|
||||
|
||||
// time
|
||||
remainingDuration := se.RemainingChargeDuration(power, lp.SoC)
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/andig/evcc/api"
|
||||
"github.com/andig/evcc/core"
|
||||
"github.com/andig/evcc/hems/ocpp/profile"
|
||||
"github.com/andig/evcc/util"
|
||||
|
|
@ -81,14 +82,12 @@ func (s *OCPP) errorHandler(errC <-chan error) {
|
|||
// Run executes the OCPP chargepoint client
|
||||
func (s *OCPP) Run() {
|
||||
for {
|
||||
for id := range s.site.LoadPoints() {
|
||||
for id, lp := range s.site.LoadPoints() {
|
||||
connector := id + 1
|
||||
|
||||
status := ocppcore.ChargePointStatusAvailable
|
||||
if statusP, err := s.cache.GetChecked(id, "charging"); err == nil {
|
||||
if statusP.Val.(bool) {
|
||||
status = ocppcore.ChargePointStatusCharging
|
||||
}
|
||||
if lp.GetStatus() == api.StatusC {
|
||||
status = ocppcore.ChargePointStatusCharging
|
||||
}
|
||||
|
||||
s.log.TRACE.Printf("send: lp-%d status: %+v", connector, status)
|
||||
|
|
|
|||
|
|
@ -428,21 +428,12 @@ func (s *SEMP) allDeviceStatus() (res []DeviceStatus) {
|
|||
return res
|
||||
}
|
||||
|
||||
// TODO remove GetChecked function
|
||||
|
||||
func (s *SEMP) planningRequest(id int, lp core.LoadPointAPI) (res PlanningRequest) {
|
||||
mode := api.ModeOff
|
||||
if modeP, err := s.cache.GetChecked(id, "mode"); err == nil {
|
||||
mode = modeP.Val.(api.ChargeMode)
|
||||
}
|
||||
|
||||
var connected bool
|
||||
if connectedP, err := s.cache.GetChecked(id, "connected"); err == nil {
|
||||
connected = connectedP.Val.(bool)
|
||||
}
|
||||
|
||||
var charging bool
|
||||
if chargingP, err := s.cache.GetChecked(id, "charging"); err == nil {
|
||||
charging = chargingP.Val.(bool)
|
||||
}
|
||||
mode := lp.GetMode()
|
||||
charging := lp.GetStatus() == api.StatusC
|
||||
connected := charging || lp.GetStatus() == api.StatusB
|
||||
|
||||
chargeEstimate := time.Duration(-1)
|
||||
if chargeEstimateP, err := s.cache.GetChecked(id, "chargeEstimate"); err == nil {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue