""" Configuration management for Calejo Control Adapter. """ from pydantic_settings import BaseSettings from typing import Optional, List from pydantic import validator import os class Settings(BaseSettings): """Application settings loaded from environment variables.""" # Database configuration db_host: str = "localhost" db_port: int = 5432 db_name: str = "calejo" db_user: str = "control_reader" db_password: str = "secure_password" db_min_connections: int = 2 db_max_connections: int = 10 # Station filter (optional) station_filter: Optional[str] = None # Security api_key: str = "your_api_key_here" tls_enabled: bool = True tls_cert_path: Optional[str] = None tls_key_path: Optional[str] = None # OPC UA opcua_enabled: bool = True opcua_host: str = "localhost" opcua_port: int = 4840 opcua_security_mode: str = "SignAndEncrypt" opcua_cert_path: Optional[str] = None opcua_key_path: Optional[str] = None # Modbus TCP modbus_enabled: bool = True modbus_host: str = "localhost" modbus_port: int = 502 modbus_unit_id: int = 1 # REST API rest_api_enabled: bool = True rest_api_host: str = "localhost" rest_api_port: int = 8080 rest_api_cors_enabled: bool = True # Safety - Watchdog watchdog_enabled: bool = True watchdog_timeout_seconds: int = 1200 # 20 minutes watchdog_check_interval_seconds: int = 60 # Check every minute # Auto-Discovery auto_discovery_enabled: bool = True auto_discovery_refresh_minutes: int = 60 # Alerts - Email alert_email_enabled: bool = True alert_email_from: str = "calejo-control@example.com" alert_email_recipients: List[str] = ["operator1@utility.it", "operator2@utility.it"] smtp_host: str = "smtp.gmail.com" smtp_port: int = 587 smtp_username: str = "calejo-control@example.com" smtp_password: str = "smtp_password" smtp_use_tls: bool = True # Alerts - SMS alert_sms_enabled: bool = True alert_sms_recipients: List[str] = ["+393401234567", "+393407654321"] twilio_account_sid: str = "your_twilio_account_sid" twilio_auth_token: str = "your_twilio_auth_token" twilio_phone_number: str = "+15551234567" # Alerts - Webhook alert_webhook_enabled: bool = True alert_webhook_url: str = "https://utility-monitoring.example.com/webhook" alert_webhook_token: str = "webhook_bearer_token" # Alerts - SCADA alert_scada_enabled: bool = True # Logging log_level: str = "INFO" log_format: str = "json" audit_log_enabled: bool = True # Application app_name: str = "Calejo Control Adapter" app_version: str = "2.0.0" environment: str = "development" # Auto-discovery settings auto_discovery_enabled: bool = True auto_discovery_refresh_minutes: int = 60 # Optimization plan management settings optimization_monitoring_enabled: bool = True optimization_refresh_seconds: int = 30 @property def database_url(self) -> str: """Generate database URL from components.""" return f"postgresql://{self.db_user}:{self.db_password}@{self.db_host}:{self.db_port}/{self.db_name}" @validator('db_port') def validate_db_port(cls, v): if not 1 <= v <= 65535: raise ValueError('Database port must be between 1 and 65535') return v @validator('opcua_port') def validate_opcua_port(cls, v): if not 1 <= v <= 65535: raise ValueError('OPC UA port must be between 1 and 65535') return v @validator('modbus_port') def validate_modbus_port(cls, v): if not 1 <= v <= 65535: raise ValueError('Modbus port must be between 1 and 65535') return v @validator('rest_api_port') def validate_rest_api_port(cls, v): if not 1 <= v <= 65535: raise ValueError('REST API port must be between 1 and 65535') return v @validator('log_level') def validate_log_level(cls, v): valid_levels = ['DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL'] if v.upper() not in valid_levels: raise ValueError(f'Log level must be one of: {valid_levels}') return v.upper() @validator('alert_email_recipients', 'alert_sms_recipients', pre=True) def parse_recipients(cls, v): if isinstance(v, str): return [recipient.strip() for recipient in v.split(',')] return v def get_sensitive_fields(self) -> List[str]: """Get list of sensitive fields for logging/masking.""" return [ 'db_password', 'api_key', 'smtp_password', 'twilio_auth_token', 'alert_webhook_token' ] def get_safe_dict(self) -> dict: """Get settings dictionary with sensitive fields masked.""" settings_dict = self.dict() for field in self.get_sensitive_fields(): if field in settings_dict and settings_dict[field]: settings_dict[field] = '***MASKED***' return settings_dict class Config: env_file = ".env" env_file_encoding = "utf-8" case_sensitive = False # Global settings instance settings = Settings()