Timestamp synchro

This commit is contained in:
Etienne Chassaing 2025-07-15 16:19:36 +02:00
parent 656ae95f19
commit 1ddf8276ef
2 changed files with 63 additions and 82 deletions

87
main.py
View File

@ -13,8 +13,10 @@ from starlette.exceptions import HTTPException as StarletteHTTPException
from starlette.status import HTTP_302_FOUND from starlette.status import HTTP_302_FOUND
import json import json
from pathlib import Path from pathlib import Path
from typing import Optional from typing import Optional, Dict, Any
from fastapi import Query from fastapi import Query
import asyncio
import datetime
if platform.system() in ["Darwin"]: # macOS or Windows if platform.system() in ["Darwin"]: # macOS or Windows
from MockCAN import CANBackend from MockCAN import CANBackend
@ -30,6 +32,37 @@ can_backend = CANBackend()
# Serve static files (HTML, JS, CSS) # Serve static files (HTML, JS, CSS)
app.mount("/static", StaticFiles(directory="static"), name="static") 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 # CREDENTIALS
# Load users from JSON file at startup # Load users from JSON file at startup
@ -152,41 +185,27 @@ def get_pu_status():
return JSONResponse(content=states) return JSONResponse(content=states)
@app.get("/monitor") async def update_latest_data():
def get_monitor_data(pu_number: Optional[int] = Query(None)): while True:
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),
"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]: for pu in [1, 2, 3]:
data = can_backend.get_latest_data(pu_number=pu) data = can_backend.get_latest_data(pu_number=pu)
logging.info(f"[MONITOR] PU{pu}: {data}") logging.info(f"[MONITOR BUFFER] PU{pu}: {data}")
all_data[f"PU_{pu}"] = format_data(data) latest_data[f"PU_{pu}"] = format_data(data)
return all_data await asyncio.sleep(0.1) # Update every 100ms
@app.get("/monitor")
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
@app.on_event("startup")
async def startup_event():
asyncio.create_task(update_latest_data())
@app.get("/can_status") @app.get("/can_status")

View File

@ -134,7 +134,6 @@
}; };
const maxPoints = 100; const maxPoints = 100;
const time = () => new Date();
function getLastMinuteRange() { function getLastMinuteRange() {
const now = new Date(); const now = new Date();
@ -148,30 +147,22 @@
if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`); if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`);
const allData = await response.json(); const allData = await response.json();
const puData = allData[`PU_${puNumber}`]; const puData = allData[`PU_${puNumber}`];
const t = time();
// Convert timestamp string to Date object
const timestamp = new Date(puData.timestamp);
Plotly.extendTraces('flow-plot', { Plotly.extendTraces('flow-plot', {
x: [[t], [t], [t], [t]], x: [[timestamp], [timestamp], [timestamp], [timestamp]],
y: [[puData.Qperm], [puData.Qdilute], [puData.Qdrain], [puData.Qrecirc]] y: [[puData.Qperm], [puData.Qdilute], [puData.Qdrain], [puData.Qrecirc]]
}, [0, 1, 2, 3], maxPoints); }, [0, 1, 2, 3], maxPoints);
Plotly.extendTraces('pressure-plot', { Plotly.extendTraces('pressure-plot', {
x: [[t], [t], [t]], x: [[timestamp], [timestamp], [timestamp]],
y: [[puData.Pro], [puData.Pdilute], [puData.Prentate]] y: [[puData.Pro], [puData.Pdilute], [puData.Prentate]]
}, [0, 1, 2], maxPoints); }, [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 range = getLastMinuteRange();
const plotIds = [ const plotIds = ['flow-plot', 'pressure-plot'];
'flow-plot', 'pressure-plot', 'mv02-plot', 'mv03-plot',
'mv04-05-plot', 'mv06-plot', 'mv07-plot', 'mv08-plot'
];
plotIds.forEach(id => { plotIds.forEach(id => {
Plotly.relayout(id, { 'xaxis.range': range }); Plotly.relayout(id, { 'xaxis.range': range });
}); });
@ -181,7 +172,7 @@
} }
function initPlots() { function initPlots() {
const time0 = [time()]; const time0 = [new Date()]; // Use current time for initialization
Plotly.newPlot('flow-plot', [ Plotly.newPlot('flow-plot', [
{ x: time0, y: [0], name: 'Qperm', mode: 'lines', line: { color: 'blue' } }, { x: time0, y: [0], name: 'Qperm', mode: 'lines', line: { color: 'blue' } },
{ x: time0, y: [0], name: 'Qdilute', mode: 'lines', line: { color: 'green' } }, { x: time0, y: [0], name: 'Qdilute', mode: 'lines', line: { color: 'green' } },
@ -192,6 +183,7 @@
xaxis: { title: 'Time', type: 'date' }, xaxis: { title: 'Time', type: 'date' },
yaxis: { title: 'Flow (L/h)', range: [0, 2000] } yaxis: { title: 'Flow (L/h)', range: [0, 2000] }
}); });
Plotly.newPlot('pressure-plot', [ Plotly.newPlot('pressure-plot', [
{ x: time0, y: [0], name: 'Pro', mode: 'lines', line: { color: 'purple' } }, { x: time0, y: [0], name: 'Pro', mode: 'lines', line: { color: 'purple' } },
{ x: time0, y: [0], name: 'Pdilute', mode: 'lines', line: { color: 'teal' } }, { x: time0, y: [0], name: 'Pdilute', mode: 'lines', line: { color: 'teal' } },
@ -201,37 +193,7 @@
xaxis: { title: 'Time', type: 'date' }, xaxis: { title: 'Time', type: 'date' },
yaxis: { title: 'Pressure (bar)', range: [0, 15] } 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); setInterval(updatePlots, 250);
} }