Fix target charging (#1872)
This commit is contained in:
parent
d690633020
commit
fbe6532aa3
9 changed files with 55 additions and 29 deletions
|
|
@ -6,7 +6,7 @@
|
|||
{{ $t("main.vehicleSubline.mincharge", { soc: minSoC }) }}
|
||||
</span>
|
||||
</small>
|
||||
<TargetCharge v-bind="targetCharge" @target-time-updated="targetTimeUpdated" v-if="false" />
|
||||
<TargetCharge v-bind="targetCharge" @target-time-updated="targetTimeUpdated" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
|
|
|||
|
|
@ -1390,7 +1390,7 @@ func (lp *LoadPoint) Update(sitePower float64, cheap bool, batteryBuffered bool)
|
|||
}
|
||||
|
||||
// target charging
|
||||
case lp.socTimer.DemandActive() && false:
|
||||
case lp.socTimer.DemandActive():
|
||||
targetCurrent := lp.socTimer.Handle()
|
||||
err = lp.setLimit(targetCurrent, true)
|
||||
|
||||
|
|
|
|||
|
|
@ -55,6 +55,12 @@ func (lp *LoadPoint) GetTargetSoC() int {
|
|||
return lp.SoC.Target
|
||||
}
|
||||
|
||||
func (lp *LoadPoint) setTargetSoC(soc int) {
|
||||
lp.SoC.Target = soc
|
||||
lp.socTimer.SoC = soc
|
||||
lp.publish("targetSoC", soc)
|
||||
}
|
||||
|
||||
// SetTargetSoC sets loadpoint charge target soc
|
||||
func (lp *LoadPoint) SetTargetSoC(soc int) {
|
||||
lp.Lock()
|
||||
|
|
@ -64,8 +70,7 @@ func (lp *LoadPoint) SetTargetSoC(soc int) {
|
|||
|
||||
// apply immediately
|
||||
if lp.SoC.Target != soc {
|
||||
lp.SoC.Target = soc
|
||||
lp.publish("targetSoC", soc)
|
||||
lp.setTargetSoC(soc)
|
||||
lp.requestUpdate()
|
||||
}
|
||||
}
|
||||
|
|
@ -105,21 +110,20 @@ func (lp *LoadPoint) SetPhases(phases int) error {
|
|||
}
|
||||
|
||||
// SetTargetCharge sets loadpoint charge targetSoC
|
||||
func (lp *LoadPoint) SetTargetCharge(finishAt time.Time, targetSoC int) {
|
||||
func (lp *LoadPoint) SetTargetCharge(finishAt time.Time, soc int) {
|
||||
lp.Lock()
|
||||
defer lp.Unlock()
|
||||
|
||||
lp.log.DEBUG.Printf("set target charge: %d @ %v", targetSoC, finishAt)
|
||||
lp.log.DEBUG.Printf("set target charge: %d @ %v", soc, finishAt)
|
||||
|
||||
// apply immediately
|
||||
// TODO check reset of targetSoC
|
||||
lp.publish("targetTime", finishAt)
|
||||
lp.publish("targetSoC", targetSoC)
|
||||
if lp.socTimer.Time != finishAt || lp.SoC.Target != soc {
|
||||
lp.publish("targetTime", finishAt)
|
||||
lp.socTimer.Time = finishAt
|
||||
|
||||
lp.socTimer.Time = finishAt
|
||||
lp.socTimer.SoC = targetSoC
|
||||
|
||||
lp.requestUpdate()
|
||||
lp.setTargetSoC(soc)
|
||||
lp.requestUpdate()
|
||||
}
|
||||
}
|
||||
|
||||
// RemoteControl sets remote status demand
|
||||
|
|
|
|||
|
|
@ -50,6 +50,18 @@ func (s *Estimator) Reset() {
|
|||
s.energyPerSocStep = s.virtualCapacity / 100
|
||||
}
|
||||
|
||||
// AssumedChargeDuration estimates charge duration up to targetSoC based on virtual capacity
|
||||
func (s *Estimator) AssumedChargeDuration(targetSoC int, chargePower float64) time.Duration {
|
||||
percentRemaining := float64(targetSoC) - s.vehicleSoc
|
||||
|
||||
if percentRemaining <= 0 {
|
||||
return 0
|
||||
}
|
||||
|
||||
whRemaining := percentRemaining / 100 * s.virtualCapacity
|
||||
return time.Duration(float64(time.Hour) * whRemaining / chargePower).Round(time.Second)
|
||||
}
|
||||
|
||||
// RemainingChargeDuration returns the remaining duration estimate based on SoC, target and charge power
|
||||
func (s *Estimator) RemainingChargeDuration(chargePower float64, targetSoC int) time.Duration {
|
||||
if chargePower > 0 {
|
||||
|
|
@ -71,9 +83,7 @@ func (s *Estimator) RemainingChargeDuration(chargePower float64, targetSoC int)
|
|||
}
|
||||
}
|
||||
|
||||
// estimate remaining time
|
||||
whRemaining := percentRemaining / 100 * s.virtualCapacity
|
||||
return time.Duration(float64(time.Hour) * whRemaining / chargePower).Round(time.Second)
|
||||
return s.AssumedChargeDuration(targetSoC, chargePower)
|
||||
}
|
||||
|
||||
return -1
|
||||
|
|
|
|||
|
|
@ -39,9 +39,9 @@ func (lp *Timer) Reset() {
|
|||
return
|
||||
}
|
||||
|
||||
lp.current = float64(lp.GetMaxCurrent())
|
||||
lp.current = lp.GetMaxCurrent()
|
||||
lp.Time = time.Time{}
|
||||
lp.SoC = 0
|
||||
lp.active = false
|
||||
}
|
||||
|
||||
// DemandActive calculates remaining charge duration and returns true if charge start is required to achieve target soc in time
|
||||
|
|
@ -50,9 +50,7 @@ func (lp *Timer) DemandActive() bool {
|
|||
return false
|
||||
}
|
||||
|
||||
se := lp.SocEstimator()
|
||||
if se == nil {
|
||||
lp.log.WARN.Printf("target charging: not possible")
|
||||
if lp.Time.IsZero() {
|
||||
return false
|
||||
}
|
||||
|
||||
|
|
@ -68,14 +66,28 @@ func (lp *Timer) DemandActive() bool {
|
|||
power *= lp.current / lp.GetMaxCurrent()
|
||||
}
|
||||
|
||||
se := lp.SocEstimator()
|
||||
if se == nil {
|
||||
lp.log.WARN.Printf("target charging: not possible")
|
||||
return false
|
||||
}
|
||||
|
||||
// time
|
||||
remainingDuration := se.RemainingChargeDuration(power, lp.SoC)
|
||||
remainingDuration := se.AssumedChargeDuration(lp.SoC, power)
|
||||
lp.finishAt = time.Now().Add(remainingDuration).Round(time.Minute)
|
||||
|
||||
lp.log.DEBUG.Printf("estimated charge duration: %v to %d%% at %.0fW", remainingDuration.Round(time.Minute), lp.SoC, power)
|
||||
if lp.active {
|
||||
lp.log.DEBUG.Printf("projected end: %v", lp.finishAt)
|
||||
lp.log.DEBUG.Printf("desired finish time: %v", lp.Time)
|
||||
} else {
|
||||
lp.log.DEBUG.Printf("projected start: %v", lp.Time.Add(-remainingDuration))
|
||||
}
|
||||
|
||||
// timer charging is already active- only deactivate once charging has stopped
|
||||
if lp.active {
|
||||
if time.Now().After(lp.Time) && lp.GetStatus() != api.StatusC {
|
||||
lp.log.TRACE.Printf("target charging: deactivating")
|
||||
lp.log.INFO.Printf("target charging: deactivating")
|
||||
lp.active = false
|
||||
}
|
||||
|
||||
|
|
@ -85,7 +97,7 @@ func (lp *Timer) DemandActive() bool {
|
|||
// check if charging need be activated
|
||||
if lp.active = lp.finishAt.After(lp.Time); lp.active {
|
||||
lp.current = lp.GetMaxCurrent()
|
||||
lp.log.DEBUG.Printf("target charging active for %v: projected %v (%v remaining)", lp.Time, lp.finishAt, remainingDuration.Round(time.Minute))
|
||||
lp.log.INFO.Printf("target charging active for %v: projected %v (%v remaining)", lp.Time, lp.finishAt, remainingDuration.Round(time.Minute))
|
||||
}
|
||||
|
||||
return lp.active
|
||||
|
|
|
|||
4
dist/index.html
vendored
4
dist/index.html
vendored
|
|
@ -1,4 +1,4 @@
|
|||
<!DOCTYPE html><html lang="de"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><meta name="description" content="EV Charge Controller"><meta name="author" content="andig"><meta name="apple-mobile-web-app-capable" content="yes"><meta name="apple-mobile-web-app-status-bar-style" content="black"><link rel="apple-touch-icon" sizes="180x180" href="ico/apple-touch-icon.png?[[.Version]]"><link rel="icon" type="image/png" sizes="32x32" href="ico/favicon-32x32.png?[[.Version]]"><link rel="icon" type="image/png" sizes="16x16" href="ico/favicon-16x16.png?[[.Version]]"><link rel="manifest" href="ico/site.webmanifest"><link rel="mask-icon" href="ico/safari-pinned-tab.svg?[[.Version]]" color="#18191a"><link rel="shortcut icon" href="ico/favicon.ico?[[.Version]]"><meta name="apple-mobile-web-app-title" content="evcc"><meta name="application-name" content="evcc"><meta name="msapplication-TileColor" content="#18191a"><meta name="msapplication-config" content="ico/browserconfig.xml"><meta name="theme-color" content="#18191a"><title>evcc</title><link href="css/chunk-vendors.a7b690cd.css" rel="preload" as="style"><link href="css/index.31975401.css" rel="preload" as="style"><link href="js/chunk-vendors.6e78ad3a.js" rel="preload" as="script"><link href="js/index.1a5119f8.js" rel="preload" as="script"><link href="css/chunk-vendors.a7b690cd.css" rel="stylesheet"><link href="css/index.31975401.css" rel="stylesheet"></head><body><script>window.evcc = {
|
||||
<!DOCTYPE html><html lang="de"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><meta name="description" content="EV Charge Controller"><meta name="author" content="andig"><meta name="apple-mobile-web-app-capable" content="yes"><meta name="apple-mobile-web-app-status-bar-style" content="black"><link rel="apple-touch-icon" sizes="180x180" href="ico/apple-touch-icon.png?[[.Version]]"><link rel="icon" type="image/png" sizes="32x32" href="ico/favicon-32x32.png?[[.Version]]"><link rel="icon" type="image/png" sizes="16x16" href="ico/favicon-16x16.png?[[.Version]]"><link rel="manifest" href="ico/site.webmanifest"><link rel="mask-icon" href="ico/safari-pinned-tab.svg?[[.Version]]" color="#18191a"><link rel="shortcut icon" href="ico/favicon.ico?[[.Version]]"><meta name="apple-mobile-web-app-title" content="evcc"><meta name="application-name" content="evcc"><meta name="msapplication-TileColor" content="#18191a"><meta name="msapplication-config" content="ico/browserconfig.xml"><meta name="theme-color" content="#18191a"><title>evcc</title><link href="css/chunk-vendors.a7b690cd.css" rel="preload" as="style"><link href="css/index.31975401.css" rel="preload" as="style"><link href="js/chunk-vendors.6e78ad3a.js" rel="preload" as="script"><link href="js/index.c646bc03.js" rel="preload" as="script"><link href="css/chunk-vendors.a7b690cd.css" rel="stylesheet"><link href="css/index.31975401.css" rel="stylesheet"></head><body><script>window.evcc = {
|
||||
version: "[[.Version]]",
|
||||
configured: "[[.Configured]]",
|
||||
};</script><div id="app"></div><script src="js/chunk-vendors.6e78ad3a.js"></script><script src="js/index.1a5119f8.js"></script></body></html>
|
||||
};</script><div id="app"></div><script src="js/chunk-vendors.6e78ad3a.js"></script><script src="js/index.c646bc03.js"></script></body></html>
|
||||
1
dist/js/index.1a5119f8.js.map
vendored
1
dist/js/index.1a5119f8.js.map
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
1
dist/js/index.c646bc03.js.map
vendored
Normal file
1
dist/js/index.c646bc03.js.map
vendored
Normal file
File diff suppressed because one or more lines are too long
Loading…
Add table
Add a link
Reference in a new issue