diff --git a/static/js/modes/analytics.js b/static/js/modes/analytics.js index f724318..18ee060 100644 --- a/static/js/modes/analytics.js +++ b/static/js/modes/analytics.js @@ -44,6 +44,10 @@ const Analytics = (function () { _setText('analyticsCountWifi', counts.wifi || 0); _setText('analyticsCountBt', counts.bluetooth || 0); _setText('analyticsCountDsc', counts.dsc || 0); + _setText('analyticsCountAcars', counts.acars || 0); + _setText('analyticsCountVdl2', counts.vdl2 || 0); + _setText('analyticsCountAprs', counts.aprs || 0); + _setText('analyticsCountMesh', counts.meshtastic || 0); // Health const health = data.health || {}; diff --git a/templates/partials/modes/analytics.html b/templates/partials/modes/analytics.html index 7e30775..40df301 100644 --- a/templates/partials/modes/analytics.html +++ b/templates/partials/modes/analytics.html @@ -34,6 +34,26 @@
DSC
+
+
0
+
ACARS
+
+
+
+
0
+
VDL2
+
+
+
+
0
+
APRS
+
+
+
+
0
+
Mesh
+
+
diff --git a/utils/analytics.py b/utils/analytics.py index fb3dc32..6481bc6 100644 --- a/utils/analytics.py +++ b/utils/analytics.py @@ -54,17 +54,33 @@ def get_activity_tracker() -> ModeActivityTracker: return _tracker +def _safe_len(attr_name: str) -> int: + """Safely get len() of an app_module attribute.""" + try: + return len(getattr(app_module, attr_name)) + except Exception: + return 0 + + +def _safe_route_attr(module_path: str, attr_name: str, default: int = 0) -> int: + """Safely read a module-level counter from a route file.""" + try: + import importlib + mod = importlib.import_module(module_path) + return int(getattr(mod, attr_name, default)) + except Exception: + return default + + def _get_mode_counts() -> dict[str, int]: - """Read current entity counts from DataStores and v2 scanners.""" + """Read current entity counts from all available data sources.""" counts: dict[str, int] = {} - try: - counts['adsb'] = len(app_module.adsb_aircraft) - except Exception: - counts['adsb'] = 0 - try: - counts['ais'] = len(app_module.ais_vessels) - except Exception: - counts['ais'] = 0 + + # ADS-B aircraft (DataStore) + counts['adsb'] = _safe_len('adsb_aircraft') + + # AIS vessels (DataStore) + counts['ais'] = _safe_len('ais_vessels') # WiFi: prefer v2 scanner, fall back to legacy DataStore wifi_count = 0 @@ -75,8 +91,7 @@ def _get_mode_counts() -> dict[str, int]: except Exception: pass if wifi_count == 0: - with contextlib.suppress(Exception): - wifi_count = len(app_module.wifi_networks) + wifi_count = _safe_len('wifi_networks') counts['wifi'] = wifi_count # Bluetooth: prefer v2 scanner, fall back to legacy DataStore @@ -88,19 +103,37 @@ def _get_mode_counts() -> dict[str, int]: except Exception: pass if bt_count == 0: - with contextlib.suppress(Exception): - bt_count = len(app_module.bt_devices) + bt_count = _safe_len('bt_devices') counts['bluetooth'] = bt_count + # DSC messages (DataStore) + counts['dsc'] = _safe_len('dsc_messages') + + # ACARS message count (route-level counter) + counts['acars'] = _safe_route_attr('routes.acars', 'acars_message_count') + + # VDL2 message count (route-level counter) + counts['vdl2'] = _safe_route_attr('routes.vdl2', 'vdl2_message_count') + + # APRS stations (route-level dict) try: - counts['dsc'] = len(app_module.dsc_messages) + import routes.aprs as aprs_mod + counts['aprs'] = len(getattr(aprs_mod, 'aprs_stations', {})) except Exception: - counts['dsc'] = 0 + counts['aprs'] = 0 + + # Meshtastic recent messages (route-level list) + try: + import routes.meshtastic as mesh_route + counts['meshtastic'] = len(getattr(mesh_route, '_recent_messages', [])) + except Exception: + counts['meshtastic'] = 0 + return counts def get_cross_mode_summary() -> dict[str, Any]: - """Return counts dict for all active DataStores and v2 scanners.""" + """Return counts dict for all available data sources.""" counts = _get_mode_counts() wifi_clients_count = 0 try: @@ -110,8 +143,7 @@ def get_cross_mode_summary() -> dict[str, Any]: except Exception: pass if wifi_clients_count == 0: - with contextlib.suppress(Exception): - wifi_clients_count = len(app_module.wifi_clients) + wifi_clients_count = _safe_len('wifi_clients') counts['wifi_clients'] = wifi_clients_count return counts @@ -131,6 +163,8 @@ def get_mode_health() -> dict[str, dict]: 'wifi': 'wifi_process', 'bluetooth': 'bt_process', 'dsc': 'dsc_process', + 'rtlamr': 'rtlamr_process', + 'dmr': 'dmr_process', } for mode, attr in process_map.items(): @@ -152,6 +186,14 @@ def get_mode_health() -> dict[str, dict]: except Exception: pass + # Meshtastic: check client connection status + try: + from utils.meshtastic import get_meshtastic_client + client = get_meshtastic_client() + health['meshtastic'] = {'running': client._interface is not None} + except Exception: + health['meshtastic'] = {'running': False} + try: sdr_status = app_module.get_sdr_device_status() health['sdr_devices'] = {str(k): v for k, v in sdr_status.items()}