Skip to content

Commit df4fd06

Browse files
committed
Allow charging.level to re-anchor PHEV prediction downward during charging
The PHEV sync-down protection from 7d5e4bd only updated display values, which the monotonicity guard in get_predicted_soc() silently overrode. Pass a from_charging_level flag so update_bmw_soc can distinguish trusted charging.level (full re-anchor) from stale header (display-only, preserved by the existing skip-header logic). Fixes #281
1 parent 4a97aaa commit df4fd06

3 files changed

Lines changed: 14 additions & 3 deletions

File tree

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,7 @@ For Plug-in Hybrid Electric Vehicles (PHEVs), the predicted SOC has special hand
240240
- **Automatic PHEV detection**: Vehicles with both an HV battery and fuel system are detected as PHEVs, unless metadata (driveTrain/propulsionType) or the model name (e.g. i4, iX, i5) identifies them as a known BEV
241241
- **Sync down on battery depletion**: If the actual BMW SOC is lower than the predicted value, the prediction syncs down immediately. This handles scenarios where the hybrid system depletes the battery (e.g., battery recovery mode, engine-priority driving)
242242
- **Stale header filtering during charging**: When `charging.level` is available and fresh, the stale `batteryManagement.header` value is skipped to avoid corrupting the predicted SOC display
243+
- **Charging level re-anchor**: During charging, `charging.level` can re-anchor the prediction downward (correcting overshoot). Stale header values are still blocked from doing this, preserving session integrity
243244
- **BEVs**: For pure electric vehicles, the predicted SOC only syncs when not actively charging (standard behavior)
244245

245246
This ensures the predicted SOC stays accurate for PHEVs even when the hybrid system uses battery power in ways that don't register as "discharging" in the BMW API.

custom_components/cardata/soc_prediction.py

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -296,7 +296,9 @@ def update_power_reading(self, vin: str, power_kw: float | None = None, aux_powe
296296
session.last_predicted_soc,
297297
)
298298

299-
def update_bmw_soc(self, vin: str, soc: float, timestamp: datetime | None = None) -> None:
299+
def update_bmw_soc(
300+
self, vin: str, soc: float, timestamp: datetime | None = None, *, from_charging_level: bool = False
301+
) -> None:
300302
"""Record BMW SOC update for staleness tracking.
301303
302304
Also updates last_predicted_soc when not charging (passthrough mode).
@@ -337,7 +339,15 @@ def update_bmw_soc(self, vin: str, soc: float, timestamp: datetime | None = None
337339
session.anchor_soc = soc
338340
session.total_energy_kwh = 0.0
339341
session.last_energy_update = time.time()
340-
# During charging: preserve anchor/energy for learning
342+
elif from_charging_level:
343+
# Charging, from trusted charging.level: full re-anchor downward
344+
old_anchor = session.anchor_soc
345+
ref_time = session.last_energy_update or session.anchor_timestamp.timestamp()
346+
session.anchor_soc = soc
347+
session.total_energy_kwh = 0.0
348+
session.last_energy_update = time.time()
349+
self._derive_power_from_soc_change(vin, session, old_anchor, soc, ref_time)
350+
# During charging from header: preserve anchor/energy for learning
341351
elif not is_charging:
342352
# Not charging: snap to actual BMW SOC
343353
self._last_predicted_soc[vin] = soc

custom_components/cardata/soc_wiring.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -641,7 +641,7 @@ def process_soc_descriptors(
641641
if not skip_stale_level:
642642
try:
643643
level_val = float(value)
644-
soc_predictor.update_bmw_soc(vin, level_val)
644+
soc_predictor.update_bmw_soc(vin, level_val, from_charging_level=True)
645645
if not soc_predictor.has_active_session(vin):
646646
_LOGGER.debug(
647647
"Late anchor attempt for %s (charging.level arrived after charging started)",

0 commit comments

Comments
 (0)