Skip to content

Strategies

Strategies are the gateway's autonomous control modes. Each strategy is responsible for computing a battery setpoint on every control cycle and dispatching a SetBatterySetpointCommand. The active strategy is selected by the platform and stored in the gateway's desired state; the gateway applies it on a recurring tick.

Available Strategies

StrategyDescription
Net ZeroMinimises grid import/export using a PID feedback loop
DischargeDischarges the battery at maximum power until MinStateOfCharge is reached
ChargeCharges the battery at maximum power until MaxStateOfCharge is reached
Peak ShavingReduces peak grid demand by capping import above a target threshold
ManualSuppresses automatic strategy execution; only explicit commands are accepted

Common Behaviour

All strategies share these mechanisms regardless of their specific logic.

Mode Gate

Before any strategy runs, ApplyStrategyCommandHandler checks the current GatewayMode. If the gateway is in Manual mode, the strategy is skipped entirely and the command returns without calling IStrategy.ApplyStrategy. This gate applies to every strategy - individual strategy code never needs to check the mode.

The gateway can be switched between modes via the platform API. See Gateway Service for details.

AbstractStrategy Base Class

All concrete strategies extend AbstractStrategy, which provides two helpers used at the start of every control cycle:

  • GetBatteryConfiguration() - loads the current BatteryConfiguration (SoC limits, power limits, PID tuning, control parameters) for the single battery asset.
  • GetBatteryName() - resolves the asset name used in subsequent commands and queries.

Both helpers throw InvalidOperationException if no battery asset is configured, which surfaces as a strategy failure log and does not crash the gateway process.

SoC Guard

Every strategy checks the battery SoC against MinStateOfCharge and/or MaxStateOfCharge before dispatching a setpoint. The exact guard and fallback behaviour differs per strategy - see each strategy's page for specifics.

Terminal Action

Every strategy cycle ends with SetBatterySetpointCommand(batteryName, setpointWatts, mode), where mode is one of Charging, Discharging, or Idle. The setpoint and mode are the only two things a strategy produces.

Registration

Strategies are registered as keyed singletons in StrategyRegistration.AddStrategies(), keyed by their Strategy enum value. StrategyFactory resolves the correct instance at runtime via [FromKeyedServices].

Because strategies are singletons they must be thread-safe. Stateful strategies (e.g. Net Zero, which holds a PidController) must manage their internal state carefully.

Behaviour Tests

Gateway-level mode-gating behaviour is covered by GatewayModeBehaviorTests (LightBDD, Voltimax.Edge.Gateway.BehaviorTests):

  • Manual mode suppresses strategy execution - ApplyStrategyCommand is dispatched but IStrategy.ApplyStrategy is never called.
  • Auto mode allows strategy execution - the resolved strategy runs normally.