Files
Whatsapp-Bridge-Integration/custom_components/whatsapp_bridge_integration/sensor.py

162 lines
5.1 KiB
Python

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, 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,
)
# 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):
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 dem Hauptgerät zu."""
return DeviceInfo(
identifiers={(DOMAIN, "general_gateway")},
)
class WhatsAppBroadcastEntity(SensorEntity):
"""Virtual 'All Accounts' Entity."""
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 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)
)