From d96374b5f9e36b68cfea9ed80b55fde7276b52ac Mon Sep 17 00:00:00 2001 From: andig Date: Wed, 27 May 2026 13:36:07 +0200 Subject: [PATCH] Add battery feed-in priority limit --- core/keys/site.go | 3 +++ core/site.go | 6 +++++- core/site_api.go | 30 ++++++++++++++++++++++++++++++ core/site_battery.go | 8 +++++++- 4 files changed, 45 insertions(+), 2 deletions(-) diff --git a/core/keys/site.go b/core/keys/site.go index 8ea653b9822..4aaa8d36829 100644 --- a/core/keys/site.go +++ b/core/keys/site.go @@ -44,6 +44,9 @@ const ( BufferSoc = "bufferSoc" BufferStartSoc = "bufferStartSoc" + BatteryFeedInPriorityLimit = "batteryFeedInPriorityLimit" + BatteryFeedInPriorityActive = "batteryFeedInPriorityActive" + // battery status Battery = "battery" BatteryMode = "batteryMode" diff --git a/core/site.go b/core/site.go index 48a8dbbc7ab..6791df628f3 100644 --- a/core/site.go +++ b/core/site.go @@ -79,6 +79,8 @@ type Site struct { batteryDischargeControl bool // prevent battery discharge for fast and planned charging batteryGridChargeLimit *float64 // grid charging limit + batteryFeedInPriorityLimit *float64 // disable battery charge and prefer feed-in at this limit + loadpoints []*Loadpoint // Loadpoints tariffs *tariff.Tariffs // Tariffs coordinator *coordinator.Coordinator // Vehicles @@ -1025,7 +1027,9 @@ func (site *Site) update(lp updater) { // update battery after reading meters to ensure that (modbus) connection is open batteryGridChargeActive := site.batteryGridChargeActive(rate) site.publish(keys.BatteryGridChargeActive, batteryGridChargeActive) - site.updateBatteryMode(batteryGridChargeActive, rate) + batteryFeedInPriorityActive := site.batteryFeedInPriorityActive(rate) + site.publish(keys.BatteryFeedInPriorityActive, batteryFeedInPriorityActive) + site.updateBatteryMode(batteryGridChargeActive, batteryFeedInPriorityActive, rate) site.stats.Update(site) } diff --git a/core/site_api.go b/core/site_api.go index b079039d8d3..472b4cb2a96 100644 --- a/core/site_api.go +++ b/core/site_api.go @@ -371,6 +371,36 @@ func (site *Site) SetBatteryGridChargeLimit(val *float64) error { return nil } +func (site *Site) GetBatteryFeedInPriorityLimit() *float64 { + site.RLock() + defer site.RUnlock() + return site.batteryFeedInPriorityLimit +} + +func (site *Site) SetBatteryFeedInPriorityLimit(val *float64) error { + site.log.DEBUG.Println("set feed-in priority limit:", printPtr("%.1f", val)) + + if !site.hasBatteryControl() { + return ErrBatteryControlNotAvailable + } + + site.Lock() + defer site.Unlock() + + if !ptrValueEqual(site.batteryFeedInPriorityLimit, val) { + site.batteryFeedInPriorityLimit = val + + if val == nil { + settings.SetString(keys.BatteryFeedInPriorityLimit, "") + site.publish(keys.BatteryFeedInPriorityLimit, nil) + } else { + settings.SetFloat(keys.BatteryFeedInPriorityLimit, *val) + site.publish(keys.BatteryFeedInPriorityLimit, *val) + } + } + + return nil +} // GetBatteryMode returns the battery mode func (site *Site) GetBatteryMode() api.BatteryMode { diff --git a/core/site_battery.go b/core/site_battery.go index a052bc74ccc..ca586398c61 100644 --- a/core/site_battery.go +++ b/core/site_battery.go @@ -52,7 +52,8 @@ func (site *Site) SetBatteryMode(batMode api.BatteryMode) { } } -func (site *Site) updateBatteryMode(batteryGridChargeActive bool, rate api.Rate) { +// TODO implement batteryFeedInPriorityActive +func (site *Site) updateBatteryMode(batteryGridChargeActive, batteryFeedInPriorityActive bool, rate api.Rate) { batteryMode := site.requiredBatteryMode(batteryGridChargeActive, rate) // put battery into hold mode when charging is active and circuit dimmed @@ -202,6 +203,11 @@ func (site *Site) batteryGridChargeActive(rate api.Rate) bool { return limit != nil && !rate.IsZero() && rate.Value <= *limit } +func (site *Site) batteryFeedInPriorityActive(rate api.Rate) bool { + limit := site.GetBatteryFeedInPriorityLimit() + return limit != nil && !rate.IsZero() && rate.Value <= *limit +} + func (site *Site) dischargeControlActive(rate api.Rate) bool { if !site.GetBatteryDischargeControl() { return false