From ea3ec2b3f94e3a5f11b53061f2601553b6ef75ed Mon Sep 17 00:00:00 2001 From: openhands Date: Sat, 1 Nov 2025 20:20:08 +0000 Subject: [PATCH] feat: Restore protocol client integration for Modbus in signals endpoint - Use real Modbus data when available - Keep fallback for OPC UA until security policy issues are resolved - Maintain graceful fallback to mock data if protocol clients fail --- src/dashboard/api.py | 98 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 92 insertions(+), 6 deletions(-) diff --git a/src/dashboard/api.py b/src/dashboard/api.py index 9da6f97..b231068 100644 --- a/src/dashboard/api.py +++ b/src/dashboard/api.py @@ -716,12 +716,98 @@ async def get_signals(): signals = [] - # Always use fallback signals for now to avoid protocol client issues - logger.info("using_fallback_signals_for_testing") - for station_id, station in stations.items(): - pumps = pumps_by_station.get(station_id, []) - for pump in pumps: - signals.extend(_create_fallback_signals(station_id, pump['pump_id'])) + # Try to use real protocol data for Modbus, fallback for OPC UA + try: + from .protocol_clients import ModbusTCPClient + + # Create Modbus client + modbus_client = ModbusTCPClient( + host="localhost", + port=502, + unit_id=1 + ) + + # Connect to Modbus server + if await modbus_client.connect(): + logger.info("using_real_modbus_data") + + # Read pump data from Modbus server + for station_id, station in stations.items(): + pumps = pumps_by_station.get(station_id, []) + for pump in pumps: + pump_id = pump['pump_id'] + + # Get pump data from Modbus + pump_data = await modbus_client.get_pump_data(pump_id) + + # Create signals from real Modbus data + signals.extend([ + { + "name": f"Station_{station_id}_Pump_{pump_id}_Setpoint", + "protocol": "modbus", + "address": "0", + "data_type": "Integer", + "current_value": f"{pump_data.get('setpoint', 0)} Hz", + "quality": "Good", + "timestamp": datetime.now().strftime("%Y-%m-%d %H:%M:%S") + }, + { + "name": f"Station_{station_id}_Pump_{pump_id}_ActualSpeed", + "protocol": "modbus", + "address": "100", + "data_type": "Integer", + "current_value": f"{pump_data.get('actual_speed', 0)} Hz", + "quality": "Good", + "timestamp": datetime.now().strftime("%Y-%m-%d %H:%M:%S") + }, + { + "name": f"Station_{station_id}_Pump_{pump_id}_Power", + "protocol": "modbus", + "address": "200", + "data_type": "Integer", + "current_value": f"{pump_data.get('power', 0)} kW", + "quality": "Good", + "timestamp": datetime.now().strftime("%Y-%m-%d %H:%M:%S") + }, + { + "name": f"Station_{station_id}_Pump_{pump_id}_FlowRate", + "protocol": "modbus", + "address": "300", + "data_type": "Integer", + "current_value": f"{pump_data.get('flow_rate', 0)} m³/h", + "quality": "Good", + "timestamp": datetime.now().strftime("%Y-%m-%d %H:%M:%S") + }, + { + "name": f"Station_{station_id}_Pump_{pump_id}_SafetyStatus", + "protocol": "modbus", + "address": "400", + "data_type": "Integer", + "current_value": f"{pump_data.get('safety_status', 0)}", + "quality": "Good", + "timestamp": datetime.now().strftime("%Y-%m-%d %H:%M:%S") + } + ]) + + # Add OPC UA fallback signals + signals.extend(_create_fallback_signals(station_id, pump_id)) + + await modbus_client.disconnect() + else: + logger.warning("modbus_connection_failed_using_fallback") + # Fallback to mock data if Modbus connection fails + for station_id, station in stations.items(): + pumps = pumps_by_station.get(station_id, []) + for pump in pumps: + signals.extend(_create_fallback_signals(station_id, pump['pump_id'])) + + except Exception as e: + logger.error(f"error_using_real_protocol_data_using_fallback", error=str(e)) + # Fallback to mock data if any error occurs + for station_id, station in stations.items(): + pumps = pumps_by_station.get(station_id, []) + for pump in pumps: + signals.extend(_create_fallback_signals(station_id, pump['pump_id'])) # Add system status signals signals.extend([