From 21d24e1176e16410bb0f02e5ecbf82140c1d8890 Mon Sep 17 00:00:00 2001 From: aniketSaha Date: Tue, 15 Jul 2025 17:28:00 +0200 Subject: [PATCH] Changes related to adding feed valve --- classCAN.py | 22 +- eds_file/inletvalveboard.eds | 385 +++++++++++++++++++++++++++++++++++ main.py | 20 +- static/monitor.html | 2 +- 4 files changed, 418 insertions(+), 11 deletions(-) create mode 100644 eds_file/inletvalveboard.eds diff --git a/classCAN.py b/classCAN.py index 27ffbf5..81fc2ed 100644 --- a/classCAN.py +++ b/classCAN.py @@ -5,7 +5,7 @@ import os class CANBackend: - def __init__(self): + def __init__(self, eds_file =None): self.network = None self.nodes = {} # {1: RemoteNode(0x02), 2: RemoteNode(0x03), ...} self.connected = False @@ -17,7 +17,10 @@ class CANBackend: 2: {}, # PU2 3: {} # PU3 } - self.eds_path = os.path.join(os.path.dirname(__file__), "eds_file", "processBoard_0.eds") + if eds_file is None: + self.eds_path = os.path.join(os.path.dirname(__file__), "eds_file", "processBoard_0.eds") + else: + self.eds_path = eds_file def connect(self): try: @@ -28,7 +31,8 @@ class CANBackend: node_map = { 1: 0x02, 2: 0x04, - 3: 0x127 + 3: 0x127, + 4: 0xF } for pu_number, node_id in node_map.items(): @@ -162,6 +166,18 @@ class CANBackend: except Exception as e: print(f"[SDO WRITE ERROR] PU{pu_number}: {e}") raise + + def send_command(self, opening :int): + try: + node = self.nodes.get(4) + if node is None: + raise ValueError(f"Feed valve is not connected") + + node.sdo[0x6000].raw = opening + + except Exception as e: + print(f"[SDO WRITE ERROR] Valve Board: {e}") + raise def send_thermal_loop_cleaning(self, mode: str, pu_number: int): if not self.connected: diff --git a/eds_file/inletvalveboard.eds b/eds_file/inletvalveboard.eds new file mode 100644 index 0000000..9553ed3 --- /dev/null +++ b/eds_file/inletvalveboard.eds @@ -0,0 +1,385 @@ +; EDS file for inletvalveboard - generated by CANopen DeviceDesigner 3.14.2 +[FileInfo] +FileName=inletvalveboard.eds +FileVersion=1.0 +FileRevision=1.0 +EDSVersion=4.0 +Description=EDS +CreationTime=12:05PM +CreationDate=04-15-25 +ModificationTime=12:05PM +ModificationDate=04-15-25 +CreatedBy=Vineeta Gupta +ModifiedBy=Vineeta Gupta + +[Comments] +Lines=1 +Line1=generated by CANopen DeviceDesigner by emotas + +[DeviceInfo] +VendorName=nehemis +VendorNumber=0x319 +ProductName=InletValveController +ProductNumber=1234 +RevisionNumber=0x1 +OrderCode=InletValveController +BaudRate_10=0 +BaudRate_20=0 +BaudRate_50=0 +BaudRate_125=0 +BaudRate_250=1 +BaudRate_500=0 +BaudRate_800=0 +BaudRate_1000=0 +NrOfRxPDO=0 +NrOfTxPDO=1 +SimpleBootupSlave=1 +SimpleBootupMaster=0 +LSS_Supported=0 +Granularity=0 +DynamicChannelsSupported=0 +GroupMessaging=0 + +[DummyUsage] +Dummy0001=0 +Dummy0002=0 +Dummy0003=0 +Dummy0004=0 +Dummy0005=0 +Dummy0006=0 +Dummy0007=0 + +[MandatoryObjects] +SupportedObjects=3 +1=0x1000 +2=0x1001 +3=0x1018 + +[ManufacturerObjects] +SupportedObjects=2 +1=0x2001 +2=0x3000 + +[OptionalObjects] +SupportedObjects=13 +1=0x1003 +2=0x1008 +3=0x1014 +4=0x1015 +5=0x1016 +6=0x1017 +7=0x1029 +8=0x1200 +9=0x1800 +10=0x1a00 +11=0x6000 +12=0x6001 +13=0x6002 + +[1000] +ParameterName=Device Type +ObjectType=7 +DataType=7 +AccessType=ro +PDOMapping=0 +DefaultValue=0 + +[1001] +ParameterName=Error Register +ObjectType=7 +DataType=5 +AccessType=ro +PDOMapping=0 + +[1003] +ParameterName=Predefined Error Field +ObjectType=8 +SubNumber=2 + +[1003sub0] +ParameterName=Number of Errors +ObjectType=7 +DataType=5 +AccessType=rw +PDOMapping=0 +DefaultValue=0 + +[1003sub1] +ParameterName=Standard Error Field +ObjectType=7 +DataType=7 +AccessType=ro +PDOMapping=0 +DefaultValue=0 + +[1008] +ParameterName=Manufacturer device name +ObjectType=7 +DataType=9 +AccessType=const +PDOMapping=0 +DefaultValue=emotas Slave 1 + +[1014] +ParameterName=COB ID EMCY +ObjectType=7 +DataType=7 +AccessType=ro +PDOMapping=0 +DefaultValue=$NODEID+0x80 + +[1015] +ParameterName=Inhibit Time Emergency +ObjectType=7 +DataType=6 +AccessType=rw +PDOMapping=0 +DefaultValue=0x0 + +[1016] +ParameterName=Consumer Heartbeat Time +ObjectType=8 +SubNumber=1 + +[1016sub0] +ParameterName=Number of entries +ObjectType=7 +DataType=5 +AccessType=ro +PDOMapping=0 +DefaultValue=0 + +[1017] +ParameterName=Producer Heartbeat Time +ObjectType=7 +DataType=6 +AccessType=rw +PDOMapping=0 + +[1018] +ParameterName=Identity Object +ObjectType=9 +SubNumber=5 + +[1018sub0] +ParameterName=Number of entries +ObjectType=7 +DataType=5 +AccessType=ro +PDOMapping=0 +DefaultValue=4 + +[1018sub1] +ParameterName=Vendor Id +ObjectType=7 +DataType=7 +AccessType=ro +PDOMapping=0 +DefaultValue=0x319 + +[1018sub2] +ParameterName=Product Code +ObjectType=7 +DataType=7 +AccessType=ro +PDOMapping=0 +DefaultValue=1234 + +[1018sub3] +ParameterName=Revision number +ObjectType=7 +DataType=7 +AccessType=ro +PDOMapping=0 +DefaultValue=0x1 + +[1018sub4] +ParameterName=Serial number +ObjectType=7 +DataType=7 +AccessType=ro +PDOMapping=0 + +[1029] +ParameterName=Error behaviour +ObjectType=8 +SubNumber=3 + +[1029sub0] +ParameterName=Nr of Error Classes +ObjectType=7 +DataType=5 +AccessType=ro +PDOMapping=0 +DefaultValue=2 + +[1029sub1] +ParameterName=Communication Error +ObjectType=7 +DataType=5 +AccessType=rw +PDOMapping=0 +DefaultValue=1 + +[1029sub2] +ParameterName=Specific Error Class +ObjectType=7 +DataType=5 +AccessType=rw +PDOMapping=0 + +[1200] +ParameterName=Server SDO Parameter +ObjectType=9 +SubNumber=3 + +[1200sub0] +ParameterName=Number of entries +ObjectType=7 +DataType=5 +AccessType=ro +PDOMapping=0 +DefaultValue=2 + +[1200sub1] +ParameterName=COB ID Client to Server +ObjectType=7 +DataType=7 +AccessType=ro +PDOMapping=0 +DefaultValue=$NODEID+0x600 + +[1200sub2] +ParameterName=COB ID Server to Client +ObjectType=7 +DataType=7 +AccessType=ro +PDOMapping=0 +DefaultValue=$NODEID+0x580 + +[1800] +ParameterName=TPDO communication parameter +ObjectType=9 +SubNumber=6 + +[1800sub0] +ParameterName=Highest sub-index supported +ObjectType=7 +DataType=5 +AccessType=const +PDOMapping=0 +DefaultValue=6 + +[1800sub1] +ParameterName=COB-ID used by TPDO +ObjectType=7 +DataType=7 +AccessType=rw +PDOMapping=0 + +[1800sub2] +ParameterName=Transmission type +ObjectType=7 +DataType=5 +AccessType=rw +PDOMapping=0 + +[1800sub3] +ParameterName=Inhibit time +ObjectType=7 +DataType=6 +AccessType=rw +PDOMapping=0 + +[1800sub5] +ParameterName=Event timer +ObjectType=7 +DataType=6 +AccessType=rw +PDOMapping=0 + +[1800sub6] +ParameterName=SYNC start value +ObjectType=7 +DataType=5 +AccessType=rw +PDOMapping=0 + +[1a00] +ParameterName=Transmit PDO Mapping Parameter +ObjectType=9 +SubNumber=2 +;;This object contains the mapping for the PDO the device is able to transmit. +;; + +[1a00sub0] +ParameterName=Highest sub-index supported +ObjectType=7 +DataType=5 +AccessType=const +PDOMapping=0 +DefaultValue=1 + +[1a00sub1] +ParameterName=Mapping Entry 1 +ObjectType=7 +DataType=7 +AccessType=const +PDOMapping=0 +DefaultValue=0x60010008 + +[2001] +ParameterName=Manufacturer Object +ObjectType=7 +DataType=4 +AccessType=rw +PDOMapping=1 + +[3000] +ParameterName=Managed Array +ObjectType=8 +SubNumber=3 + +[3000sub0] +ParameterName=NUmber of Entries +ObjectType=7 +DataType=5 +AccessType=ro +PDOMapping=0 +DefaultValue=2 + +[3000sub1] +ParameterName=Sub 1 +ObjectType=7 +DataType=3 +AccessType=ro +PDOMapping=1 + +[3000sub2] +ParameterName=sub 2 +ObjectType=7 +DataType=3 +AccessType=rw +PDOMapping=1 + +[6000] +ParameterName=Position Set Point +ObjectType=7 +DataType=5 +AccessType=rw +PDOMapping=0 + +[6001] +ParameterName=Position Feedback +ObjectType=7 +DataType=5 +AccessType=rw +PDOMapping=1 + +[6002] +ParameterName=Motor Current +ObjectType=7 +DataType=8 +AccessType=rw +PDOMapping=1 + diff --git a/main.py b/main.py index 6b9c5e2..3197523 100644 --- a/main.py +++ b/main.py @@ -29,6 +29,8 @@ router = APIRouter() templates = Jinja2Templates(directory="templates") logging.basicConfig(level=logging.INFO) can_backend = CANBackend() +valve_backend = CANBackend(eds_file="/home/hmi/Desktop/HMI/eds_file/inletvalveboard.eds") + # Serve static files (HTML, JS, CSS) app.mount("/static", StaticFiles(directory="static"), name="static") @@ -136,10 +138,15 @@ def connect_toggle(): return {"connected": False} else: success = can_backend.connect() - if not success: - raise HTTPException(status_code=500, detail="Connection failed.") - return {"connected": True} + try: + valve_backend.connect() + except Exception as e: + print(f"Connection error : {e}") + if not success: + raise HTTPException(status_code=500, detail="Connection failed.") + return {"connected": True} + @app.post("/command/{state}/pu/{pu_number}") def send_command(state: str, pu_number: int, ploop_setpoint: float = Query(...)): @@ -191,7 +198,7 @@ async def update_latest_data(): 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 + await asyncio.sleep(0.2) # Update every 100ms @app.get("/monitor") @@ -215,13 +222,12 @@ def can_status(): @app.post("/command/feed_valve") -def can_status(MV01_opening: int = Query(...)): +def feedvalve_control(MV01_opening: int = Query(...)): """Control MV01 feed valve""" - # can_backend.send_command(MV01_opening) # TODO: TODO + valve_backend.send_command(MV01_opening) # TODO: TODO logging.info(f"Feed valve opening to {MV01_opening}") return {"status": "ok"} - app.include_router(router) if __name__ == "__main__": diff --git a/static/monitor.html b/static/monitor.html index 9cb7158..d447431 100644 --- a/static/monitor.html +++ b/static/monitor.html @@ -194,7 +194,7 @@ yaxis: { title: 'Pressure (bar)', range: [0, 15] } }); - setInterval(updatePlots, 250); + setInterval(updatePlots, 500); } window.onload = initPlots;