MCPcopy Create free account
hub / github.com/PierreGode/Ragnar / update_external_fix

Method update_external_fix

gps_manager.py:405–467  ·  view source on GitHub ↗

Inject a position from an external source (e.g. a USB-connected Piglet/HuginnESP companion that has its own GPS receiver). Lets Ragnar operate as if it had GPS even when no local receiver is attached, so BT/cell scans, the gps_track table, and the status UI all see a

(self, lat, lon, alt=None, speed_kmh=None,
                            satellites=None, hdop=None, source='companion')

Source from the content-addressed store, hash-verified

403 Idempotent: if already reading that port, do nothing. Prefers gpsd when
404 it is running (it owns the serial device). This is what makes GPS
405 self-healing — a puck that appears minutes after boot, or bounces
406 (disconnect→reconnect), is attached automatically with no restart.
407 """
408 if not port:
409 return False
410 target = port
411 sock = _try_gpsd()
412 if sock:
413 try:
414 sock.close()
415 except Exception:
416 pass
417 target = 'gpsd'
418 if self._running and self.port == target:
419 return True
420 if self._running:
421 self.stop()
422 self.port = target
423 return self.start()
424
425 def detach(self):
426 """Release the current GPS device — called when it is unplugged so the
427 monitor can re-attach a fresh one later."""
428 was = self.port
429 self.stop()
430 self.port = None
431 self.error = "No GPS device detected"
432 if was:
433 logger.info(f"GPS detached from {was}")
434
435 def has_fix(self):
436 """Return True if GPS has a valid position fix (not stale)."""
437 if self.fix_quality <= 0 or self.latitude is None or self.longitude is None:
438 return False
439 # Consider fix stale after 10 seconds without update
440 if self.last_update and (time.time() - self.last_update) > 10:
441 return False
442 # Stamp TTFF here rather than in each of the GGA / RMC / gpsd paths:
443 # this method is the one definition of "we actually have a fix", so
444 # every producer would otherwise need the same guard duplicated.
445 if not self.first_fix_time:
446 self.first_fix_time = time.time()
447 return True
448
449 @property
450 def ttff_seconds(self):
451 """Seconds from reader start to first fix, or None if still searching."""
452 if not self.start_time or not self.first_fix_time:
453 return None
454 return round(self.first_fix_time - self.start_time, 1)
455
456 def get_position(self):
457 """Return current position dict (or None if no fix)."""
458 if not self.has_fix():
459 return None
460 with self._lock:
461 return {
462 'lat': self.latitude,

Callers 1

_parse_serial_lineMethod · 0.80

Calls

no outgoing calls

Tested by

no test coverage detected