Fix uptime and energy calculation on charging start (#2253)

This commit is contained in:
Michael Geers 2022-01-10 16:40:02 +01:00 • committed by GitHub
parent feb71d46d5
commit c124e110bf
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 55 additions and 30 deletions

View file

@ -127,7 +127,7 @@
<br />
{{
$t("footer.savings.modalServerStart", {
since: fmtTimeAgo(since * -1000),
since: fmtTimeAgo(secondsSinceStart()),
})
}}
</p>
@ -181,6 +181,11 @@ export default {
return Math.round(this.selfConsumptionPercent) || 0;
},
},
methods: {
secondsSinceStart() {
return this.since * 1000 - Date.now();
},
},
};
</script>
<style scoped>

View file

@ -18,15 +18,15 @@ type publisher interface {
// Site is the main configuration container. A site can host multiple loadpoints.
type Savings struct {
clock clock.Clock
tariffs tariff.Tariffs
started time.Time // Boot time
updated time.Time // Time of last charged value update
gridCharged float64 // Grid energy charged since startup (kWh)
gridCost float64 // Running total of charged grid energy cost (e.g. EUR)
selfConsumptionCharged float64 // Self-produced energy charged since startup (kWh)
selfConsumptionCost float64 // Running total of charged self-produced energy cost (e.g. EUR)
lastGridPrice float64 // Stores the last published grid price. Needed to detect price changes (Awattar, ..)
clock clock.Clock
tariffs tariff.Tariffs
started time.Time // Boot time
updated time.Time // Time of last charged value update
gridCharged float64 // Grid energy charged since startup (kWh)
gridCost float64 // Running total of charged grid energy cost (e.g. EUR)
selfConsumptionCharged float64 // Self-produced energy charged since startup (kWh)
selfConsumptionCost float64 // Running total of charged self-produced energy cost (e.g. EUR)
lastGridPrice, lastFeedInPrice float64 // Stores the last published grid price. Needed to detect price changes (Awattar, ..)
}
func NewSavings(tariffs tariff.Tariffs) *Savings {
@ -41,8 +41,8 @@ func NewSavings(tariffs tariff.Tariffs) *Savings {
return savings
}
func (s *Savings) Since() time.Duration {
return time.Since(s.started)
func (s *Savings) Since() time.Time {
return s.started
}
func (s *Savings) SelfConsumptionPercent() float64 {
@ -106,26 +106,42 @@ func (s *Savings) currentFeedInPrice() float64 {
return DefaultFeedInPrice
}
func (s *Savings) Update(p publisher, gridPower, pvPower, batteryPower, chargePower float64) {
// assume charge power as constant over the duration -> rough kWh estimate
energyAdded := s.clock.Since(s.updated).Hours() * chargePower / 1e3
func (s *Savings) updatePrices(p publisher) (float64, float64) {
gridPrice := s.currentGridPrice()
if gridPrice != s.lastGridPrice {
s.lastGridPrice = gridPrice
p.publish("tariffGrid", gridPrice)
}
// nothing meaningfull changed, no need to update
if energyAdded == 0 && s.lastGridPrice == s.currentGridPrice() {
feedinPrice := s.currentFeedInPrice()
if feedinPrice != s.lastFeedInPrice {
s.lastFeedInPrice = feedinPrice
p.publish("tariffFeedIn", feedinPrice)
}
return gridPrice, feedinPrice
}
func (s *Savings) Update(p publisher, gridPower, pvPower, batteryPower, chargePower float64) {
gridPrice, feedinPrice := s.updatePrices(p)
defer func() { s.updated = s.clock.Now() }()
// no charging, no need to update
if chargePower == 0 {
return
}
// assume charge power as constant over the duration -> rough kWh estimate
energyAdded := s.clock.Since(s.updated).Hours() * chargePower / 1e3
share := s.shareOfSelfProducedEnergy(gridPower, pvPower, batteryPower)
addedSelfConsumption := energyAdded * share
addedGrid := energyAdded - addedSelfConsumption
s.gridCharged += addedGrid
s.gridCost += addedGrid * s.currentGridPrice()
s.gridCost += addedGrid * gridPrice
s.selfConsumptionCharged += addedSelfConsumption
s.selfConsumptionCost += addedSelfConsumption * s.currentFeedInPrice()
s.lastGridPrice = s.currentGridPrice()
s.updated = s.clock.Now()
s.selfConsumptionCost += addedSelfConsumption * feedinPrice
p.publish("savingsTotalCharged", s.TotalCharged())
p.publish("savingsGridCharged", s.gridCharged)
@ -133,6 +149,4 @@ func (s *Savings) Update(p publisher, gridPower, pvPower, batteryPower, chargePo
p.publish("savingsSelfConsumptionPercent", s.SelfConsumptionPercent())
p.publish("savingsEffectivePrice", s.EffectivePrice())
p.publish("savingsAmount", s.SavingsAmount())
p.publish("tariffGrid", s.currentGridPrice())
p.publish("tariffFeedIn", s.currentFeedInPrice())
}

View file

@ -108,6 +108,12 @@ func TestSavingsWithDifferentTimespans(t *testing.T) {
steps []tcStep
total, self, percentage float64
}{
{"10 second not charging, full grid",
[]tcStep{
{10 * time.Second, 1000, 0, 0, 0},
},
0, 0, 0, // 0Wh
},
{"10 second 11kW charging, full grid",
[]tcStep{
{10 * time.Second, 0, 0, 0, 11000},

View file

@ -436,7 +436,7 @@ func (site *Site) update(lp Updater) {
// prepare publishes initial values
func (site *Site) prepare() {
site.publish("currency", site.tariffs.Currency.String())
site.publish("savingsSince", site.savings.Since())
site.publish("savingsSince", site.savings.Since().Unix())
}
// Prepare attaches communication channels to site and loadpoints

File diff suppressed because one or more lines are too long

4
dist/index.html vendored
View file

@ -1,5 +1,5 @@
<!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.4692b1e2.css" rel="preload" as="style"><link href="css/index.77f18cb6.css" rel="preload" as="style"><link href="js/chunk-vendors.323cc329.js" rel="preload" as="script"><link href="js/index.2b1f2a0a.js" rel="preload" as="script"><link href="css/chunk-vendors.4692b1e2.css" rel="stylesheet"><link href="css/index.77f18cb6.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.4692b1e2.css" rel="preload" as="style"><link href="css/index.def25fd4.css" rel="preload" as="style"><link href="js/chunk-vendors.323cc329.js" rel="preload" as="script"><link href="js/index.768ebb48.js" rel="preload" as="script"><link href="css/chunk-vendors.4692b1e2.css" rel="stylesheet"><link href="css/index.def25fd4.css" rel="stylesheet"></head><body><script>window.evcc = {
version: "[[.Version]]",
configured: "[[.Configured]]",
commit: "[[.Commit]]",
};</script><div id="app"></div><script src="js/chunk-vendors.323cc329.js"></script><script src="js/index.2b1f2a0a.js"></script></body></html>
};</script><div id="app"></div><script src="js/chunk-vendors.323cc329.js"></script><script src="js/index.768ebb48.js"></script></body></html>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

2
dist/js/index.768ebb48.js vendored Normal file

File diff suppressed because one or more lines are too long

1
dist/js/index.768ebb48.js.map vendored Normal file

File diff suppressed because one or more lines are too long