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__) SCAN_INTERVAL = timedelta(seconds=15) async def async_setup_entry(hass, entry, async_add_entities): """Add sensors for WhatsApp accounts, live status, and a global broadcast sensor.""" # 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, ) try: await coordinator.async_config_entry_first_refresh() except UpdateFailed: _LOGGER.warning("Erster Status-Abruf fehlgeschlagen. Add-on läuft eventuell noch an.") # Jeder Account bekommt immer seine eigene Entität entities = [WhatsAppAccountEntity(entry)] # Globale Entitäten (Status & Broadcast) NUR EINMALIG für die gesamte Integration anlegen if not hass.data[DOMAIN].get("global_entities_registered"): entities.append(WhatsAppStatusSensor(coordinator)) entities.append(WhatsAppBroadcastEntity()) hass.data[DOMAIN]["global_entities_registered"] = True async_add_entities(entities, True) class WhatsAppAccountEntity(SensorEntity): """Individual Account (e.g., Rene, Work).""" def __init__(self, entry): self._entry = entry self._attr_name = f"WhatsApp {entry.title}" self._attr_unique_id = f"{entry.entry_id}_status" self._attr_icon = "mdi:whatsapp" self._attr_extra_state_attributes = { "phone_number": entry.data.get("phone_number"), "is_broadcast": False } @property def state(self): return "Ready" @property def device_info(self) -> DeviceInfo: """Ordnet diesen Sensor seinem spezifischen Personen-Gerät zu.""" return DeviceInfo( identifiers={(DOMAIN, self._entry.entry_id)}, ) class WhatsAppBroadcastEntity(SensorEntity): """Virtual 'All Accounts' Entity, geordnet unter dem zentralen Hub.""" def __init__(self): self._attr_name = "WhatsApp Broadcast (All)" self._attr_unique_id = "whatsapp_bridge_broadcast_all" self._attr_icon = "mdi:whatsapp-arrow-up" self._attr_extra_state_attributes = { "is_broadcast": True } @property def state(self): return "Global" @property def device_info(self) -> DeviceInfo: """Ordnet diese Entität dem permanenten, zentralen Hub-Gerät zu.""" return DeviceInfo( identifiers={(DOMAIN, "global_bridge_hub")}, ) class WhatsAppStatusSensor(SensorEntity): """Echter Live-Status-Sensor, geordnet unter dem zentralen Hub.""" def __init__(self, coordinator): self.coordinator = coordinator self._attr_name = "WhatsApp Bridge Status" self._attr_unique_id = "whatsapp_bridge_live_status_global" 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 diese Entität dem permanenten, zentralen Hub-Gerät zu.""" return DeviceInfo( identifiers={(DOMAIN, "global_bridge_hub")}, ) 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) )