CalejoControl/config/settings.py

193 lines
6.0 KiB
Python
Raw Normal View History

"""
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
db_query_timeout: int = 30
# 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
# JWT Authentication
jwt_secret_key: str = "your-secret-key-change-in-production"
jwt_token_expire_minutes: int = 60
jwt_algorithm: str = "HS256"
# Password policy
password_min_length: int = 8
password_require_uppercase: bool = True
password_require_lowercase: bool = True
password_require_numbers: bool = True
password_require_special: bool = True
# 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
# Health Monitoring
health_monitor_port: int = 9090
# 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('health_monitor_port')
def validate_health_monitor_port(cls, v):
if not 1 <= v <= 65535:
raise ValueError('Health monitor 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()