193 lines
5.9 KiB
Python
193 lines
5.9 KiB
Python
"""
|
|
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 = "calejo-postgres"
|
|
db_port: int = 5432
|
|
db_name: str = "calejo"
|
|
db_user: str = "calejo"
|
|
db_password: str = "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 = "0.0.0.0"
|
|
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() |