Skip to content

Predbat ignores best_soc_keep and discharges battery below configured minimum #3207

@InvertedMinor

Description

@InvertedMinor

Predbat Ignores best_soc_keep and Discharges Battery Below Configured Minimum

Summary

Predbat completely ignores best_soc_keep: 30, best_soc_min: 30, and set_reserve_min: 30 settings and allows battery to discharge to 14% SOC, far below the configured 30% minimum. This is a critical safety issue that can damage lithium batteries.

Environment

  • **Predbat version: v8.31.14
  • Inverter: Growatt SPH 10000TL3 BH-UP (via OpenInverterGateway MQTT)
  • Battery: 15kWh
  • Date of incident: 2026-01-10, 00:00 - 08:30

Configuration

Battery & SOC Settings

# From apps.yaml
best_soc_min: input_number.battery_minimum_soc  # Set to 30%
best_soc_keep: 30
best_soc_max: 100
set_reserve_min: 30

battery_rate_max_charge: 6000
battery_rate_max_discharge: 6000
battery_rate_max:
  - 6000
soc_max:
  - 15
battery_loss: 0.05
battery_loss_discharge: 0.05

Inverter Configuration

inverter_type: GROWATT_MQTT
num_inverters: 1

# Inverter limits
inverter_limit: 8000
inverter_limit_charge:
  - 6000
inverter_limit_discharge:
  - 6000

# Reserve control
set_reserve_enable: true
set_reserve_min: 30
reserve_percent_tolerance: 2

# Service call management (to handle MQTT timing issues)
service_call_repeat_minutes: 5

# Charge control services
charge_start_service:
  - service: script.predbat_charge_start
    domain: charge
charge_stop_service:
  - service: script.predbat_charge_stop
    domain: charge
charge_freeze_service:
  - service: script.predbat_charge_freeze
    domain: charge

# Discharge control services
discharge_start_service:
  - service: script.predbat_discharge_start
    domain: discharge
discharge_stop_service:
  - service: script.predbat_discharge_stop
    domain: discharge
discharge_freeze_service:
  - service: script.predbat_discharge_freeze
    domain: discharge

# Reserve control
set_reserve_service:
  - service: script.predbat_set_reserve
    domain: reserve

# Inverter doesn't support scheduled charge windows
scheduled_charge_enable: false
scheduled_discharge_enable: false

Sensor Mappings

soc_kw:
  - sensor.growatt_battery_soc_kwh
soc_percent:
  - sensor.growatt_battery_soc
battery_power:
  - sensor.growatt_battery_power
pv_power:
  - sensor.growatt_pv_power
load_power:
  - sensor.growatt_load_power
charge_rate:
  - number.charge_power_rate
discharge_rate:
  - number.discharge_power_rate
reserve:
  - number.discharge_stop_soc
charge_limit:
  - number.charge_stop_soc

Expected Behavior

With best_soc_keep: 30 configured:

  1. Predbat should maintain battery at minimum 30% SOC
  2. Predbat should charge immediately if battery drops below 30%
  3. Predbat should NEVER plan to discharge below 30%

From documentation: best_soc_keep should force Predbat to keep battery at or above this level, charging if needed regardless of price optimization.

Actual Behavior

Predbat completely ignored all three minimum settings and allowed battery to discharge to 14% SOC.

Timeline (2026-01-10):

  • 00:00: Battery 29% - just below minimum
  • 03:00: Battery 26% - Predbat still planning no charge
  • 04:30: Battery 24% - CRITICAL BATTERY alert triggered
  • 06:00: Battery 19% - continuing to discharge
  • 08:30: Battery 14% - absolute minimum reached

Predbat Logs During Incident:

2026-01-09 21:30:02: No charging is planned
2026-01-09 21:30:02: The battery is currently at 26% and is in eco mode
2026-01-09 21:30:02: Import rates are expensive (21.3c - 23.3c) for the next 4.5 hours then cheap (20.9c) for the next 3 hours
2026-01-09 21:30:02: Best charging limit SoC's []kWh, export []kWh gives import battery 0kWh

Predbat saw battery at 26%, recognized cheap rates were coming, and planned NO charging despite being 4% below configured minimum.

Reserve Status

The inverter reserve (number.discharge_stop_soc) was correctly set to 30% by Predbat:

Inverter 0 Current reserve is 30%, already at target

However, this only prevents FUTURE discharge - it doesn't trigger charging when already below the reserve level.

Cost Optimization Override

It appears Predbat's cost optimization completely overrides the best_soc_keep safety setting. In this case:

  • Current electricity: €0.23/kWh
  • Cheaper rates coming: €0.20/kWh
  • Savings: ~€0.45 per charge cycle

Predbat prioritized saving €0.45 over battery safety, discharging 16% below the configured minimum.

Impact

This is a critical safety issue:

  1. Deep discharges (below 20%) reduce lithium battery lifespan
  2. Discharging to 14% risks triggering BMS protection cutoff
  3. If power outage occurs at 14%, entire house loses backup power
  4. Users cannot trust their configured minimum SOC settings

Attempted Workarounds

  1. best_soc_keep: 30 - Completely ignored
  2. best_soc_min: input_number.battery_minimum_soc - Ignored
  3. set_reserve_min: 30 - Sets reserve but doesn't trigger charging
  4. metric_min_improvement: 1.0 - No effect
  5. ✓ Manual safety automation - Required to force charging

Reproduction Steps

  1. Set best_soc_keep: 30 in apps.yaml
  2. Let battery discharge to 29% through normal operation
  3. Ensure cheaper electricity rates are coming in next 3-4 hours
  4. Observe Predbat plan "No charging is planned"
  5. Watch battery continue discharging well below 30%

Expected Fix

best_soc_keep should be a HARD FLOOR that:

  1. Immediately triggers charging if battery is below this level
  2. Overrides ALL cost optimization when battery is below this level
  3. Never plans to discharge below this level
  4. Logs a warning when this safety limit is active

Additional Information

  • Dynamic pricing: ENTSO-e (Dutch day-ahead market)
  • Typical price variation: €0.18 - €0.29/kWh
  • Battery reserve control working (MQTT delays handled with 5-second delays + tolerance)
  • Predbat successfully optimizes charge/discharge cycles when SOC is above minimum

Question for Maintainers

Is best_soc_keep intended to be a hard safety minimum, or just a "preference"? The documentation suggests it should force charging, but the implementation appears to treat it as advisory only, allowing cost optimization to override it.

If best_soc_keep is not intended as a safety floor, what is the recommended way to ensure Predbat NEVER discharges below a critical minimum SOC?

Metadata

Metadata

Labels

No labels
No labels

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions