Compare commits

..

No commits in common. "7cf7ed928b77773c34828552a62ad9b72c77135d" and "66e56eb70c22ccb82343261fc31daf274b4d8725" have entirely different histories.

2 changed files with 47 additions and 132 deletions

View File

@ -597,103 +597,6 @@ async def _generate_mock_signals(stations: Dict, pumps_by_station: Dict) -> List
return signals return signals
def _create_fallback_signals(station_id: str, pump_id: str) -> List[Dict[str, Any]]:
"""Create fallback signals when protocol servers are unavailable"""
import random
from datetime import datetime
# Generate realistic mock data
base_setpoint = random.randint(300, 450) # 30-45 Hz
actual_speed = base_setpoint + random.randint(-20, 20)
power = int(actual_speed * 2.5) # Rough power calculation
flow_rate = int(actual_speed * 10) # Rough flow calculation
temperature = random.randint(20, 35) # Normal operating temperature
return [
{
"name": f"Station_{station_id}_Pump_{pump_id}_Setpoint",
"protocol": "opcua",
"address": f"ns=2;s=Station_{station_id}.Pump_{pump_id}.Setpoint_Hz",
"data_type": "Float",
"current_value": f"{base_setpoint / 10:.1f} Hz",
"quality": "Good",
"timestamp": datetime.now().strftime("%Y-%m-%d %H:%M:%S")
},
{
"name": f"Station_{station_id}_Pump_{pump_id}_ActualSpeed",
"protocol": "opcua",
"address": f"ns=2;s=Station_{station_id}.Pump_{pump_id}.ActualSpeed_Hz",
"data_type": "Float",
"current_value": f"{actual_speed / 10:.1f} Hz",
"quality": "Good",
"timestamp": datetime.now().strftime("%Y-%m-%d %H:%M:%S")
},
{
"name": f"Station_{station_id}_Pump_{pump_id}_Power",
"protocol": "opcua",
"address": f"ns=2;s=Station_{station_id}.Pump_{pump_id}.Power_kW",
"data_type": "Float",
"current_value": f"{power / 10:.1f} kW",
"quality": "Good",
"timestamp": datetime.now().strftime("%Y-%m-%d %H:%M:%S")
},
{
"name": f"Station_{station_id}_Pump_{pump_id}_FlowRate",
"protocol": "opcua",
"address": f"ns=2;s=Station_{station_id}.Pump_{pump_id}.FlowRate_m3h",
"data_type": "Float",
"current_value": f"{flow_rate:.1f} m³/h",
"quality": "Good",
"timestamp": datetime.now().strftime("%Y-%m-%d %H:%M:%S")
},
{
"name": f"Station_{station_id}_Pump_{pump_id}_SafetyStatus",
"protocol": "opcua",
"address": f"ns=2;s=Station_{station_id}.Pump_{pump_id}.SafetyStatus",
"data_type": "String",
"current_value": "normal",
"quality": "Good",
"timestamp": datetime.now().strftime("%Y-%m-%d %H:%M:%S")
},
{
"name": f"Station_{station_id}_Pump_{pump_id}_Setpoint",
"protocol": "modbus",
"address": f"{40000 + int(pump_id[-1]) * 10 + 1}",
"data_type": "Integer",
"current_value": f"{base_setpoint} Hz (x10)",
"quality": "Good",
"timestamp": datetime.now().strftime("%Y-%m-%d %H:%M:%S")
},
{
"name": f"Station_{station_id}_Pump_{pump_id}_ActualSpeed",
"protocol": "modbus",
"address": f"{40000 + int(pump_id[-1]) * 10 + 2}",
"data_type": "Integer",
"current_value": f"{actual_speed} Hz (x10)",
"quality": "Good",
"timestamp": datetime.now().strftime("%Y-%m-%d %H:%M:%S")
},
{
"name": f"Station_{station_id}_Pump_{pump_id}_Power",
"protocol": "modbus",
"address": f"{40000 + int(pump_id[-1]) * 10 + 3}",
"data_type": "Integer",
"current_value": f"{power} kW (x10)",
"quality": "Good",
"timestamp": datetime.now().strftime("%Y-%m-%d %H:%M:%S")
},
{
"name": f"Station_{station_id}_Pump_{pump_id}_Temperature",
"protocol": "modbus",
"address": f"{40000 + int(pump_id[-1]) * 10 + 4}",
"data_type": "Integer",
"current_value": f"{temperature} °C",
"quality": "Good",
"timestamp": datetime.now().strftime("%Y-%m-%d %H:%M:%S")
}
]
# Signal Overview endpoints # Signal Overview endpoints
@dashboard_router.get("/signals") @dashboard_router.get("/signals")
async def get_signals(): async def get_signals():
@ -716,12 +619,51 @@ async def get_signals():
signals = [] signals = []
# Always use fallback signals for now to avoid protocol client issues # Check if protocol servers are enabled before trying to connect
logger.info("using_fallback_signals_for_testing") if settings.opcua_enabled or settings.modbus_enabled:
for station_id, station in stations.items(): # Try to get data from protocol servers
pumps = pumps_by_station.get(station_id, []) try:
for pump in pumps: # Initialize protocol data collector
signals.extend(_create_fallback_signals(station_id, pump['pump_id'])) from src.dashboard.protocol_clients import ProtocolDataCollector
collector = ProtocolDataCollector()
# Collect data from all pumps across all protocols
for station_id, station in stations.items():
pumps = pumps_by_station.get(station_id, [])
for pump in pumps:
pump_id = pump['pump_id']
# Get signal data from protocol servers
pump_signals = await collector.get_signal_data(station_id, pump_id)
signals.extend(pump_signals)
# Clean up connections
await collector.cleanup()
# If no signals were retrieved from protocol servers, return error
if not signals:
logger.error("no_signals_from_protocol_servers")
raise HTTPException(
status_code=503,
detail="No signals available from protocol servers. Please check server connectivity."
)
except HTTPException:
# Re-raise HTTP exceptions directly
raise
except Exception as e:
logger.error("failed_to_get_protocol_data", error=str(e))
raise HTTPException(
status_code=503,
detail=f"Unable to connect to protocol servers: {str(e)}"
)
else:
# Protocol servers are disabled, return clear error
logger.error("protocol_servers_disabled_in_production")
raise HTTPException(
status_code=503,
detail="Protocol servers are disabled in production environment. No real-time data available."
)
# Add system status signals # Add system status signals
signals.extend([ signals.extend([

View File

@ -24,13 +24,9 @@ class OPCUAClient:
try: try:
from asyncua import Client from asyncua import Client
self._client = Client(url=self.endpoint) self._client = Client(url=self.endpoint)
# Set timeout for connection await self._client.connect()
await asyncio.wait_for(self._client.connect(), timeout=5.0)
logger.info("opcua_client_connected", endpoint=self.endpoint) logger.info("opcua_client_connected", endpoint=self.endpoint)
return True return True
except asyncio.TimeoutError:
logger.error("opcua_connection_timeout", endpoint=self.endpoint)
return False
except Exception as e: except Exception as e:
logger.error("failed_to_connect_opcua", endpoint=self.endpoint, error=str(e)) logger.error("failed_to_connect_opcua", endpoint=self.endpoint, error=str(e))
return False return False
@ -49,11 +45,8 @@ class OPCUAClient:
await self.connect() await self.connect()
node = self._client.get_node(node_id) node = self._client.get_node(node_id)
value = await asyncio.wait_for(node.read_value(), timeout=3.0) value = await node.read_value()
return value return value
except asyncio.TimeoutError:
logger.error("opcua_read_timeout", node_id=node_id)
return None
except Exception as e: except Exception as e:
logger.error("failed_to_read_opcua_node", node_id=node_id, error=str(e)) logger.error("failed_to_read_opcua_node", node_id=node_id, error=str(e))
return None return None
@ -122,17 +115,7 @@ class ModbusClient:
if not self._client or not self._client.is_socket_open(): if not self._client or not self._client.is_socket_open():
self.connect() self.connect()
# Set timeout for the read operation
if hasattr(self._client, 'timeout'):
original_timeout = self._client.timeout
self._client.timeout = 2.0 # 2 second timeout
result = self._client.read_holding_registers(address, count) result = self._client.read_holding_registers(address, count)
# Restore original timeout
if hasattr(self._client, 'timeout'):
self._client.timeout = original_timeout
if not result.isError(): if not result.isError():
return result.registers return result.registers
else: else:
@ -148,17 +131,7 @@ class ModbusClient:
if not self._client or not self._client.is_socket_open(): if not self._client or not self._client.is_socket_open():
self.connect() self.connect()
# Set timeout for the read operation
if hasattr(self._client, 'timeout'):
original_timeout = self._client.timeout
self._client.timeout = 2.0 # 2 second timeout
result = self._client.read_input_registers(address, count) result = self._client.read_input_registers(address, count)
# Restore original timeout
if hasattr(self._client, 'timeout'):
self._client.timeout = original_timeout
if not result.isError(): if not result.isError():
return result.registers return result.registers
else: else: