-
-
Notifications
You must be signed in to change notification settings - Fork 96
Description
Problem Statement
When running two batteries from different manufacturers (e.g., GivEnergy + Alpha ESS), they can have different response times to mode change commands. Without coordination, rapid transitions between charge/discharge can result in:
Cross-charging: One battery charging while the other discharges
Energy waste: Battery cycles used charging each other instead of serving the house
Inverter conflicts: Simultaneous state changes causing grid stress
This is particularly problematic when:
External control is active (Octopus Intelligent)
Frequent rate changes occur (Agile tariff)
Plan recalculations trigger rapid mode switches
Proposed Solution
Add opt-in multi-battery coordination that:
Designates one battery as "master" and others as "slave(s)"
Always transitions slave batteries through ECO/self-consumption mode before state changes
Verifies each battery has stabilized before proceeding
Works transparently with all existing Predbat modes and features
Core principle: Slow down rapid state transitions and ensure slaves always go via ECO mode.
Describe alternatives you've considered
Just setting both inverters in config. However, there is a risk that delays in passing charge/discharge instructions to the batteries could result in one discharging whilst the other is charging.
** Other context **
This request originated from a discussion in FB:
https://www.facebook.com/share/p/181zwEistE/
Github Copilot Suggests the following method, but I should clarify that I am not sufficiently familiar with the code at this point to verify it. I may attempt to do so over the coming weeks:
Implementation Location
The coordination logic should sit in apps/predbat/execute.py within the execute_plan() method, specifically:
Before inverter commands (lines 69-590): Add pre-transition coordination check
Wrap state changes: Intercept calls to adjust_charge_window(), adjust_force_export(), etc.
After state changes: Verify transitions completed successfully
Minimal Code Changes
Python
In execute.py, before line 69 (start of inverter loop)
class Execute:
def execute_plan(self):
# NEW: Pre-flight coordination check
if self.multi_battery_coordination_enabled():
self.coordinate_battery_transitions()
# EXISTING: Loop over inverters
for inverter in self.inverters:
# ... existing code unchanged ...
Python
NEW: Coordination wrapper for state changes
def safe_battery_transition(self, inverter, new_state, action_fn):
"""
Safely transition a battery to new state with coordination
Args:
inverter: Inverter object
new_state: Target state ("charging", "exporting", "eco")
action_fn: Function to execute the actual inverter command
"""
if not self.is_coordinated_battery(inverter):
# Master battery or independent mode - direct execution
return action_fn()
# Slave battery - must go via ECO first
if self.should_transition_via_eco(inverter, new_state):
self.log(f"Inverter {inverter.id} (slave) transitioning via ECO to {new_state}")
# Step 1: Set to ECO mode
inverter.adjust_inverter_mode(force_export=False)
# Step 2: Wait for power to stabilize (default 30 seconds)
if not self.wait_for_stable_power(inverter, timeout=self.slave_transition_delay):
self.log(f"Warn: Inverter {inverter.id} did not stabilize, aborting transition")
return False
# Step 3: Now safe to execute target action
return action_fn()
else:
# Already in ECO or direct transition is safe
return action_fn()
Configuration (apps.yaml)
YAML
Existing multi-inverter config
num_inverters: 2
inverter_type:
- "GE" # Master
- "ALPHA" # Slave
NEW: Optional coordination settings (default: off)
multi_battery_coordination: False # Set to True to enable
master_inverter: 0 # Index of master battery
slave_transition_delay: 30 # Seconds to wait for slave to stabilize
cross_charge_threshold: 200 # Watts - detect if one charges the other
Where Code Changes Are Needed
- apps/predbat/execute.py (Primary changes)
Add coordination check at start of execute_plan()
Wrap inverter state change calls with safe_battery_transition()
Add power monitoring for cross-charge detection - apps/predbat/inverter.py (Helper methods)
Add get_current_mode() - read actual inverter state
Add wait_for_power_stable() - monitor battery power flow
Existing methods (adjust_charge_window(), adjust_force_export()) unchanged - apps/predbat/config.py (Configuration)
Add new config options: multi_battery_coordination, master_inverter, slave_transition_delay - docs/apps-yaml.md (Documentation)
Document new multi-battery coordination settings
Compatibility with Existing Features
✅ Works with all Predbat modes: Monitor, Control SoC, Control Charge, Control Charge & Discharge
✅ Respects read-only mode: Coordination disabled when set_read_only=True
✅ Compatible with Octopus Intelligent: Slave follows master's externally-controlled state
✅ Works with manual overrides: Manual controls apply to master, slave follows
✅ Preserves balance_inverters: Coordination pauses during active balancing
✅ No changes to single battery setups: Only activates when explicitly enabled
State Transition Strategy
Master Battery: Normal Predbat control (no changes)
Slave Battery:
Code
Current State → ECO Mode → Verify Stable → Target State
Safe Transitions (always via ECO):
Charging → Discharging
Discharging → Charging
Any → ECO (direct)
Monitoring: Continuously check for cross-charging condition:
Python
if (master.battery_power < -200W and slave.battery_power > 200W) or
(slave.battery_power < -200W and master.battery_power > 200W):
# Cross-charging detected - force both to ECO
self.emergency_eco_mode()
Benefits
Prevents energy waste from cross-charging
Manufacturer agnostic - works with any inverter combination
Minimal code changes - wraps existing execution flow
Opt-in design - zero impact on existing users
Future-proof - easily extends to 3+ batteries
Implementation Phases
Phase 1 (MVP):
Basic master/slave coordination
ECO transition logic
Configuration options
Phase 2 (Safety):
Power flow monitoring
Cross-charge detection
Emergency fallback
Phase 3 (Polish):
Octopus Intelligent integration
Balance inverters cooperation
Enhanced logging/debugging
Questions for Maintainer
Should this be a separate class (BatteryCoordinator) or methods within Execute?
Preferred approach for inverter state verification? (polling vs. events)
Default timing values for slave_transition_delay? (suggest 30 seconds)
Should we add a multi_battery_mode: "coordinated" option to make it more explicit?
Minimal invasive approach: The key is that slave batteries always pause in ECO mode before any state change, giving the master time to stabilize first. This simple rule prevents 99% of cross-charging scenarios with minimal code complexity.