Compare commits

...

2 Commits

Author SHA1 Message Date
Etienne Chassaing
edc3a45194 Merge branch 'main' of https://git.nehemis.fr/aniketSaha/NorthStar-HMI
# Conflicts:
#	main.py
2025-07-17 12:32:29 +02:00
Etienne Chassaing
c74264545b Range updates 2025-07-17 12:31:16 +02:00
2 changed files with 53 additions and 34 deletions

79
main.py
View File

@ -25,10 +25,12 @@ import aiohttp
if platform.system() in ["Darwin"]: # macOS or Windows if platform.system() in ["Darwin"]: # macOS or Windows
from MockCAN import CANBackend from MockCAN import CANBackend
logging.basicConfig(level=logging.INFO) logging.basicConfig(level=logging.INFO)
else: else:
from classCAN import CANBackend # Your real backend from classCAN import CANBackend # Your real backend
logging.basicConfig(level=logging.ERROR) logging.basicConfig(level=logging.ERROR)
app = FastAPI() app = FastAPI()
@ -36,14 +38,21 @@ app.add_middleware(SessionMiddleware, secret_key="your_super_secret_key")
router = APIRouter() router = APIRouter()
templates = Jinja2Templates(directory="templates") templates = Jinja2Templates(directory="templates")
can_backend = CANBackend() can_backend = CANBackend()
valve_backend = ValveBackend(eds_file="/home/hmi/Desktop/HMI/eds_file/inletvalveboard.eds") valve_backend = ValveBackend(
eds_file="/home/hmi/Desktop/HMI/eds_file/inletvalveboard.eds"
)
# 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 ## BUFFER CREATION AND HELPER
# Global object to store the latest data # Global object to store the latest data
latest_data: Dict[str, Any] = {"PU_1": None, "PU_2": None, "PU_3": None, "PatientSkid" : {"QSkid":0.0}} latest_data: Dict[str, Any] = {
"PU_1": None,
"PU_2": None,
"PU_3": None,
"PatientSkid": {"QSkid": 0.0},
}
# RECORDER # RECORDER
recording_flag = False recording_flag = False
@ -54,6 +63,7 @@ write_buffer = deque()
flush_interval = 1.0 # flush every 1 second flush_interval = 1.0 # flush every 1 second
last_flush_time = datetime.datetime.now() last_flush_time = datetime.datetime.now()
## LOGGING QSkid ## LOGGING QSkid
async def update_latest_flow(): async def update_latest_flow():
async with aiohttp.ClientSession() as session: async with aiohttp.ClientSession() as session:
@ -73,30 +83,31 @@ async def update_latest_flow():
def format_data(data): def format_data(data):
return { return {
"timestamp": datetime.datetime.now().isoformat(), "timestamp": datetime.datetime.now().isoformat(),
"Qperm": data.get("FM2", 0.0), "Qperm": np.round(data.get("FM2", 0.0), 1),
"Qdilute": data.get("FM1", 0.0), "Qdilute": np.round(data.get("FM1", 0.0), 1),
"Qdrain": data.get("FM4", 0.0), "Qdrain": np.round(data.get("FM4", 0.0), 1),
"Qrecirc": data.get("FM3", 0.0), "Qrecirc": np.round(data.get("FM3", 0.0), 1),
"Pro": data.get("PS1", 0.0), "Pro": np.round(data.get("PS1", 0.0), 1),
"Pdilute": data.get("PS3", 0.0), "Pdilute": np.round(data.get("PS3", 0.0), 1),
"Prentate": data.get("PS2", 0.0), "Prentate": np.round(data.get("PS2", 0.0), 1),
"Conductivity": data.get("Cond", 0.0), "Conductivity": np.round(data.get("Cond", 0.0), 1),
"MV02": data.get("MV02", 0.0), "MV02": np.round(data.get("MV02", 0.0), 1),
"MV02_sp": data.get("MV02_sp", 0.0), "MV02_sp": np.round(data.get("MV02_sp", 0.0), 1),
"MV03": data.get("MV03", 0.0), "MV03": np.round(data.get("MV03", 0.0), 1),
"MV03_sp": data.get("MV03_sp", 0.0), "MV03_sp": np.round(data.get("MV03_sp", 0.0), 1),
"MV04": data.get("MV05", 0.0), "MV04": np.round(data.get("MV05", 0.0), 1),
"MV04_sp": data.get("MV05_sp", 0.0), "MV04_sp": np.round(data.get("MV05_sp", 0.0), 1),
"MV05": data.get("MV05", 0.0), "MV05": np.round(data.get("MV05", 0.0), 1),
"MV05_sp": data.get("MV05_sp", 0.0), "MV05_sp": np.round(data.get("MV05_sp", 0.0), 1),
"MV06": data.get("MV06", 0.0), "MV06": np.round(data.get("MV06", 0.0), 1),
"MV06_sp": data.get("MV06_sp", 0.0), "MV06_sp": np.round(data.get("MV06_sp", 0.0), 1),
"MV07": data.get("MV07", 0.0), "MV07": np.round(data.get("MV07", 0.0), 1),
"MV07_sp": data.get("MV07_sp", 0.0), "MV07_sp": np.round(data.get("MV07_sp", 0.0), 1),
"MV08": data.get("MV08", 0.0), "MV08": np.round(data.get("MV08", 0.0), 1),
"MV08_sp": data.get("MV08_sp", 0.0), "MV08_sp": np.round(data.get("MV08_sp", 0.0), 1),
} }
# CREDENTIALS # CREDENTIALS
# Load users from JSON file at startup # Load users from JSON file at startup
@ -169,14 +180,14 @@ def connect_toggle():
else: else:
success = can_backend.connect() success = can_backend.connect()
try: try:
valve_backend.connect() valve_backend.connect()
except Exception as e: except Exception as e:
print(f"Connection error : {e}") print(f"Connection error : {e}")
if not success: if not success:
raise HTTPException(status_code=500, detail="Connection failed.") raise HTTPException(status_code=500, detail="Connection failed.")
return {"connected": True} return {"connected": True}
@app.post("/command/{state}/pu/{pu_number}") @app.post("/command/{state}/pu/{pu_number}")
def send_command(state: str, pu_number: int, ploop_setpoint: float = Query(...)): def send_command(state: str, pu_number: int, ploop_setpoint: float = Query(...)):
@ -225,7 +236,10 @@ def get_pu_status():
async def update_latest_data(): async def update_latest_data():
while True: while True:
for pu in [1, 2]: # TODO: REPLACE THIS WITH CONNECTED PUs, IS GET PU STATUS SLOW? for pu in [
1,
2,
]: # TODO: REPLACE THIS WITH CONNECTED PUs, IS GET PU STATUS SLOW?
data = can_backend.get_latest_data(pu_number=pu) data = can_backend.get_latest_data(pu_number=pu)
latest_data[f"PU_{pu}"] = format_data(data) latest_data[f"PU_{pu}"] = format_data(data)
current_data = latest_data[f"PU_{pu}"] current_data = latest_data[f"PU_{pu}"]
@ -263,7 +277,8 @@ def feedvalve_control(MV01_opening: int = Query(...)):
logging.info(f"Feed valve opening to {MV01_opening}") logging.info(f"Feed valve opening to {MV01_opening}")
return {"status": "ok"} return {"status": "ok"}
#LOCAL RECORDER
# LOCAL RECORDER
@app.post("/start_recording") @app.post("/start_recording")
async def start_recording(): async def start_recording():
global recording_flag, recording_task, recording_file, recording_writer global recording_flag, recording_task, recording_file, recording_writer
@ -307,7 +322,6 @@ async def stop_recording():
return {"status": "recording stopped"} return {"status": "recording stopped"}
async def record_data_loop(): async def record_data_loop():
global recording_writer, recording_file, write_buffer, last_flush_time global recording_writer, recording_file, write_buffer, last_flush_time
@ -315,6 +329,7 @@ async def record_data_loop():
timestamp = datetime.datetime.now().isoformat() timestamp = datetime.datetime.now().isoformat()
for pu, data in latest_data.items(): for pu, data in latest_data.items():
if data: if data:
row = {"timestamp": timestamp, "pu": pu, **data}
print("record_data",data) print("record_data",data)
row = { row = {
"timestamp": timestamp, "timestamp": timestamp,
@ -324,11 +339,15 @@ async def record_data_loop():
recording_writer.writerow(row) recording_writer.writerow(row)
# Flush every flush_interval seconds # Flush every flush_interval seconds
if (datetime.datetime.now() - last_flush_time).total_seconds() >= flush_interval: if (
datetime.datetime.now() - last_flush_time
).total_seconds() >= flush_interval:
recording_file.flush() recording_file.flush()
last_flush_time = datetime.datetime.now() last_flush_time = datetime.datetime.now()
await asyncio.sleep(0.1) # 10 Hz await asyncio.sleep(0.1) # 10 Hz
app.include_router(router) app.include_router(router)
if __name__ == "__main__": if __name__ == "__main__":

View File

@ -260,13 +260,13 @@
Plotly.newPlot('MV02_sp-plot', [{ Plotly.newPlot('MV02_sp-plot', [{
x: time0, y: [0], name: 'MV02_sp', mode: 'lines' x: time0, y: [0], name: 'MV02_sp', mode: 'lines'
}], { }], {
title: 'MV02_sp (%)', yaxis: { range: [0, 100] }, xaxis: { type: 'date' } title: 'MV02_sp (%)', yaxis: { }, xaxis: { type: 'date' }
}); });
Plotly.newPlot('MV03_sp-plot', [{ Plotly.newPlot('MV03_sp-plot', [{
x: time0, y: [0], name: 'MV03_sp', mode: 'lines' x: time0, y: [0], name: 'MV03_sp', mode: 'lines'
}], { }], {
title: 'MV03_sp (%)', yaxis: { range: [0, 100] }, xaxis: { type: 'date' } title: 'MV03_sp (%)', yaxis: { }, xaxis: { type: 'date' }
}); });
Plotly.newPlot('MV04_sp-05-plot', [ Plotly.newPlot('MV04_sp-05-plot', [
@ -279,13 +279,13 @@
Plotly.newPlot('MV06_sp-plot', [{ Plotly.newPlot('MV06_sp-plot', [{
x: time0, y: [0], name: 'MV06_sp', mode: 'lines' x: time0, y: [0], name: 'MV06_sp', mode: 'lines'
}], { }], {
title: 'MV06_sp (%)', yaxis: { range: [0, 100] }, xaxis: { type: 'date' } title: 'MV06_sp (%)', yaxis: { }, xaxis: { type: 'date' }
}); });
Plotly.newPlot('MV07_sp-plot', [{ Plotly.newPlot('MV07_sp-plot', [{
x: time0, y: [0], name: 'MV07_sp', mode: 'lines' x: time0, y: [0], name: 'MV07_sp', mode: 'lines'
}], { }], {
title: 'MV07_sp (%)', yaxis: { range: [0, 100] }, xaxis: { type: 'date' } title: 'MV07_sp (%)', yaxis: { }, xaxis: { type: 'date' }
}); });
Plotly.newPlot('MV08_sp-plot', [{ Plotly.newPlot('MV08_sp-plot', [{