137 lines
4.3 KiB
Python
137 lines
4.3 KiB
Python
|
|
#!/usr/bin/env python3
|
||
|
|
"""
|
||
|
|
Calejo Control Adapter - Main Application
|
||
|
|
|
||
|
|
Multi-protocol integration adapter for municipal wastewater pump stations
|
||
|
|
with comprehensive safety and security framework.
|
||
|
|
"""
|
||
|
|
|
||
|
|
import asyncio
|
||
|
|
import signal
|
||
|
|
import structlog
|
||
|
|
from typing import Dict, Any
|
||
|
|
|
||
|
|
from config.settings import Settings
|
||
|
|
from src.database.client import DatabaseClient
|
||
|
|
from src.core.auto_discovery import AutoDiscovery
|
||
|
|
from src.core.security import SecurityManager
|
||
|
|
from src.core.safety import SafetyLimitEnforcer
|
||
|
|
from src.core.plan_to_setpoint import PlanToSetpointEngine
|
||
|
|
from src.monitoring.watchdog import DatabaseWatchdog
|
||
|
|
from src.monitoring.alerts import AlertManager
|
||
|
|
from src.protocols.opc_ua_server import OPCUAServer
|
||
|
|
from src.protocols.modbus_server import ModbusServer
|
||
|
|
from src.protocols.rest_api import RESTAPIServer
|
||
|
|
|
||
|
|
logger = structlog.get_logger()
|
||
|
|
|
||
|
|
|
||
|
|
class CalejoControlAdapter:
|
||
|
|
"""Main application class for Calejo Control Adapter."""
|
||
|
|
|
||
|
|
def __init__(self, settings: Settings):
|
||
|
|
self.settings = settings
|
||
|
|
self.running = False
|
||
|
|
|
||
|
|
# Initialize components
|
||
|
|
self.db_client = DatabaseClient(settings.database_url)
|
||
|
|
self.auto_discovery = AutoDiscovery(self.db_client)
|
||
|
|
self.security_manager = SecurityManager()
|
||
|
|
self.safety_enforcer = SafetyLimitEnforcer(self.db_client)
|
||
|
|
self.plan_engine = PlanToSetpointEngine(self.db_client, self.safety_enforcer)
|
||
|
|
self.alert_manager = AlertManager(settings)
|
||
|
|
self.watchdog = DatabaseWatchdog(
|
||
|
|
self.db_client, self.alert_manager, settings.safety_timeout_seconds
|
||
|
|
)
|
||
|
|
|
||
|
|
# Protocol servers
|
||
|
|
self.opc_ua_server = OPCUAServer(settings.opc_ua_endpoint, self.plan_engine)
|
||
|
|
self.modbus_server = ModbusServer(settings.modbus_port, self.plan_engine)
|
||
|
|
self.rest_api = RESTAPIServer(settings.rest_api_port, self.plan_engine)
|
||
|
|
|
||
|
|
async def start(self):
|
||
|
|
"""Start the Calejo Control Adapter."""
|
||
|
|
logger.info("starting_calejo_control_adapter", version="2.0.0")
|
||
|
|
|
||
|
|
try:
|
||
|
|
# Connect to database
|
||
|
|
await self.db_client.connect()
|
||
|
|
|
||
|
|
# Load safety limits
|
||
|
|
await self.safety_enforcer.load_safety_limits()
|
||
|
|
|
||
|
|
# Auto-discover pump stations and pumps
|
||
|
|
await self.auto_discovery.discover()
|
||
|
|
|
||
|
|
# Start protocol servers
|
||
|
|
await asyncio.gather(
|
||
|
|
self.opc_ua_server.start(),
|
||
|
|
self.modbus_server.start(),
|
||
|
|
self.rest_api.start(),
|
||
|
|
)
|
||
|
|
|
||
|
|
# Start monitoring
|
||
|
|
await self.watchdog.start()
|
||
|
|
|
||
|
|
self.running = True
|
||
|
|
logger.info("calejo_control_adapter_started")
|
||
|
|
|
||
|
|
# Keep application running
|
||
|
|
while self.running:
|
||
|
|
await asyncio.sleep(1)
|
||
|
|
|
||
|
|
except Exception as e:
|
||
|
|
logger.error("failed_to_start_adapter", error=str(e))
|
||
|
|
await self.stop()
|
||
|
|
raise
|
||
|
|
|
||
|
|
async def stop(self):
|
||
|
|
"""Stop the Calejo Control Adapter gracefully."""
|
||
|
|
logger.info("stopping_calejo_control_adapter")
|
||
|
|
self.running = False
|
||
|
|
|
||
|
|
# Stop protocol servers
|
||
|
|
await asyncio.gather(
|
||
|
|
self.opc_ua_server.stop(),
|
||
|
|
self.modbus_server.stop(),
|
||
|
|
self.rest_api.stop(),
|
||
|
|
return_exceptions=True
|
||
|
|
)
|
||
|
|
|
||
|
|
# Close database connection
|
||
|
|
await self.db_client.disconnect()
|
||
|
|
|
||
|
|
logger.info("calejo_control_adapter_stopped")
|
||
|
|
|
||
|
|
|
||
|
|
def handle_shutdown(signum, frame):
|
||
|
|
"""Handle shutdown signals gracefully."""
|
||
|
|
logger.info("received_shutdown_signal", signal=signum)
|
||
|
|
# Signal handling will be implemented in the async context
|
||
|
|
|
||
|
|
|
||
|
|
async def main():
|
||
|
|
"""Main application entry point."""
|
||
|
|
# Load settings
|
||
|
|
settings = Settings()
|
||
|
|
|
||
|
|
# Set up signal handlers
|
||
|
|
signal.signal(signal.SIGINT, handle_shutdown)
|
||
|
|
signal.signal(signal.SIGTERM, handle_shutdown)
|
||
|
|
|
||
|
|
# Create and start adapter
|
||
|
|
adapter = CalejoControlAdapter(settings)
|
||
|
|
|
||
|
|
try:
|
||
|
|
await adapter.start()
|
||
|
|
except KeyboardInterrupt:
|
||
|
|
logger.info("keyboard_interrupt_received")
|
||
|
|
except Exception as e:
|
||
|
|
logger.error("unexpected_error", error=str(e))
|
||
|
|
raise
|
||
|
|
finally:
|
||
|
|
await adapter.stop()
|
||
|
|
|
||
|
|
|
||
|
|
if __name__ == "__main__":
|
||
|
|
asyncio.run(main())
|