Files
homelab-infra/apps/dashboard/backend/app/clients/home_assistant_client.py
T

84 lines
3.1 KiB
Python

from __future__ import annotations
from datetime import datetime, timezone
import logging
from time import perf_counter
from app.clients.base import BaseHTTPClient
from app.config import Settings
from app.models.sources import HomeAssistantSnapshot
logger = logging.getLogger(__name__)
class HomeAssistantClient(BaseHTTPClient):
def __init__(self, settings: Settings) -> None:
super().__init__(settings, "home-assistant", settings.home_assistant_base_url)
async def fetch_status(self) -> HomeAssistantSnapshot:
snapshot = HomeAssistantSnapshot()
if not self.base_url or not self.settings.home_assistant_token:
logger.info("home assistant skipped: base URL or token missing")
return snapshot
headers = {
"Authorization": f"Bearer {self.settings.home_assistant_token}",
"Content-Type": "application/json",
}
started_at = perf_counter()
api_info = await self._request_json("GET", "/api/", headers=headers)
logger.info("home assistant raw /api/ response: %s", api_info)
elapsed_ms = int((perf_counter() - started_at) * 1000)
config = await self._request_json("GET", "/api/config", headers=headers)
logger.info("home assistant raw /api/config response: %s", config)
version = None
if isinstance(config, dict):
version = config.get("version")
# Fetch entity states for widget counts
lights_on = 0
lights_total = 0
climate_active = 0
doors_open = 0
alerts = 0
try:
states = await self._request_json("GET", "/api/states", headers=headers)
if isinstance(states, list):
for entity in states:
eid = entity.get("entity_id", "")
state = entity.get("state", "")
if eid.startswith("light."):
lights_total += 1
if state == "on":
lights_on += 1
elif eid.startswith("climate."):
if state not in ("off", "unavailable", "unknown"):
climate_active += 1
elif eid.startswith("binary_sensor.") and "door" in eid:
if state == "on":
doors_open += 1
elif eid.startswith("persistent_notification."):
if state == "notifying":
alerts += 1
except Exception as exc:
logger.warning("home assistant fetch states failed: %s", exc)
normalized = HomeAssistantSnapshot(
status="online",
version=str(version) if version else None,
response_time_ms=elapsed_ms,
last_checked=datetime.now(timezone.utc),
lights_on=lights_on,
lights_total=lights_total,
climate_active=climate_active,
doors_open=doors_open,
alerts=alerts,
)
logger.info("home assistant normalized snapshot: %s", normalized.model_dump())
return normalized