diff --git a/main.py b/main.py index 598e931..6b9c5e2 100644 --- a/main.py +++ b/main.py @@ -13,8 +13,10 @@ from starlette.exceptions import HTTPException as StarletteHTTPException from starlette.status import HTTP_302_FOUND import json from pathlib import Path -from typing import Optional +from typing import Optional, Dict, Any from fastapi import Query +import asyncio +import datetime if platform.system() in ["Darwin"]: # macOS or Windows from MockCAN import CANBackend @@ -30,6 +32,37 @@ can_backend = CANBackend() # Serve static files (HTML, JS, CSS) app.mount("/static", StaticFiles(directory="static"), name="static") +## BUFFER CREATION AND HELPER +# Global object to store the latest data +latest_data: Dict[str, Any] = {"PU_1": None, "PU_2": None, "PU_3": None} + + +def format_data(data): + return { + "timestamp": datetime.datetime.now().isoformat(), + "Qperm": data.get("FM2", 0.0), + "Qdilute": data.get("FM1", 0.0), + "Qdrain": data.get("FM4", 0.0), + "Qrecirc": data.get("FM3", 0.0), + "Pro": data.get("PS1", 0.0), + "Pdilute": data.get("PS3", 0.0), + "Prentate": data.get("PS2", 0.0), + "Conductivity": data.get("Cond", 0.0), + "MV02": data.get("MV02", 0.0), + "MV02_sp": data.get("MV02_sp", 0.0), + "MV03": data.get("MV03", 0.0), + "MV03_sp": data.get("MV03_sp", 0.0), + "MV05": data.get("MV05", 0.0), + "MV05_sp": data.get("MV05_sp", 0.0), + "MV06": data.get("MV06", 0.0), + "MV06_sp": data.get("MV06_sp", 0.0), + "MV07": data.get("MV07", 0.0), + "MV07_sp": data.get("MV07_sp", 0.0), + "MV08": data.get("MV08", 0.0), + "MV08_sp": data.get("MV08_sp", 0.0), + } + + # CREDENTIALS # Load users from JSON file at startup @@ -152,41 +185,27 @@ def get_pu_status(): return JSONResponse(content=states) +async def update_latest_data(): + while True: + for pu in [1, 2, 3]: + data = can_backend.get_latest_data(pu_number=pu) + logging.info(f"[MONITOR BUFFER] PU{pu}: {data}") + latest_data[f"PU_{pu}"] = format_data(data) + await asyncio.sleep(0.1) # Update every 100ms + + @app.get("/monitor") -def get_monitor_data(pu_number: Optional[int] = Query(None)): - logging.info(f"[MONITOR DATA] {pu_number}") - def format_data(data): - return { - "Qperm": data.get("FM2", 0.0), - "Qdilute": data.get("FM1", 0.0), - "Qdrain": data.get("FM4", 0.0), - "Qrecirc": data.get("FM3", 0.0), +async def get_monitor_data(pu_number: Optional[int] = Query(None)): + logging.info(f"[MONITOR DATA QUERY] {pu_number}") + if pu_number: + return latest_data.get(f"PU_{pu_number}", {}) + else: + return latest_data - "Pro": data.get("PS1", 0.0), - "Pdilute": data.get("PS3", 0.0), - "Prentate": data.get("PS2", 0.0), - "Conductivity": data.get("Cond", 0.0), - - "MV02": data.get("MV02", 0.0), - "MV02_sp": data.get("MV02_sp", 0.0), - "MV03": data.get("MV03", 0.0), - "MV03_sp": data.get("MV03_sp", 0.0), - "MV05": data.get("MV05", 0.0), - "MV05_sp": data.get("MV05_sp", 0.0), - "MV06": data.get("MV06", 0.0), - "MV06_sp": data.get("MV06_sp", 0.0), - "MV07": data.get("MV07", 0.0), - "MV07_sp": data.get("MV07_sp", 0.0), - "MV08": data.get("MV08", 0.0), - "MV08_sp": data.get("MV08_sp", 0.0), - } - all_data = {} - for pu in [1, 2, 3]: - data = can_backend.get_latest_data(pu_number=pu) - logging.info(f"[MONITOR] PU{pu}: {data}") - all_data[f"PU_{pu}"] = format_data(data) - return all_data +@app.on_event("startup") +async def startup_event(): + asyncio.create_task(update_latest_data()) @app.get("/can_status") diff --git a/static/monitor.html b/static/monitor.html index 9871650..9cb7158 100644 --- a/static/monitor.html +++ b/static/monitor.html @@ -134,7 +134,6 @@ }; const maxPoints = 100; - const time = () => new Date(); function getLastMinuteRange() { const now = new Date(); @@ -148,30 +147,22 @@ if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`); const allData = await response.json(); const puData = allData[`PU_${puNumber}`]; - const t = time(); + + // Convert timestamp string to Date object + const timestamp = new Date(puData.timestamp); + Plotly.extendTraces('flow-plot', { - x: [[t], [t], [t], [t]], + x: [[timestamp], [timestamp], [timestamp], [timestamp]], y: [[puData.Qperm], [puData.Qdilute], [puData.Qdrain], [puData.Qrecirc]] }, [0, 1, 2, 3], maxPoints); + Plotly.extendTraces('pressure-plot', { - x: [[t], [t], [t]], + x: [[timestamp], [timestamp], [timestamp]], y: [[puData.Pro], [puData.Pdilute], [puData.Prentate]] }, [0, 1, 2], maxPoints); - // Plotly.extendTraces('mv02-plot', { x: [[t]], y: [[puData.MV02]] }, [0]); - // Plotly.extendTraces('mv03-plot', { x: [[t]], y: [[puData.MV03]] }, [0]); - // Plotly.extendTraces('mv04-05-plot', { - // x: [[t], [t]], - // y: [[puData.MV04], [puData.MV05]] - // }, [0, 1]); - // Plotly.extendTraces('mv06-plot', { x: [[t]], y: [[puData.MV06]] }, [0]); - // Plotly.extendTraces('mv07-plot', { x: [[t]], y: [[puData.MV07]] }, [0]); - // Plotly.extendTraces('mv08-plot', { x: [[t]], y: [[puData.MV08]] }, [0]); const range = getLastMinuteRange(); - const plotIds = [ - 'flow-plot', 'pressure-plot', 'mv02-plot', 'mv03-plot', - 'mv04-05-plot', 'mv06-plot', 'mv07-plot', 'mv08-plot' - ]; + const plotIds = ['flow-plot', 'pressure-plot']; plotIds.forEach(id => { Plotly.relayout(id, { 'xaxis.range': range }); }); @@ -181,7 +172,7 @@ } function initPlots() { - const time0 = [time()]; + const time0 = [new Date()]; // Use current time for initialization Plotly.newPlot('flow-plot', [ { x: time0, y: [0], name: 'Qperm', mode: 'lines', line: { color: 'blue' } }, { x: time0, y: [0], name: 'Qdilute', mode: 'lines', line: { color: 'green' } }, @@ -192,6 +183,7 @@ xaxis: { title: 'Time', type: 'date' }, yaxis: { title: 'Flow (L/h)', range: [0, 2000] } }); + Plotly.newPlot('pressure-plot', [ { x: time0, y: [0], name: 'Pro', mode: 'lines', line: { color: 'purple' } }, { x: time0, y: [0], name: 'Pdilute', mode: 'lines', line: { color: 'teal' } }, @@ -201,37 +193,7 @@ xaxis: { title: 'Time', type: 'date' }, yaxis: { title: 'Pressure (bar)', range: [0, 15] } }); - // Plotly.newPlot('mv02-plot', [{ - // x: time0, y: [0], name: 'MV02', mode: 'lines' - // }], { - // title: 'MV02 (%)', yaxis: { range: [0, 100] }, xaxis: { type: 'date' } - // }); - // Plotly.newPlot('mv03-plot', [{ - // x: time0, y: [0], name: 'MV03', mode: 'lines' - // }], { - // title: 'MV03 (%)', yaxis: { range: [0, 100] }, xaxis: { type: 'date' } - // }); - // Plotly.newPlot('mv04-05-plot', [ - // { x: time0, y: [0], name: 'MV04', mode: 'lines' }, - // { x: time0, y: [0], name: 'MV05', mode: 'lines' } - // ], { - // title: 'MV04 + MV05 (%)', yaxis: { range: [0, 100] }, xaxis: { type: 'date' } - // }); - // Plotly.newPlot('mv06-plot', [{ - // x: time0, y: [0], name: 'MV06', mode: 'lines' - // }], { - // title: 'MV06 (%)', yaxis: { range: [0, 100] }, xaxis: { type: 'date' } - // }); - // Plotly.newPlot('mv07-plot', [{ - // x: time0, y: [0], name: 'MV07', mode: 'lines' - // }], { - // title: 'MV07 (%)', yaxis: { range: [0, 100] }, xaxis: { type: 'date' } - // }); - // Plotly.newPlot('mv08-plot', [{ - // x: time0, y: [0], name: 'MV08', mode: 'lines' - // }], { - // title: 'MV08 (%)', yaxis: { range: [0, 100] }, xaxis: { type: 'date' } - // }); + setInterval(updatePlots, 250); }