Files
pv-controller/src/pv_controller/config.py
2025-12-03 18:09:25 +01:00

78 lines
1.9 KiB
Python

import os
import re
from pathlib import Path
from typing import List, Optional
from pydantic import BaseModel, Field, field_validator
import yaml
from loguru import logger
class RegisterConfig(BaseModel):
"""Modbus Register Configuration"""
address: int
attribute: str
name: str
unit: str
register_type: str
data_type: str
adaptor: str
class OutputConfig(BaseModel):
"""Output Configuration for Modbus Devices"""
name: str
enabled: bool = Field(default=True)
publish_topic: str
slave_id: int
registers: List[RegisterConfig]
class MqttConfig(BaseModel):
"""MQTT Configuration"""
broker: str
port: int
publish_period: int
class ModbusConfig(BaseModel):
"""Modbus Configuration"""
gateway: str
class Config(BaseModel):
"""Main Configuration"""
mqtt: MqttConfig
modbus: ModbusConfig
output: List[OutputConfig]
@classmethod
def load_from_file(cls, config_path: Optional[str] = None) -> 'Config':
"""
Load configuration from YAML file with environment variable substitution.
Args:
config_path: Path to config file. If None, uses CFG_FILE environment variable.
Returns:
Config instance
"""
if config_path is None:
config_path = os.getenv('CFG_FILE')
if config_path is None:
raise ValueError("Config path not provided and CFG_FILE environment variable not set")
config_file = Path(config_path)
if not config_file.exists():
raise FileNotFoundError(f"Configuration file not found: {config_path}")
# Read YAML file
with open(config_file, 'r', encoding='utf-8') as f:
yaml_content = f.read()
# Parse YAML
config_dict = yaml.safe_load(yaml_content)
logger.info(f"Configuration loaded from: {config_path}")
return cls(**config_dict)