diff --git a/custom_components/whatsapp_bridge_integration/sensor.py b/custom_components/whatsapp_bridge_integration/sensor.py index c7bf63f..758f8ca 100644 --- a/custom_components/whatsapp_bridge_integration/sensor.py +++ b/custom_components/whatsapp_bridge_integration/sensor.py @@ -1,18 +1,62 @@ +import logging +import async_timeout +import aiohttp +from datetime import timedelta + from homeassistant.components.sensor import SensorEntity +from homeassistant.helpers.entity import DeviceInfo +from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed from .const import DOMAIN +_LOGGER = logging.getLogger(__name__) + +# Polling-Intervall (15 Sekunden) +SCAN_INTERVAL = timedelta(seconds=15) + async def async_setup_entry(hass, entry, async_add_entities): - """Add sensors for WhatsApp accounts and a global broadcast sensor.""" - entities = [WhatsAppAccountEntity(entry)] + """Add sensors for WhatsApp accounts, live status, and a global broadcast sensor.""" - # Wir prüfen, ob die Broadcast-Entität schon existiert - # Falls nicht, legen wir sie einmalig an + # Coordinator für den echten Live-Status vom Add-on einrichten + async def _async_update_data(): + url = "http://866fd2eb-whatsapp-bridge:3000/api/status" + async with aiohttp.ClientSession() as session: + try: + async with async_timeout.timeout(5): + async with session.get(url) as response: + if response.status != 200: + raise UpdateFailed(f"API meldet Fehler {response.status}") + return await response.json() + except Exception as err: + raise UpdateFailed(f"Add-on nicht erreichbar: {err}") + + coordinator = DataUpdateCoordinator( + hass, + _LOGGER, + name="whatsapp_bridge_status", + update_method=_async_update_data, + update_interval=SCAN_INTERVAL, + ) + + # Ersten Abruf vor dem Erstellen der Entitäten erzwingen + try: + await coordinator.async_config_entry_first_refresh() + except UpdateFailed: + _LOGGER.warning("Erster Status-Abruf fehlgeschlagen. Add-on läuft eventuell noch an.") + + # Basis-Entitäten: Account-Sensor und der neue Live-Status-Sensor + entities = [ + WhatsAppAccountEntity(entry), + WhatsAppStatusSensor(coordinator, entry) + ] + + # Prüfen, ob die Broadcast-Entität schon existiert if not hass.data[DOMAIN].get("broadcast_registered"): entities.append(WhatsAppBroadcastEntity()) hass.data[DOMAIN]["broadcast_registered"] = True async_add_entities(entities, True) + class WhatsAppAccountEntity(SensorEntity): """Individual Account (e.g., Rene, Work).""" def __init__(self, entry): @@ -29,6 +73,14 @@ class WhatsAppAccountEntity(SensorEntity): def state(self): return "Ready" + @property + def device_info(self) -> DeviceInfo: + """Ordnet diesen Sensor dem Hauptgerät zu.""" + return DeviceInfo( + identifiers={(DOMAIN, "general_gateway")}, + ) + + class WhatsAppBroadcastEntity(SensorEntity): """Virtual 'All Accounts' Entity.""" def __init__(self): @@ -41,4 +93,70 @@ class WhatsAppBroadcastEntity(SensorEntity): @property def state(self): - return "Global" \ No newline at end of file + return "Global" + + @property + def device_info(self) -> DeviceInfo: + """Ordnet diesen Sensor dem Hauptgerät zu.""" + return DeviceInfo( + identifiers={(DOMAIN, "general_gateway")}, + ) + + +class WhatsAppStatusSensor(SensorEntity): + """Echter Live-Status-Sensor, gekoppelt an die Add-on API.""" + + def __init__(self, coordinator, entry): + self.coordinator = coordinator + self._entry = entry + self._attr_name = "WhatsApp Bridge Status" + self._attr_unique_id = f"{entry.entry_id}_bridge_live_status" + self._attr_icon = "mdi:whatsapp" + + @property + def should_poll(self) -> bool: + return False + + @property + def available(self) -> bool: + return self.coordinator.last_update_success + + @property + def state(self): + """Gibt den dynamischen Status aus der Add-on API zurück.""" + data = self.coordinator.data + if not data: + return "OFFLINE" + + if data.get("isReady"): + return "CONNECTED" + elif data.get("hasQr"): + return "WAITING_FOR_SCAN" + elif data.get("isInitializing"): + return "INITIALIZING" + + return "UNKNOWN" + + @property + def extra_state_attributes(self): + """Zusätzliche Attribute für erweitertes Debugging.""" + data = self.coordinator.data + if data: + return { + "client_state": data.get("clientState", "UNKNOWN"), + "has_qr_code": data.get("hasQr", False) + } + return {} + + @property + def device_info(self) -> DeviceInfo: + """Ordnet diesen Sensor dem Hauptgerät zu.""" + return DeviceInfo( + identifiers={(DOMAIN, "general_gateway")}, + ) + + async def async_added_to_hass(self): + """Registrieren beim Live-Coordinator.""" + self.async_on_remove( + self.coordinator.async_add_listener(self.async_write_ha_state) + ) \ No newline at end of file