mirror of
https://github.com/smittix/intercept.git
synced 2026-04-24 06:40:00 -07:00
feat: Add cross-mode analytics dashboard with geofencing, correlations, and data export
Adds a unified analytics mode under the Security nav group that aggregates data across all signal modes. Includes emergency squawk alerting (7700/7600/7500), vertical rate anomaly detection, ACARS/VDL2-to-ADS-B flight correlation, geofence zones with enter/exit detection for aircraft/vessels/APRS stations, temporal pattern detection, RSSI history tracking, Meshtastic topology mapping, and JSON/CSV data export. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -306,6 +306,9 @@ class MeshtasticClient:
|
||||
self._range_test_running: bool = False
|
||||
self._range_test_results: list[dict] = []
|
||||
|
||||
# Topology tracking: node_id -> {neighbors, hop_count, msg_count, last_seen}
|
||||
self._topology: dict[str, dict] = {}
|
||||
|
||||
@property
|
||||
def is_running(self) -> bool:
|
||||
return self._running
|
||||
@@ -326,6 +329,35 @@ class MeshtasticClient:
|
||||
"""Set callback for received messages."""
|
||||
self._callback = callback
|
||||
|
||||
def record_message_route(self, from_node: str, to_node: str, hops: int | None = None) -> None:
|
||||
"""Record a message route for topology tracking."""
|
||||
now = datetime.now(timezone.utc).isoformat()
|
||||
for node_id in (from_node, to_node):
|
||||
if node_id not in self._topology:
|
||||
self._topology[node_id] = {
|
||||
'neighbors': set(),
|
||||
'hop_count': hops,
|
||||
'msg_count': 0,
|
||||
'last_seen': now,
|
||||
}
|
||||
entry = self._topology[node_id]
|
||||
entry['msg_count'] += 1
|
||||
entry['last_seen'] = now
|
||||
self._topology[from_node]['neighbors'].add(to_node)
|
||||
self._topology[to_node]['neighbors'].add(from_node)
|
||||
|
||||
def get_topology(self) -> dict:
|
||||
"""Return topology dict with serializable sets."""
|
||||
result = {}
|
||||
for node_id, data in self._topology.items():
|
||||
result[node_id] = {
|
||||
'neighbors': list(data.get('neighbors', set())),
|
||||
'hop_count': data.get('hop_count'),
|
||||
'msg_count': data.get('msg_count', 0),
|
||||
'last_seen': data.get('last_seen'),
|
||||
}
|
||||
return result
|
||||
|
||||
def connect(self, device: str | None = None, connection_type: str = 'serial',
|
||||
hostname: str | None = None) -> bool:
|
||||
"""
|
||||
@@ -463,6 +495,14 @@ class MeshtasticClient:
|
||||
# Track node from packet (always, even for filtered messages)
|
||||
self._track_node_from_packet(packet, decoded, portnum)
|
||||
|
||||
# Record topology route
|
||||
if from_num and to_num:
|
||||
self.record_message_route(
|
||||
self._format_node_id(from_num),
|
||||
self._format_node_id(to_num),
|
||||
packet.get('hopLimit'),
|
||||
)
|
||||
|
||||
# Parse traceroute responses
|
||||
if portnum == 'TRACEROUTE_APP':
|
||||
self._handle_traceroute_response(packet, decoded)
|
||||
|
||||
Reference in New Issue
Block a user