import shutil from printer import perror if shutil.which("npx") is None: perror("npx is not installed or not found in PATH") import folium import psutil import subprocess from pathlib import Path from datetime import datetime from printer import monitor_stderr MAP_PATH = Path.cwd() / "gps_tracker" / "map.html" class GPS_Tracker: def __init__(self): self.background_process = None self.last_marker = None self.waypoints = [] self.map = folium.Map( location=[45.4642, 9.1900], # Milan as default center zoom_start=17, tiles="OpenStreetMap" ) self.map.save(MAP_PATH) def add_waypoint(self, lat, lon, accuracy): # Accuracy can be 0, meaning that it wasn't possible to measure it if not (-90 <= lat <= 90) or not (-180 <= lon <= 180) or not (accuracy >= 0): perror(f"Invalid coordinates: lat={lat}, lon={lon}, accuracy={accuracy}") return timestamp = datetime.now() new_waypoint = { 'lat': lat, 'lon': lon, 'accuracy': accuracy, 'timestamp': timestamp } self.waypoints.append(new_waypoint) # If the waypoint is the first, then mark it differently idx = len(self.waypoints) - 1 if idx == 0: color = 'green' icon_name = 'play' else: color = 'red' icon_name = 'stop' # Add the waypoint marker to the map popup_text = f"Point {idx+1}
Lat: {lat:.6f}
Lon: {lon:.6f}
Time: {timestamp.strftime('%H:%M:%S')}" if accuracy > 0: popup_text += f"
Accuracy: {accuracy}m" marker = folium.Marker( [lat, lon], popup=popup_text, tooltip=f"Waypoint #{idx+1}", icon=folium.Icon(color=color, icon=icon_name) ).add_to(self.map) # Add the accuracy circle (if available) if accuracy > 0: folium.Circle( location=[lat, lon], radius=accuracy, color='black', fill=True, fillOpacity=0.2, weight=1 ).add_to(self.map) # Center the map around the new waypoint self.map.location = [lat, lon] # If the added waypoint is the first, stop here if self.last_marker is None: self.last_marker = marker self.map.save(MAP_PATH) return # Get the old latest waypoint last_idx = idx - 1 last_waypoint = self.waypoints[last_idx] last_lat, last_lon = last_waypoint['lat'], last_waypoint['lon'] # Add line connecting the latest and new waypoints folium.PolyLine( [[last_lat, last_lon], [lat, lon]], color='red', weight=3, opacity=0.8, ).add_to(self.map) # If the latest waypoint wasn't the first, change its icon if (last_idx > 0): self.last_marker.set_icon(folium.Icon(color='blue', icon='record')) self.last_marker = marker self.map.save(MAP_PATH) def open_live_map(self): cmd = ["npx", "electron", "gps_tracker"] try: self.background_process = subprocess.Popen(cmd, stderr=subprocess.PIPE) monitor_stderr(self.background_process, "GPS TRACKER") print("GPS TRACKER process launched") except Exception as e: perror(f"Failed to launch GPS TRACKER: {e}") def close_live_map(self): if self.background_process: parent = psutil.Process(self.background_process.pid) for child in parent.children(recursive=True): child.kill() parent.kill() print("GPS TRACKER process terminated") else: print("No GPS TRACKER process to terminate")