diff --git a/routes/system.py b/routes/system.py index b66efc2..271a2ef 100644 --- a/routes/system.py +++ b/routes/system.py @@ -436,17 +436,21 @@ def _ensure_collector() -> None: def _get_observer_location() -> dict[str, Any]: """Get observer location from GPS state or config defaults.""" lat, lon, source = None, None, 'none' + gps_meta: dict[str, Any] = {} - # Try GPS state from app module + # Try GPS via utils.gps with contextlib.suppress(Exception): - import app as app_module + from utils.gps import get_current_position - gps_state = getattr(app_module, 'gps_state', None) - if gps_state and isinstance(gps_state, dict): - g_lat = gps_state.get('lat') or gps_state.get('latitude') - g_lon = gps_state.get('lon') or gps_state.get('longitude') - if g_lat is not None and g_lon is not None: - lat, lon, source = float(g_lat), float(g_lon), 'gps' + pos = get_current_position() + if pos and pos.fix_quality >= 2: + lat, lon, source = pos.latitude, pos.longitude, 'gps' + gps_meta['fix_quality'] = pos.fix_quality + gps_meta['satellites'] = pos.satellites + if pos.epx is not None and pos.epy is not None: + gps_meta['accuracy'] = round(max(pos.epx, pos.epy), 1) + if pos.altitude is not None: + gps_meta['altitude'] = round(pos.altitude, 1) # Fall back to config defaults if lat is None: @@ -456,7 +460,10 @@ def _get_observer_location() -> dict[str, Any]: if DEFAULT_LATITUDE != 0.0 or DEFAULT_LONGITUDE != 0.0: lat, lon, source = DEFAULT_LATITUDE, DEFAULT_LONGITUDE, 'config' - return {'lat': lat, 'lon': lon, 'source': source} + result: dict[str, Any] = {'lat': lat, 'lon': lon, 'source': source} + if gps_meta: + result['gps'] = gps_meta + return result # --------------------------------------------------------------------------- diff --git a/static/css/modes/system.css b/static/css/modes/system.css index 7beee04..5593690 100644 --- a/static/css/modes/system.css +++ b/static/css/modes/system.css @@ -282,16 +282,17 @@ color: var(--accent-cyan, #00d4ff); } -/* Globe container */ +/* Globe container — compact vertical layout */ .sys-location-inner { display: flex; - gap: 16px; - align-items: stretch; + flex-direction: column; + gap: 10px; + align-items: center; } .sys-globe-wrap { - width: 300px; - height: 300px; + width: 200px; + height: 200px; flex-shrink: 0; background: #000; border-radius: 8px; @@ -300,10 +301,42 @@ } .sys-location-details { - flex: 1; + width: 100%; display: flex; flex-direction: column; - gap: 8px; + gap: 6px; +} + +/* GPS status indicator */ +.sys-gps-status { + display: flex; + align-items: center; + gap: 6px; + font-size: 10px; + color: var(--text-dim, #8888aa); + text-transform: uppercase; + letter-spacing: 0.05em; +} + +.sys-gps-dot { + display: inline-block; + width: 7px; + height: 7px; + border-radius: 50%; +} + +.sys-gps-dot.fix-3d { + background: var(--accent-green, #00ff88); + box-shadow: 0 0 4px rgba(0, 255, 136, 0.4); +} + +.sys-gps-dot.fix-2d { + background: var(--accent-yellow, #ffcc00); + box-shadow: 0 0 4px rgba(255, 204, 0, 0.4); +} + +.sys-gps-dot.no-fix { + background: var(--text-dim, #555); } .sys-location-coords { @@ -515,13 +548,9 @@ grid-column: 1; } - .sys-location-inner { - flex-direction: column; - } - .sys-globe-wrap { width: 100%; - height: 250px; + height: 180px; } .sys-process-grid { diff --git a/static/js/modes/system.js b/static/js/modes/system.js index 74fb93d..6731806 100644 --- a/static/js/modes/system.js +++ b/static/js/modes/system.js @@ -390,14 +390,27 @@ const SystemHealth = (function () { // Globe container html += '
'; - // Details column + // Details below globe html += '