zwei Lampen und Test-Werkzeug
This commit is contained in:
@@ -43,6 +43,11 @@ def load_config(config_path: Path) -> dict[str, Any]:
|
||||
with open(config_path, "r") as f:
|
||||
config = yaml.safe_load(f)
|
||||
|
||||
# Normalize device entries: accept both 'id' and 'device_id', use 'device_id' internally
|
||||
devices = config.get("devices", [])
|
||||
for device in devices:
|
||||
device["device_id"] = device.pop("device_id", device.pop("id", None))
|
||||
|
||||
logger.info(f"Loaded configuration from {config_path}")
|
||||
return config
|
||||
|
||||
@@ -56,16 +61,33 @@ def validate_devices(devices: list[dict[str, Any]]) -> None:
|
||||
Raises:
|
||||
ValueError: If device configuration is invalid
|
||||
"""
|
||||
required_fields = ["device_id", "type", "cap_version", "technology"]
|
||||
|
||||
for device in devices:
|
||||
if "id" not in device:
|
||||
raise ValueError(f"Device missing 'id': {device}")
|
||||
if "type" not in device:
|
||||
raise ValueError(f"Device {device['id']} missing 'type'")
|
||||
# Check for device_id
|
||||
if "device_id" not in device or device["device_id"] is None:
|
||||
raise ValueError(f"Device entry requires 'id' or 'device_id': {device}")
|
||||
|
||||
device_id = device["device_id"]
|
||||
|
||||
# Check required top-level fields
|
||||
for field in required_fields:
|
||||
if field not in device:
|
||||
raise ValueError(f"Device {device_id} missing '{field}'")
|
||||
|
||||
# Check topics structure
|
||||
if "topics" not in device:
|
||||
raise ValueError(f"Device {device['id']} missing 'topics'")
|
||||
if "set" not in device["topics"] or "state" not in device["topics"]:
|
||||
raise ValueError(f"Device {device['id']} missing 'topics.set' or 'topics.state'")
|
||||
logger.info(f"Validated {len(devices)} device(s)")
|
||||
raise ValueError(f"Device {device_id} missing 'topics'")
|
||||
|
||||
if "set" not in device["topics"]:
|
||||
raise ValueError(f"Device {device_id} missing 'topics.set'")
|
||||
|
||||
if "state" not in device["topics"]:
|
||||
raise ValueError(f"Device {device_id} missing 'topics.state'")
|
||||
|
||||
# Log loaded devices
|
||||
device_ids = [d["device_id"] for d in devices]
|
||||
logger.info(f"Loaded {len(devices)} device(s): {', '.join(device_ids)}")
|
||||
|
||||
|
||||
async def get_redis_client(redis_url: str, max_retries: int = 5) -> aioredis.Redis:
|
||||
@@ -172,7 +194,7 @@ async def mqtt_worker(config: dict[str, Any], redis_client: aioredis.Redis) -> N
|
||||
redis_config = config.get("redis", {})
|
||||
redis_channel = redis_config.get("channel", "ui:updates")
|
||||
|
||||
devices = {d["id"]: d for d in config.get("devices", [])}
|
||||
devices = {d["device_id"]: d for d in config.get("devices", [])}
|
||||
|
||||
retry_delay = 1
|
||||
max_retry_delay = 60
|
||||
@@ -191,7 +213,7 @@ async def mqtt_worker(config: dict[str, Any], redis_client: aioredis.Redis) -> N
|
||||
|
||||
# Subscribe to abstract SET topics for all devices
|
||||
for device in devices.values():
|
||||
abstract_set_topic = f"home/{device['type']}/{device['id']}/set"
|
||||
abstract_set_topic = f"home/{device['type']}/{device['device_id']}/set"
|
||||
await client.subscribe(abstract_set_topic)
|
||||
logger.info(f"Subscribed to abstract SET: {abstract_set_topic}")
|
||||
|
||||
|
||||
Reference in New Issue
Block a user