Protect PHEV charging session from sync-down corruption#243
Merged
kvanbiesen merged 1 commit intokvanbiesen:mainfrom Feb 14, 2026
Merged
Protect PHEV charging session from sync-down corruption#243kvanbiesen merged 1 commit intokvanbiesen:mainfrom
kvanbiesen merged 1 commit intokvanbiesen:mainfrom
Conversation
During PHEV AC charging, stale batteryManagement.header values could trigger the sync-down path in update_bmw_soc(), resetting anchor_soc and total_energy_kwh to zero. This caused two production issues: 1. SOC flicker: stale header (e.g. 5%) in same message as fresh charging.level (45%) briefly drops prediction before sync-up recovers — session data was destroyed in the interim. 2. Session discarded: at charge end, header arrives before status=NOCHARGING. Sync-down resets anchor to header value and energy to 0. Pending session then has soc_gain=0 and is discarded, losing the full charging session for learning. Fix: when is_charging is True, the PHEV sync-down now only updates display values (_last_predicted_soc, session.last_predicted_soc) but preserves session.anchor_soc, total_energy_kwh, and last_energy_update. When not charging, full reset is preserved (no change). Verified paths: - BEV unaffected: entire block gated by _is_phev (BEVs take the elif-is_charging path which already has sync-up-only protection) - Bug 1 trace: header=5 sets display to 5, session data preserved; charging.level=45 then syncs up cleanly. Entity never sees flicker (same async context, debounce fires after both processed) - Bug 2 trace: header=56 with predicted=58 syncs display down but keeps anchor_soc=3 and total_energy_kwh=8.5; end_session reads soc_gain=56-3=53% with real energy — session preserved for learning - Monotonicity guard: after sync-down sets session.last_predicted_soc low, next get_predicted_soc computes anchor+energy and max() picks the real prediction — display self-corrects on next tick - Not-charging: full reset unchanged (anchor + energy zeroed) - PHEV detection: i4 eDrive40 (BEV) safe — _is_metadata_bev override prevents misclassification even with erroneous fuel descriptors
Contributor
Author
|
Should solve #242 |
3 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
During PHEV AC charging, stale batteryManagement.header values could trigger the sync-down path in update_bmw_soc(), resetting anchor_soc and total_energy_kwh to zero. This caused two production issues:
SOC flicker: stale header (e.g. 5%) in same message as fresh charging.level (45%) briefly drops prediction before sync-up recovers — session data was destroyed in the interim.
Session discarded: at charge end, header arrives before status=NOCHARGING. Sync-down resets anchor to header value and energy to 0. Pending session then has soc_gain=0 and is discarded, losing the full charging session for learning.
Fix: when is_charging is True, the PHEV sync-down now only updates display values (_last_predicted_soc, session.last_predicted_soc) but preserves session.anchor_soc, total_energy_kwh, and last_energy_update. When not charging, full reset is preserved (no change).
Verified paths: