wangrong
2025-09-23 f19a0e925da02a08b88784a534b16ec6d833df4c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
import json
import time
import threading
import sqlite3
from flask import Flask, jsonify, request
import paho.mqtt.client as mqtt
 
# ========= CONFIGURATION =========
MQTT_BROKER = 'localhost'
MQTT_PORT = 1883
MQTT_TOPICS = ['lte_message', 'nr_message', 'wifi_message']
MQTT_CONTROL_TOPIC = 'test_control_command'
 
DB_FILE = 'roadtest.db'
WEB_PORT = 5000
 
status_context = {
    'testing': False,
    'path_id': None,
    'start_time': None
}
 
# ========= DATABASE SETUP =========
def init_db():
    conn = sqlite3.connect(DB_FILE)
    cursor = conn.cursor()
    cursor.execute('''CREATE TABLE IF NOT EXISTS test_paths (
        path_id TEXT PRIMARY KEY,
        start_time TEXT,
        end_time TEXT,
        remark TEXT
    )''')
    cursor.execute('''CREATE TABLE IF NOT EXISTS network_measurements (
        id INTEGER PRIMARY KEY AUTOINCREMENT,
        path_id TEXT,
        message_type TEXT,
        data_json TEXT,
        ts TEXT
    )''')
    conn.commit()
    conn.close()
 
# ========= MQTT CALLBACKS =========
def on_connect(client, userdata, flags, rc):
    print(f"[MQTT] Connected with result code {rc}")
    client.subscribe(MQTT_CONTROL_TOPIC)
    for topic in MQTT_TOPICS:
        client.subscribe(topic)
 
 
def on_message(client, userdata, msg):
    topic = msg.topic
    payload = msg.payload.decode('utf-8')
 
    if topic == MQTT_CONTROL_TOPIC:
        handle_control_message(payload)
        return
 
    if not status_context['testing']:
        return
 
    # Save measurement
    try:
        data = json.loads(payload)
        insert_measurement(
            status_context['path_id'],
            topic,
            payload,
            time.strftime("%Y-%m-%d %H:%M:%S")
        )
        print(f"[DATA] Saved data on {topic} for path {status_context['path_id']}")
    except Exception as e:
        print(f"[ERROR] Failed to parse or save message: {e}")
 
 
def handle_control_message(payload):
    try:
        cmd = json.loads(payload)
        action = cmd.get('action')
        if action == 'start':
            status_context['testing'] = True
            status_context['path_id'] = cmd['path_id']
            status_context['start_time'] = time.strftime("%Y-%m-%d %H:%M:%S")
            insert_path(status_context['path_id'], status_context['start_time'])
            print(f"[CONTROL] Test started with path_id={status_context['path_id']}")
        elif action == 'stop':
            status_context['testing'] = False
            update_path_endtime(status_context['path_id'], time.strftime("%Y-%m-%d %H:%M:%S"))
            print(f"[CONTROL] Test ended for path_id={status_context['path_id']}")
            status_context['path_id'] = None
    except Exception as e:
        print(f"[ERROR] Control message error: {e}")
 
# ========= DATABASE FUNCTIONS =========
def insert_path(path_id, start_time):
    conn = sqlite3.connect(DB_FILE)
    cursor = conn.cursor()
    cursor.execute('INSERT OR REPLACE INTO test_paths (path_id, start_time) VALUES (?, ?)',
                   (path_id, start_time))
    conn.commit()
    conn.close()
 
def update_path_endtime(path_id, end_time):
    conn = sqlite3.connect(DB_FILE)
    cursor = conn.cursor()
    cursor.execute('UPDATE test_paths SET end_time = ? WHERE path_id = ?', (end_time, path_id))
    conn.commit()
    conn.close()
 
def insert_measurement(path_id, message_type, data_json, ts):
    conn = sqlite3.connect(DB_FILE)
    cursor = conn.cursor()
    cursor.execute('''INSERT INTO network_measurements (path_id, message_type, data_json, ts)
                      VALUES (?, ?, ?, ?)''', (path_id, message_type, data_json, ts))
    conn.commit()
    conn.close()
 
# ========= WEB SERVER =========
app = Flask(__name__)
 
@app.route('/status', methods=['GET'])
def get_status():
    return jsonify({
        'testing': status_context['testing'],
        'path_id': status_context['path_id'],
        'start_time': status_context['start_time']
    })
 
@app.route('/paths', methods=['GET'])
def list_paths():
    conn = sqlite3.connect(DB_FILE)
    cursor = conn.cursor()
    cursor.execute('SELECT * FROM test_paths ORDER BY start_time DESC')
    rows = cursor.fetchall()
    conn.close()
    return jsonify(rows)
 
# ========= MAIN =========
def main():
    init_db()
    mqtt_client = mqtt.Client()
    mqtt_client.on_connect = on_connect
    mqtt_client.on_message = on_message
    mqtt_client.connect(MQTT_BROKER, MQTT_PORT, 60)
 
    threading.Thread(target=app.run, kwargs={'port': WEB_PORT, 'debug': False, 'use_reloader': False}, daemon=True).start()
    print("[SYSTEM] Web UI running on http://localhost:5000")
    mqtt_client.loop_forever()
 
if __name__ == '__main__':
    main()