#!/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())