125 lines
3.8 KiB
Python
125 lines
3.8 KiB
Python
"""Configuration loading functions."""
|
|
|
|
from pathlib import Path
|
|
|
|
import yaml
|
|
|
|
from config.schema import (
|
|
BridgeConfig,
|
|
DeviceConfig,
|
|
DeviceStatusConfig,
|
|
EnvOverrideSettings,
|
|
EventQueueConfig,
|
|
LoggingConfig,
|
|
MQTTConfig,
|
|
OdooConfig,
|
|
SessionConfig,
|
|
)
|
|
from exceptions import ConfigurationError
|
|
|
|
|
|
def _apply_environment_overrides(mqtt_data: dict, odoo_data: dict) -> tuple[dict, dict]:
|
|
"""Apply environment variable overrides for MQTT and Odoo settings."""
|
|
env = EnvOverrideSettings()
|
|
|
|
mqtt_overrides = {
|
|
"broker": env.mqtt_broker,
|
|
"port": env.mqtt_port,
|
|
"username": env.mqtt_username,
|
|
"password": env.mqtt_password,
|
|
"client_id": env.mqtt_client_id,
|
|
"keepalive": env.mqtt_keepalive,
|
|
"use_tls": env.mqtt_use_tls,
|
|
}
|
|
odoo_overrides = {
|
|
"base_url": env.odoo_base_url,
|
|
"database": env.odoo_database,
|
|
"username": env.odoo_username,
|
|
"api_key": env.odoo_api_key,
|
|
}
|
|
|
|
merged_mqtt = {**mqtt_data, **{key: value for key, value in mqtt_overrides.items() if value is not None}}
|
|
merged_odoo = {**odoo_data, **{key: value for key, value in odoo_overrides.items() if value is not None}}
|
|
|
|
return merged_mqtt, merged_odoo
|
|
|
|
|
|
def load_config(config_path: str = "config.yaml") -> BridgeConfig:
|
|
"""Load configuration from YAML file.
|
|
|
|
Resolution order:
|
|
1. YAML values from ``config_path``
|
|
2. Environment variable overrides (via ``EnvOverrideSettings``)
|
|
3. Pydantic default values from schema models
|
|
"""
|
|
path = Path(config_path)
|
|
if not path.exists():
|
|
raise ConfigurationError(
|
|
f"Config file not found: {config_path}",
|
|
path=str(path.absolute()),
|
|
)
|
|
|
|
with open(path) as f:
|
|
data = yaml.safe_load(f)
|
|
|
|
mqtt_data, odoo_data = _apply_environment_overrides(data["mqtt"], data.get("odoo", {}))
|
|
|
|
mqtt_config = MQTTConfig(**mqtt_data)
|
|
odoo_config = OdooConfig(**odoo_data)
|
|
logging_config = LoggingConfig(**data.get("logging", {}))
|
|
event_queue_config = EventQueueConfig(**data.get("event_queue", {}))
|
|
device_status_config = DeviceStatusConfig(**data.get("device_status", {}))
|
|
|
|
devices = []
|
|
for dev_data in data.get("devices", []):
|
|
session_cfg = SessionConfig(**dev_data["session_config"])
|
|
device = DeviceConfig(
|
|
device_id=dev_data["device_id"],
|
|
mqtt_topic=dev_data["mqtt_topic"],
|
|
parser_type=dev_data["parser_type"],
|
|
machine_name=dev_data["machine_name"],
|
|
session_config=session_cfg,
|
|
)
|
|
devices.append(device)
|
|
|
|
return BridgeConfig(
|
|
mqtt=mqtt_config,
|
|
odoo=odoo_config,
|
|
logging=logging_config,
|
|
event_queue=event_queue_config,
|
|
device_status=device_status_config,
|
|
devices=devices,
|
|
)
|
|
|
|
|
|
def load_devices_from_config(config_path: str) -> list[DeviceConfig]:
|
|
"""Load only devices from a config file (for config-active.yaml)."""
|
|
path = Path(config_path)
|
|
if not path.exists():
|
|
raise ConfigurationError(
|
|
f"Config file not found: {config_path}",
|
|
path=str(path.absolute()),
|
|
)
|
|
|
|
with open(path) as f:
|
|
data = yaml.safe_load(f)
|
|
|
|
devices = []
|
|
for dev_data in data.get("devices", []):
|
|
session_data = dev_data["session_config"].copy()
|
|
# Add default strategy if not present (pushed configs don't include it)
|
|
if "strategy" not in session_data:
|
|
session_data["strategy"] = "power_threshold"
|
|
|
|
session_cfg = SessionConfig(**session_data)
|
|
device = DeviceConfig(
|
|
device_id=dev_data["device_id"],
|
|
mqtt_topic=dev_data["mqtt_topic"],
|
|
parser_type=dev_data["parser_type"],
|
|
machine_name=dev_data["machine_name"],
|
|
session_config=session_cfg,
|
|
)
|
|
devices.append(device)
|
|
|
|
return devices
|