Skip to content

Commit ab599d8

Browse files
authored
Merge pull request #264 from renaudallard/main
Some fixes for issues seen in logs
2 parents 4d38ad6 + a5fca75 commit ab599d8

2 files changed

Lines changed: 24 additions & 11 deletions

File tree

custom_components/cardata/magic_soc.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -359,7 +359,7 @@ def anchor_driving_session(
359359
consumption_kwh_per_km=consumption,
360360
last_predicted_soc=anchor_soc,
361361
created_at=time.time(),
362-
trip_start_soc=anchor_soc,
362+
trip_start_soc=current_soc,
363363
trip_start_mileage=trip_start,
364364
)
365365

@@ -381,7 +381,13 @@ def reanchor_driving_session(self, vin: str, new_soc: float, current_mileage: fl
381381
if session is None:
382382
return
383383
# Skip no-op re-anchors (duplicate SOC/mileage from MQTT bursts).
384-
if session.anchor_soc == new_soc and session.anchor_mileage == current_mileage:
384+
# Pre-compute what anchor would become after smoothing to detect true no-ops
385+
# (smoothed anchor_soc won't match BMW integer, so raw comparison always fails).
386+
if abs(new_soc - session.last_predicted_soc) < 0.5:
387+
effective_anchor = session.last_predicted_soc
388+
else:
389+
effective_anchor = new_soc
390+
if effective_anchor == session.anchor_soc and current_mileage == session.anchor_mileage:
385391
return
386392
old_anchor = session.anchor_soc
387393
# BMW sends integer SOC. If our sub-integer prediction rounds to that

custom_components/cardata/motion_detection.py

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ class MotionDetector:
4747
# Minimum time span (seconds) for the 3 park-confirming readings.
4848
# BMW sends GPS in bursts (3 readings within <1s at the same position).
4949
# Without this guard the burst immediately parks the car while driving.
50-
MIN_PARK_SPAN_SECONDS: ClassVar[float] = 30.0
50+
MIN_PARK_SPAN_SECONDS: ClassVar[float] = 90.0
5151

5252
# Minutes without GPS update to consider GPS unavailable (switch to mileage fallback)
5353
# Longer than MOTION_ACTIVE_WINDOW to handle BMW's bursty GPS (every 2-3 min)
@@ -208,24 +208,31 @@ def update_location(self, vin: str, lat: float, lon: float) -> bool:
208208
for r in park_readings[-3:]
209209
)
210210
if all_within_park:
211-
# Require readings to span a minimum time window to avoid
212-
# treating a single GPS burst as parking
213-
first_park_time = park_readings[-3][2]
214-
time_span = (now - first_park_time).total_seconds()
215-
if time_span < self.MIN_PARK_SPAN_SECONDS:
211+
# Require readings from at least 2 distinct MQTT bursts
212+
# separated by MIN_PARK_SPAN_SECONDS. BMW sends GPS in
213+
# tight bursts (3-6 readings in <1s), so park_readings[-3]
214+
# is always from the current burst. Instead, find the
215+
# latest reading that preceded the current burst by at
216+
# least MIN_PARK_SPAN_SECONDS — proving the car was already
217+
# in the park zone that long ago.
218+
has_old_reading = any(
219+
(now - r[2]).total_seconds() >= self.MIN_PARK_SPAN_SECONDS for r in park_readings
220+
)
221+
if not has_old_reading:
216222
# Burst detection: readings too close together, not real parking
217223
# Stay in driving mode
218224
return True
219225

220226
# Vehicle has stopped - exit driving mode
221227
# Backdate last movement to when the car first entered the park zone
228+
time_in_zone = (now - park_readings[0][2]).total_seconds()
222229
_LOGGER.debug(
223-
"Motion: %s stopped (3 readings within park radius over %.0fs) - NOW PARKED",
230+
"Motion: %s stopped (readings in park zone for %.0fs) - NOW PARKED",
224231
redact_vin(vin),
225-
time_span,
232+
time_in_zone,
226233
)
227234
self._is_driving[vin] = False
228-
self._last_location_change[vin] = first_park_time
235+
self._last_location_change[vin] = park_readings[0][2]
229236
self._park_anchor[vin] = self._calculate_centroid(park_readings)
230237
return False
231238
else:

0 commit comments

Comments
 (0)