12 Commits
0.2.1 ... main

4 changed files with 66 additions and 10 deletions

View File

@@ -1,8 +1,21 @@
# CHANGELOG - Whatsapp Bridge Integration
## Release 0.2.4 - 2026-06-15
- **Fix:** Resolved a `TypeError` in `async_get_or_create()` caused by stricter Home Assistant Core requirements demanding a `config_entry_id` for all device registry entries.
- **Architecture Refinement:** The global "WhatsApp Bridge Hub" now utilizes a shared multi-entry architecture. It dynamically links to active configurations under a static identifier, ensuring the hub remains a single, non-duplicated entity that survives individual account deletions.
## Release 0.2.3 - 2026-06-15
- **New (Orphaned Devices Cleaner):** Added an automatic database cleanup utility. On startup, the integration now automatically identifies and removes orphaned or "ghost" devices left behind by previous configuration changes or older versions.
- **Fix:** Decoupled the central "WhatsApp Bridge Hub" device from specific config entry bindings. The Hub is now persistent and indestructible, preventing global entities (Broadcast and Live Status) from disappearing when individual user profiles are deleted or re-added.
## Release 0.2.2 - 2026-06-15
- **Architecture Change:** Introduced a dedicated "WhatsApp Bridge Hub" device. This central device acts as a single point of reference for global components, preventing UI clutter.
- **Fix:** Moved the global live status sensor and the virtual broadcast entity to the new WhatsApp Bridge Hub device. This ensures they remain fully visible and accessible across the Home Assistant UI, automations, and service calls without being duplicated across individual user accounts.
- **Improvement:** Maintained isolated, clean individual devices for each configured account profile.
## Release 0.2.1 - 2026-06-15
- **Fix:** Resolved device assignment duplication. Instead of a rigid global gateway card duplicating across all account tabs, a distinct and separate Home Assistant device is now generated for each configured account (*Larissa, Rene, Work*).
- **Fix:** Globalized the live status sensor and the broadcast entity. They are now instantiated exactly once for the entire integration (rather than incorrectly duplicating per account) and exist as free entities without device assignment to maintain a clean UI layout.
- **Fix:** Resolved device assignment duplication where a single global gateway card duplicated across all account tabs.
- **Fix:** Globalized the live status sensor and the broadcast entity to instantiate exactly once for the entire integration rather than incorrectly duplicating per account.
- **Optimization:** Code refactoring within `sensor.py` to prevent entity duplication when utilizing multiple profiles.
## Release 0.2.0 - 2026-06-15

View File

@@ -9,20 +9,49 @@ async def async_setup(hass: HomeAssistant, config: dict):
return True
async def async_setup_entry(hass: HomeAssistant, entry):
"""Set up entry, create specific contact device and forward to sensor platform."""
# Lege die Daten im hass-Objekt ab
"""Set up entry, create devices, and clean up old orphaned devices."""
hass.data.setdefault(DOMAIN, {})
hass.data[DOMAIN][entry.entry_id] = entry.data
# 1. Eigenes Gerät SPEZIFISCH für diesen Account/Kontakt anlegen
device_registry = dr.async_get(hass)
# 1. Automatisches Aufräumen von alten Geister-Geräten
active_entry_ids = set(hass.config_entries.async_entries(DOMAIN))
active_ids = {e.entry_id for e in active_entry_ids}
# Durchsuche die HA-Datenbank nach Geräten unserer Integration
devices_to_clean = [
dev for dev in device_registry.devices.values()
if any(identifier[0] == DOMAIN for identifier in dev.identifiers)
]
for device in devices_to_clean:
# Falls ein Gerät zu einem gelöschten Config Entry gehört -> Löschen!
# Der globale Hub ("global_bridge_hub") wird ignoriert und bleibt erhalten.
for config_id in device.config_entries:
if config_id not in active_ids and not any(idx == "global_bridge_hub" for _, idx in device.identifiers):
_LOGGER.info(f"Entferne verwaistes WhatsApp-Gerät: {device.name}")
device_registry.async_remove_device(device.id)
# 2. Eigenes Gerät SPEZIFISCH für dieses aktive Konto anlegen
device_registry.async_get_or_create(
config_entry_id=entry.entry_id,
identifiers={(DOMAIN, entry.entry_id)}, # Einzigartig pro Eintrag
identifiers={(DOMAIN, entry.entry_id)},
name=f"WhatsApp {entry.title}",
manufacturer="Bahmcloud",
model="Kontakt-Endpunkt",
sw_version="0.2.1",
sw_version="0.2.4",
)
# 3. Zentralen System-Hub anlegen mit erzwungener config_entry_id Bindung (HA Core Anforderung)
# Nutzt Multi-Entry-Zusammenführung über den fixen "global_bridge_hub" Identifier.
device_registry.async_get_or_create(
config_entry_id=entry.entry_id,
identifiers={(DOMAIN, "global_bridge_hub")},
name="WhatsApp Bridge Hub",
manufacturer="Bahmcloud",
model="Bridge Server",
sw_version="0.2.4",
)
# Forward the setup to the sensor platform to create entities

View File

@@ -4,7 +4,7 @@
"documentation": "https://git.bahmcloud.de/bahmcloud/Whatsapp-Bridge-Integration",
"dependencies": [],
"codeowners": ["@bahmcloud"],
"version": "0.2.1",
"version": "0.2.4",
"iot_class": "local_polling",
"config_flow": true
}

View File

@@ -78,7 +78,7 @@ class WhatsAppAccountEntity(SensorEntity):
class WhatsAppBroadcastEntity(SensorEntity):
"""Virtual 'All Accounts' Entity (Global, keinem spezifischen Gerät zugeordnet)."""
"""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"
@@ -91,9 +91,16 @@ class WhatsAppBroadcastEntity(SensorEntity):
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 (Global, keinem spezifischen Gerät zugeordnet)."""
"""Echter Live-Status-Sensor, geordnet unter dem zentralen Hub."""
def __init__(self, coordinator):
self.coordinator = coordinator
@@ -136,6 +143,13 @@ class WhatsAppStatusSensor(SensorEntity):
}
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(