#!/usr/bin/env python3 """ V2X Sniffer - Separate SQLite-Datenbank für V2X-Daten (Trenn von home_tracker.db - nur für Essen & Aktivitäten!) """ import sqlite3 import os import json from datetime import datetime DB_PATH = os.path.join(os.path.dirname(os.path.abspath(__file__)), "v2x_sniffer.db") def get_connection(): """Verbindung zur V2X-Datenbank aufbauen.""" conn = sqlite3.connect(DB_PATH) conn.row_factory = sqlite3.Row conn.execute("PRAGMA journal_mode=WAL") conn.execute("PRAGMA synchronous=NORMAL") return conn def init_db(): """Datenbank initialisieren.""" conn = get_connection() cursor = conn.cursor() # V2X Messages Tabelle (C-ITS, BSM, CAM, DENM) cursor.execute(""" CREATE TABLE IF NOT EXISTS v2x_messages ( id INTEGER PRIMARY KEY AUTOINCREMENT, timestamp TEXT NOT NULL, message_type TEXT NOT NULL, channel INTEGER NOT NULL, frequency_mhz REAL NOT NULL, rssi_dbm REAL, power_dbm REAL, data_rate_bps REAL, frame_len INTEGER, cam_container_id TEXT, station_id TEXT, vehicle_type INTEGER, latitude REAL, longitude REAL, altitude REAL, speed_kmh REAL, heading_deg REAL, acceleration_kmh2 REAL, lateral_accel_kmh2 REAL, yaw_rate_dps REAL, driveway_width_mm INTEGER, brake_status INTEGER, sparkplug INTEGER, wiper_status INTEGER, vehicle_length_mm INTEGER, vehicle_width_mm INTEGER, vehicle_class INTEGER, position_precision INTEGER, mission_status INTEGER, crossroad_status INTEGER, message_id TEXT, raw_data TEXT, decoded_json TEXT ) """) # Kanäle und Frequenzen cursor.execute(""" CREATE TABLE IF NOT EXISTS v2x_channels ( id INTEGER PRIMARY KEY AUTOINCREMENT, channel_name TEXT UNIQUE NOT NULL, frequency_mhz REAL NOT NULL, channel_number INTEGER NOT NULL, phy_mode TEXT DEFAULT '802.11p', bandwidth_mhz REAL DEFAULT 10.0, description TEXT ) """) # Statistik pro Tag cursor.execute(""" CREATE TABLE IF NOT EXISTS v2x_statistics ( id INTEGER PRIMARY KEY AUTOINCREMENT, date TEXT NOT NULL, total_messages INTEGER DEFAULT 0, cam_count INTEGER DEFAULT 0, denm_count INTEGER DEFAULT 0, bsm_count INTEGER DEFAULT 0, other_count INTEGER DEFAULT 0, avg_rssi REAL, min_rssi REAL, max_rssi REAL, unique_stations INTEGER DEFAULT 0 ) """) # C-ITS Tabellen cursor.execute(""" CREATE TABLE IF NOT EXISTS v2x_vehicles ( id INTEGER PRIMARY KEY AUTOINCREMENT, station_id TEXT UNIQUE NOT NULL, first_seen TEXT NOT NULL, last_seen TEXT NOT NULL, message_count INTEGER DEFAULT 0, vehicle_type INTEGER, lat REAL, lng REAL, speed_kmh REAL, heading_deg REAL, signal_strength REAL ) """) conn.commit() conn.close() def insert_message(msg_type, data): """Eine V2X-Nachricht in die Datenbank einfügen.""" conn = get_connection() cursor = conn.cursor() # Entpacken der Rohdaten lat = data.get('latitude', 0.0) lng = data.get('longitude', 0.0) cursor.execute(""" INSERT INTO v2x_messages ( timestamp, message_type, channel, frequency_mhz, rssi_dbm, power_dbm, data_rate_bps, frame_len, cam_container_id, station_id, vehicle_type, latitude, longitude, altitude, speed_kmh, heading_deg, acceleration_kmh2, raw_data, decoded_json ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) """, ( datetime.now().isoformat(), msg_type, data.get('channel', 0), data.get('frequency_mhz', 5900.0), data.get('rssi', 0.0), data.get('power', 0.0), data.get('data_rate', 0.0), data.get('frame_len', 0), data.get('cam_container_id', ''), data.get('station_id', ''), data.get('vehicle_type', 0), lat, lng, data.get('altitude', 0.0), data.get('speed_kmh', 0.0), data.get('heading_deg', 0.0), data.get('acceleration_kmh2', 0.0), data.get('raw_data', ''), json.dumps(data.get('decoded', {})) )) # Fahrzeug aktualisieren station_id = data.get('station_id', '') if station_id: cursor.execute(""" INSERT INTO v2x_vehicles ( station_id, first_seen, last_seen, message_count, vehicle_type, lat, lng, speed_kmh, heading_deg, signal_strength ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ON CONFLICT(station_id) DO UPDATE SET last_seen = excluded.last_seen, message_count = v2x_vehicles.message_count + 1, vehicle_type = COALESCE(excluded.vehicle_type, v2x_vehicles.vehicle_type), lat = COALESCE(excluded.lat, v2x_vehicles.lat), lng = COALESCE(excluded.lng, v2x_vehicles.lng), speed_kmh = COALESCE(excluded.speed_kmh, v2x_vehicles.speed_kmh), heading_deg = COALESCE(excluded.heading_deg, v2x_vehicles.heading_deg), signal_strength = COALESCE(excluded.signal_strength, v2x_vehicles.signal_strength) """, ( station_id, datetime.now().isoformat(), datetime.now().isoformat(), 1, data.get('vehicle_type', 0), lat, lng, data.get('speed_kmh', 0.0), data.get('heading_deg', 0.0), data.get('rssi', 0.0) )) conn.commit() conn.close() def query_recent(limit=50): """Die letzten V2X-Nachrichten abfragen.""" conn = get_connection() cursor = conn.cursor() cursor.execute(""" SELECT * FROM v2x_messages ORDER BY timestamp DESC LIMIT ? """, (limit,)) rows = cursor.fetchall() conn.close() return [dict(row) for row in rows] def get_statistics(): """Statistiken der V2X-Datenbank abrufen.""" conn = get_connection() cursor = conn.cursor() total = cursor.execute("SELECT COUNT(*) FROM v2x_messages").fetchone()[0] cams = cursor.execute("SELECT COUNT(*) FROM v2x_messages WHERE message_type='CAM'").fetchone()[0] denms = cursor.execute("SELECT COUNT(*) FROM v2x_messages WHERE message_type='DENM'").fetchone()[0] bsm = cursor.execute("SELECT COUNT(*) FROM v2x_messages WHERE message_type='BSM'").fetchone()[0] stats = cursor.execute(""" SELECT AVG(rssi_dbm), MIN(rssi_dbm), MAX(rssi_dbm) FROM v2x_messages WHERE rssi_dbm IS NOT NULL """).fetchone() conn.close() return { 'total': total, 'cam': cams, 'denm': denms, 'bsm': bsm, 'avg_rssi': stats[0], 'min_rssi': stats[1], 'max_rssi': stats[2] } if __name__ == "__main__": init_db() print(f"✅ V2X-Datenbank initialisiert: {DB_PATH}") # Testdaten einfügen test_data = { 'channel': 59, 'frequency_mhz': 5900.0, 'rssi': -45.0, 'power': -20.0, 'data_rate': 12000000.0, 'frame_len': 200, 'cam_container_id': 'test_cam_001', 'station_id': 'AT-GRA-001', 'vehicle_type': 1, 'latitude': 47.0707, 'longitude': 15.4395, 'altitude': 314.0, 'speed_kmh': 65.5, 'heading_deg': 180.0, 'acceleration_kmh2': -2.5, 'raw_data': '0x10,0x20,0x30,0x40', 'decoded': {'msgId': 'test', 'version': 2} } insert_message('CAM', test_data) print("✅ Test-Nachricht eingefügt") stats = get_statistics() print(f"📊 Statistik: {stats}")