Compare commits
No commits in common. "7cf7ed928b77773c34828552a62ad9b72c77135d" and "66e56eb70c22ccb82343261fc31daf274b4d8725" have entirely different histories.
7cf7ed928b
...
66e56eb70c
|
|
@ -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([
|
||||||
|
|
|
||||||
|
|
@ -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:
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue