@@ -228,19 +228,13 @@ def _process_coordinate_pair(self) -> None:
228228
229229 # Wait until both coordinates exist
230230 if lat is None or lon is None :
231- _LOGGER .debug (
232- "Waiting for coordinate pair for %s (lat=%s, lon=%s)" ,
233- self ._vin ,
234- "present" if lat is not None else "missing" ,
235- "present" if lon is not None else "missing"
236- )
237231 return
238232
239233 # Calculate time difference and ages
240234 time_diff = abs (lat_time - lon_time )
241235 lat_age = now - lat_time
242236 lon_age = now - lon_time
243-
237+
244238 # Discard if both coordinates are very stale
245239 if lat_age > self ._MAX_STALE_TIME and lon_age > self ._MAX_STALE_TIME :
246240 _LOGGER .debug (
@@ -251,78 +245,39 @@ def _process_coordinate_pair(self) -> None:
251245 )
252246 return
253247
254- # Determine which coordinate is fresher
255- lat_is_newer = lat_time > lon_time
256- newer_age = lat_age if lat_is_newer else lon_age
257- older_age = lon_age if lat_is_newer else lat_age
258-
248+ # CRITICAL: Only accept coordinates that arrived close together
249+ if time_diff > self ._PAIR_WINDOW :
250+ _LOGGER .debug (
251+ "Coordinates too far apart for %s (Δt=%.1fs > %.1fs window) - waiting for pair" ,
252+ self ._vin ,
253+ time_diff ,
254+ self ._PAIR_WINDOW
255+ )
256+ return
257+
258+ # Final coordinates (may be smoothed)
259+ final_lat = lat
260+ final_lon = lon
261+
259262 # Check if coordinates changed from previous position
260- lat_changed = False
261- lon_changed = False
263+ lat_changed = True
264+ lon_changed = True
262265 if self ._current_lat is not None and self ._current_lon is not None :
263266 lat_changed = abs (lat - self ._current_lat ) > self ._COORD_PRECISION
264267 lon_changed = abs (lon - self ._current_lon ) > self ._COORD_PRECISION
265268
266- # Decide how to handle the coordinate pair
267- final_lat = lat
268- final_lon = lon
269- update_reason = None
270-
271- # Case 1: Both coordinates arrived close together (ideal case)
272- if time_diff <= self ._PAIR_WINDOW :
273- if lat_changed or lon_changed :
274- update_reason = f"paired update (Δt={ time_diff :.1f} s)"
275- else :
276- _LOGGER .debug ("Ignoring update for %s - no movement detected" , self ._vin )
277- return
278-
279- # Case 2: Coordinates arrived far apart - handle stale coordinate
280- elif time_diff <= self ._MAX_DELAY :
281- # One coordinate is fresher, the other is stale but not too old
282- if lat_changed and lon_changed :
283- # Both changed - accept the pair even though timing is off
284- update_reason = f"delayed pair (Δt={ time_diff :.1f} s, both changed)"
285- elif lat_changed and not lon_changed :
286- # Only lat changed - use new lat with old lon (keep last known lon)
287- update_reason = f"lat update (lon unchanged, Δt={ time_diff :.1f} s)"
288- elif lon_changed and not lat_changed :
289- # Only lon changed - use new lon with old lat (keep last known lat)
290- update_reason = f"lon update (lat unchanged, Δt={ time_diff :.1f} s)"
291- else :
269+ if not lat_changed and not lon_changed :
292270 _LOGGER .debug ("Ignoring update for %s - no movement detected" , self ._vin )
293271 return
294-
295- # Case 3: One coordinate is too stale (> _MAX_DELAY)
296- else :
297- # Use the fresher coordinate with the last known value of the stale one
298- if self ._current_lat is not None and self ._current_lon is not None :
299- if lat_is_newer :
300- if lat_changed :
301- # Use new lat, keep old lon from restored position
302- final_lon = self ._current_lon
303- update_reason = f"lat update (lon stale { older_age :.1f} s, using last known)"
304- else :
305- _LOGGER .debug ("Ignoring update for %s - lat unchanged and lon too stale" , self ._vin )
306- return
307- else :
308- if lon_changed :
309- # Use new lon, keep old lat from restored position
310- final_lat = self ._current_lat
311- update_reason = f"lon update (lat stale { older_age :.1f} s, using last known)"
312- else :
313- _LOGGER .debug ("Ignoring update for %s - lon unchanged and lat too stale" , self ._vin )
314- return
315- else :
316- # No previous position - accept even with stale coordinate
317- update_reason = f"initial position (Δt={ time_diff :.1f} s)"
318-
272+
319273 # Apply movement threshold check
320- if self ._current_lat is not None and self ._current_lon is not None and update_reason :
274+ update_reason = None
275+ if self ._current_lat is not None and self ._current_lon is not None :
321276 distance = self ._calculate_distance (
322277 self ._current_lat , self ._current_lon ,
323278 final_lat , final_lon
324279 )
325-
280+
326281 if distance < self ._MIN_MOVEMENT_DISTANCE :
327282 _LOGGER .debug (
328283 "Ignoring update for %s - movement too small (%.1fm < %dm threshold)" ,
@@ -331,37 +286,30 @@ def _process_coordinate_pair(self) -> None:
331286 self ._MIN_MOVEMENT_DISTANCE
332287 )
333288 return
334-
335- # Add distance to update reason for logging
336- update_reason = f"{ update_reason } , moved { distance :.1f} m"
337289
338- # Apply smoothing to reduce GPS jitter (optional)
339- if (self ._SMOOTHING_FACTOR > 0 and
340- self ._current_lat is not None and
341- self ._current_lon is not None and
342- update_reason and "initial" not in update_reason ):
343-
344- # Weighted average: new_value = (1 - factor) * new + factor * old
345- # factor=0 means no smoothing (use new value)
346- # factor=1 means full smoothing (keep old value)
347- smoothed_lat = (1 - self ._SMOOTHING_FACTOR ) * final_lat + self ._SMOOTHING_FACTOR * self ._current_lat
348- smoothed_lon = (1 - self ._SMOOTHING_FACTOR ) * final_lon + self ._SMOOTHING_FACTOR * self ._current_lon
290+ update_reason = f"paired update (Δt={ time_diff :.1f} s, moved { distance :.1f} m)"
291+
292+ # Apply smoothing to reduce GPS jitter (optional)
293+ if self ._SMOOTHING_FACTOR > 0 :
294+ smoothed_lat = (1 - self ._SMOOTHING_FACTOR ) * final_lat + self ._SMOOTHING_FACTOR * self ._current_lat
295+ smoothed_lon = (1 - self ._SMOOTHING_FACTOR ) * final_lon + self ._SMOOTHING_FACTOR * self ._current_lon
349296
350- _LOGGER .debug (
351- "Applying smoothing for %s (factor=%.1f): raw=(%.6f, %.6f) -> smoothed=(%.6f, %.6f)" ,
352- self ._vin ,
353- self ._SMOOTHING_FACTOR ,
354- final_lat , final_lon ,
355- smoothed_lat , smoothed_lon
356- )
297+ _LOGGER .debug (
298+ "Applying smoothing for %s (factor=%.1f): raw=(%.6f, %.6f) -> smoothed=(%.6f, %.6f)" ,
299+ self ._vin ,
300+ self ._SMOOTHING_FACTOR ,
301+ final_lat , final_lon ,
302+ smoothed_lat , smoothed_lon
303+ )
357304
358- final_lat = smoothed_lat
359- final_lon = smoothed_lon
360- update_reason = f"{ update_reason } , smoothed"
361-
305+ final_lat = smoothed_lat
306+ final_lon = smoothed_lon
307+ update_reason = f"{ update_reason } , smoothed"
308+ else :
309+ update_reason = f"initial position (Δt={ time_diff :.1f} s)"
310+
362311 # Update the tracker position
363- if update_reason :
364- self ._apply_new_coordinates (final_lat , final_lon , update_reason )
312+ self ._apply_new_coordinates (final_lat , final_lon , update_reason )
365313
366314 def _calculate_distance (self , lat1 : float , lon1 : float , lat2 : float , lon2 : float ) -> float :
367315 """Calculate distance between two GPS coordinates in meters using Haversine formula."""
0 commit comments