diff --git a/application_events.json b/application_events.json index 732ed62..82622c2 100644 --- a/application_events.json +++ b/application_events.json @@ -7602,8 +7602,118 @@ "activated_datasets": 2, "total_datasets": 3 } + }, + { + "timestamp": "2025-08-15T20:16:35.894381", + "level": "info", + "event_type": "udp_streaming_started", + "message": "UDP streaming to PlotJuggler started", + "details": { + "udp_host": "127.0.0.1", + "udp_port": 9870, + "datasets_available": 3 + } + }, + { + "timestamp": "2025-08-15T20:16:56.537497", + "level": "info", + "event_type": "config_reload", + "message": "Dataset configuration reloaded from files with CSV header validation", + "details": { + "datasets_count": 3, + "active_datasets_count": 3, + "csv_recording_active": true + } + }, + { + "timestamp": "2025-08-15T20:16:59.997119", + "level": "info", + "event_type": "udp_streaming_stopped", + "message": "UDP streaming to PlotJuggler stopped (CSV recording continues)", + "details": {} + }, + { + "timestamp": "2025-08-15T20:17:05.782835", + "level": "info", + "event_type": "udp_streaming_started", + "message": "UDP streaming to PlotJuggler started", + "details": { + "udp_host": "127.0.0.1", + "udp_port": 9870, + "datasets_available": 3 + } + }, + { + "timestamp": "2025-08-15T20:21:47.811533", + "level": "info", + "event_type": "application_started", + "message": "Application initialization completed successfully", + "details": {} + }, + { + "timestamp": "2025-08-15T20:21:47.876040", + "level": "info", + "event_type": "dataset_activated", + "message": "Dataset activated: DAR", + "details": { + "dataset_id": "DAR", + "variables_count": 2, + "streaming_count": 2, + "prefix": "gateway_phoenix" + } + }, + { + "timestamp": "2025-08-15T20:21:47.885336", + "level": "info", + "event_type": "dataset_activated", + "message": "Dataset activated: Fast", + "details": { + "dataset_id": "Fast", + "variables_count": 2, + "streaming_count": 2, + "prefix": "fast" + } + }, + { + "timestamp": "2025-08-15T20:21:47.894836", + "level": "info", + "event_type": "csv_recording_started", + "message": "CSV recording started: 2 datasets activated", + "details": { + "activated_datasets": 2, + "total_datasets": 3 + } + }, + { + "timestamp": "2025-08-15T20:21:47.904356", + "level": "info", + "event_type": "udp_streaming_started", + "message": "UDP streaming to PlotJuggler started", + "details": { + "udp_host": "127.0.0.1", + "udp_port": 9870, + "datasets_available": 3 + } + }, + { + "timestamp": "2025-08-15T20:22:34.633059", + "level": "info", + "event_type": "udp_streaming_stopped", + "message": "UDP streaming to PlotJuggler stopped (CSV recording continues)", + "details": {} + }, + { + "timestamp": "2025-08-15T20:22:39.890817", + "level": "info", + "event_type": "udp_streaming_started", + "message": "UDP streaming to PlotJuggler started", + "details": { + "udp_host": "127.0.0.1", + "udp_port": 9870, + "datasets_available": 3 + } } ], - "last_updated": "2025-08-15T20:06:52.289232", - "total_entries": 620 + "last_updated": "2025-08-15T20:22:39.890817", + "total_entries": 631 } \ No newline at end of file diff --git a/config/data/dataset_variables.json b/config/data/dataset_variables.json index 4f05226..30f6c13 100644 --- a/config/data/dataset_variables.json +++ b/config/data/dataset_variables.json @@ -36,7 +36,7 @@ { "configType": "symbol", "area": "db", - "streaming": false, + "streaming": true, "symbol": "AUX Blink_1.6S", "type": "real" } diff --git a/frontend/src/pages/Dashboard.jsx b/frontend/src/pages/Dashboard.jsx index 0daa50a..b9aa34a 100644 --- a/frontend/src/pages/Dashboard.jsx +++ b/frontend/src/pages/Dashboard.jsx @@ -315,12 +315,26 @@ function StatusBar({ status, isConnected, isLeader }) { const streaming = !!status?.streaming const csvRecording = !!status?.csv_recording const [actionLoading, setActionLoading] = useState({}) + const [plotJugglerFound, setPlotJugglerFound] = useState(false) const toast = useToast() const setLoading = (action, loading) => { setActionLoading(prev => ({ ...prev, [action]: loading })) } + // Check if PlotJuggler is available on component mount + useEffect(() => { + const checkPlotJuggler = async () => { + try { + const result = await api.getPlotJugglerPath() + setPlotJugglerFound(result.found) + } catch (error) { + setPlotJugglerFound(false) + } + } + checkPlotJuggler() + }, []) + const handleConnectPlc = async () => { setLoading('connect', true) try { @@ -413,6 +427,28 @@ function StatusBar({ status, isConnected, isLeader }) { } } + const handleLaunchPlotJuggler = async () => { + setLoading('launchPlotJuggler', true) + try { + const result = await api.launchPlotJugglerStreamer() + toast({ + title: '🚀 PlotJuggler launched', + description: result.message || 'PlotJuggler started with UDP streamer', + status: 'success', + duration: 2000 + }) + } catch (error) { + toast({ + title: '❌ Failed to launch PlotJuggler', + description: error.message, + status: 'error', + duration: 3000 + }) + } finally { + setLoading('launchPlotJuggler', false) + } + } + return ( @@ -464,29 +500,49 @@ function StatusBar({ status, isConnected, isLeader }) { {streaming ? 'Active' : 'Inactive'} - {streaming ? ( - - ) : ( - - )} + + {streaming ? ( + + ) : ( + + )} + {plotJugglerFound && ( + + )} + {!plotJugglerFound && ( + + PlotJuggler not found + + )} + diff --git a/frontend/src/services/api.js b/frontend/src/services/api.js index c7ba781..9d10859 100644 --- a/frontend/src/services/api.js +++ b/frontend/src/services/api.js @@ -263,6 +263,17 @@ export async function setPlotJugglerPath(path) { return toJsonOrThrow(res) } +export async function launchPlotJugglerStreamer() { + const res = await fetch(`${BASE_URL}/api/plotjuggler/launch-streamer`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'Accept': 'application/json' + } + }) + return toJsonOrThrow(res) +} + // Open CSV in Excel export async function openCsvInExcel(filePath) { const res = await fetch(`${BASE_URL}/api/csv/open-excel`, { diff --git a/main.py b/main.py index ea8c3fe..caa0ed2 100644 --- a/main.py +++ b/main.py @@ -3015,6 +3015,38 @@ def launch_plotjuggler(): return jsonify({"error": str(e)}), 500 +@app.route("/api/plotjuggler/launch-streamer", methods=["POST"]) +def launch_plotjuggler_streamer(): + """Launch PlotJuggler with UDP streamer configured""" + try: + # Get PlotJuggler path from system state + plotjuggler_path = get_plotjuggler_path() + if not plotjuggler_path: + return jsonify({"error": "PlotJuggler not found"}), 404 + + # Launch PlotJuggler with UDP streamer parameters + import subprocess + + cmd = [ + plotjuggler_path, + "-n", # no recent files menu + "--start_streamer", "UDP streamer" + ] + + subprocess.Popen(cmd, shell=True) + + return jsonify( + { + "success": True, + "message": "PlotJuggler launched with UDP streamer", + "command": " ".join(cmd), + } + ) + + except Exception as e: + return jsonify({"error": str(e)}), 500 + + @app.route("/api/plotjuggler/path", methods=["GET"]) def get_plotjuggler_path_endpoint(): """Get PlotJuggler executable path""" diff --git a/system_state.json b/system_state.json index e134174..eba789b 100644 --- a/system_state.json +++ b/system_state.json @@ -1,7 +1,7 @@ { "last_state": { "should_connect": true, - "should_stream": false, + "should_stream": true, "active_datasets": [ "Fast", "Test", @@ -9,6 +9,5 @@ ] }, "auto_recovery_enabled": true, - "last_update": "2025-08-15T20:15:35.459362", - "plotjuggler_path": "C:\\Program Files\\PlotJuggler\\plotjuggler.exe" + "last_update": "2025-08-15T20:22:39.890817" } \ No newline at end of file