Skip to content

Peak Shaving Strategy

The Peak Shaving strategy reduces peak grid demand by discharging the battery whenever site import exceeds a configurable power threshold. Its goal is to flatten the load curve - keeping grid draw below the peak threshold at all times while respecting battery SoC limits.

How It Works

For common behaviour shared by all strategies (mode gate, SoC guard, base class helpers), see the Strategies overview.

Each time the strategy fires it runs through this pipeline:

Peak Threshold and Excess

The strategy computes the excess grid import above the configured threshold:

ts
excess = gridPower − PeakThreshold

A positive excess means the site is drawing more from the grid than the target ceiling. The battery discharges at the excess power level to compensate, capping actual grid draw at PeakThreshold. If excess ≤ 0 the site is already within its peak limit and the cycle is skipped.

SoC Guard

Before anything else the strategy checks that the battery SoC is above MinStateOfCharge. If SoC is at or below the minimum the cycle is skipped entirely - the grid import is allowed to exceed the threshold rather than risk over-discharging. See Common Behaviour for the base class pattern.

Because peak shaving only discharges, MaxStateOfCharge does not gate cycles.

Deadband

If excess is positive but falls at or within ControlParameters.Deadband (default 500 W), no command is sent. This prevents chattering for marginal over-threshold conditions where the cost of a setpoint change outweighs the benefit.

Output Pipeline

The raw excess passes through the same output transforms used by Net Zero:

StepDescriptionParameter
ClampConstrains the setpoint to [0, MaxDischargePower]. Peak shaving never charges the battery.BatteryConfiguration.MaxDischargePower
QuantizeRounds to the nearest multiple of DeviceStep using round-half-away-from-zero.ControlParameters.DeviceStep (default 100 W)
Rate limitCaps the change between cycles to prevent large step changes. Uses the last known setpoint from the distributed cache (Gateway:PeakShaving:{batteryName}:LastSetpoint, 5-minute TTL) as the reference. When no cached value exists, 0 W is used as the baseline.ControlParameters.MaxRateOfChange (default 500 W)

Configuration

GridConnectionConfiguration

PeakThreshold is set on the grid connection asset, not on the battery. This reflects that the threshold is a property of the grid connection contract, not of the battery hardware.

ParameterDefaultDescription
PeakThresholdnullPeak import power target (W). The strategy discharges when grid import exceeds this value. Leave null to disable peak shaving on this connection.

ControlParameters (on BatteryConfiguration)

ParameterDefaultDescription
Deadband500 WMinimum excess above PeakThreshold before a setpoint is sent.
MaxRateOfChange500 WMaximum setpoint change per control cycle.
DeviceStep100 WSetpoints are quantized to multiples of this value.

Peak Threshold Selection

PeakThreshold is the most important tuning parameter. Setting it:

  • Too low - the battery discharges frequently but may exhaust SoC before the actual evening peak, leaving no headroom when it matters most.
  • Too high - the strategy rarely fires and peak reduction is minimal.

A practical starting point is the site's tariff-based demand threshold (the import level above which a higher unit rate or demand charge applies). For residential sites without demand tariffs, a value around 50–70% of typical peak import is a reasonable default.

Because peak shaving is purely reactive (it responds to real-time grid power), it pairs naturally with a separate charging strategy (e.g. Charge or Net Zero) that replenishes the battery during off-peak periods. Operating both simultaneously requires a strategy-selection schedule or a combined strategy - neither of which exists yet. See the Roadmap for planned multi-strategy support.

Behaviour Tests

Gateway mode gating is covered by GatewayModeBehaviorTests - see Strategies overview.

Strategy-specific tests are in PeakShavingStrategyTests (Voltimax.Edge.Gateway.Tests):

  • GridPower_BelowThreshold_NoCommandSent - grid below threshold, no setpoint dispatched
  • GridPower_ExceedsThreshold_DischargesExcess - excess = 5 kW, setpoint sent at 5 kW Discharging
  • GridPower_ExceedsThreshold_ClampedToMaxDischargePower - excess exceeds MaxDischargePower, setpoint clamped
  • Excess_WithinDeadband_NoCommandSent - excess within deadband, no setpoint dispatched
  • SoC_AtMinimum_CycleSkipped - SoC at MinStateOfCharge, cycle skipped
  • Quantization_RoundsToDeviceStep - 5 250 W excess quantized to 5 300 W at 100 W step
  • RateLimit_CapsChangeFromLastSetpoint - 10 kW excess rate-limited to 2 500 W from a 2 kW baseline
  • NoPeakThreshold_Configured_CycleSkipped - PeakThreshold = null, skips gracefully without throwing
  • NoGridAsset_Configured_ThrowsInvalidOperationException - no grid asset in config throws