"""Per-enclosure temperature aggregation. Builds a compact snapshot of enclosure temperatures suitable for Home Assistant: each named SES temperature sensor plus a derived per-enclosure hotspot (the hottest reading across SES sensors *and* the drives housed in that enclosure — drive temps are usually the real hotspot signal). """ import asyncio import logging import socket from services.enclosure import discover_enclosures, get_enclosure_status, list_slots from services.smart import get_smart_data logger = logging.getLogger(__name__) def get_node_id() -> str: """Stable identifier for this monitor instance (defaults to hostname).""" import os return os.environ.get("MQTT_NODE_ID") or socket.gethostname() or "jbod-monitor" async def build_temp_snapshot() -> dict: """Collect per-enclosure temperature metrics for all enclosures.""" enclosures = discover_enclosures() async def _health(enc): if enc.get("sg_device"): return await get_enclosure_status(enc["sg_device"]) return None health_results = await asyncio.gather( *[_health(enc) for enc in enclosures], return_exceptions=True ) out_enclosures: list[dict] = [] for enc, health in zip(enclosures, health_results): if isinstance(health, Exception): logger.warning("SES health failed for %s: %s", enc["id"], health) health = None sensors: list[dict] = [] sensor_temps: list[float] = [] if isinstance(health, dict): for t in health.get("temps", []): temp = t.get("temperature_c") sensors.append({ "index": t["index"], "name": t.get("name"), "status": t.get("status", "Unknown"), "temperature_c": temp, }) if isinstance(temp, (int, float)) and temp > 0: sensor_temps.append(float(temp)) # Drive temperatures for drives housed in this enclosure. drive_temps: list[float] = [] devices = [s["device"] for s in list_slots(enc["id"]) if s.get("device")] if devices: smart_results = await asyncio.gather( *[get_smart_data(d) for d in devices], return_exceptions=True ) for res in smart_results: if isinstance(res, Exception): continue data, _hit = res temp = data.get("temperature_c") if isinstance(temp, (int, float)) and temp > 0: drive_temps.append(float(temp)) all_temps = sensor_temps + drive_temps out_enclosures.append({ "id": enc["id"], "vendor": enc.get("vendor", ""), "model": enc.get("model", ""), "hotspot_c": max(all_temps) if all_temps else None, "drive_max_c": max(drive_temps) if drive_temps else None, "drive_temp_count": len(drive_temps), "sensors": sensors, }) return {"node": get_node_id(), "enclosures": out_enclosures}