Skip to content

[Feature Request] Multi-Battery Coordination for Mixed Manufacturers #3303

@ian-morgan99

Description

@ian-morgan99

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

  1. 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
  2. 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
  3. apps/predbat/config.py (Configuration)
    Add new config options: multi_battery_coordination, master_inverter, slave_transition_delay
  4. 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions