|
12 | 12 | SensorEntityDescription, |
13 | 13 | SensorStateClass, |
14 | 14 | ) |
| 15 | +from homeassistant.const import Platform |
15 | 16 | from homeassistant.core import HomeAssistant, callback |
| 17 | +from homeassistant.helpers import entity_registry as er |
16 | 18 | from homeassistant.helpers.device_registry import DeviceEntryType, DeviceInfo |
17 | 19 | from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback |
18 | 20 | from homeassistant.helpers.update_coordinator import CoordinatorEntity |
@@ -210,36 +212,67 @@ async def async_setup_entry( |
210 | 212 |
|
211 | 213 | async_add_entities(entities) |
212 | 214 |
|
| 215 | + # Remove stale newsletter entities left over from previous runs. |
| 216 | + entity_registry = er.async_get(hass) |
| 217 | + prefix = f"{entry.unique_id}_newsletter_" |
| 218 | + active_newsletters = { |
| 219 | + newsletter_id |
| 220 | + for newsletter_id, newsletter in coordinator.data.newsletters.items() |
| 221 | + if newsletter.get("status") == "active" |
| 222 | + } |
| 223 | + for entity_entry in er.async_entries_for_config_entry( |
| 224 | + entity_registry, entry.entry_id |
| 225 | + ): |
| 226 | + if ( |
| 227 | + entity_entry.unique_id.startswith(prefix) |
| 228 | + and entity_entry.unique_id[len(prefix) :] not in active_newsletters |
| 229 | + ): |
| 230 | + entity_registry.async_remove(entity_entry.entity_id) |
| 231 | + |
213 | 232 | newsletter_added: set[str] = set() |
214 | 233 |
|
215 | 234 | @callback |
216 | | - def _async_add_newsletter_entities() -> None: |
217 | | - """Add newsletter entities when new newsletters appear.""" |
| 235 | + def _async_update_newsletter_entities() -> None: |
| 236 | + """Add new and remove stale newsletter entities.""" |
218 | 237 | nonlocal newsletter_added |
219 | 238 |
|
220 | | - new_newsletters = { |
| 239 | + active_newsletters = { |
221 | 240 | newsletter_id |
222 | 241 | for newsletter_id, newsletter in coordinator.data.newsletters.items() |
223 | 242 | if newsletter.get("status") == "active" |
224 | | - } - newsletter_added |
225 | | - |
226 | | - if not new_newsletters: |
227 | | - return |
228 | | - |
229 | | - async_add_entities( |
230 | | - GhostNewsletterSensorEntity( |
231 | | - coordinator, |
232 | | - entry, |
233 | | - newsletter_id, |
234 | | - coordinator.data.newsletters[newsletter_id].get("name", "Newsletter"), |
| 243 | + } |
| 244 | + |
| 245 | + new_newsletters = active_newsletters - newsletter_added |
| 246 | + |
| 247 | + if new_newsletters: |
| 248 | + async_add_entities( |
| 249 | + GhostNewsletterSensorEntity( |
| 250 | + coordinator, |
| 251 | + entry, |
| 252 | + newsletter_id, |
| 253 | + coordinator.data.newsletters[newsletter_id].get( |
| 254 | + "name", "Newsletter" |
| 255 | + ), |
| 256 | + ) |
| 257 | + for newsletter_id in new_newsletters |
235 | 258 | ) |
236 | | - for newsletter_id in new_newsletters |
237 | | - ) |
238 | | - newsletter_added |= new_newsletters |
239 | | - |
240 | | - _async_add_newsletter_entities() |
| 259 | + newsletter_added.update(new_newsletters) |
| 260 | + |
| 261 | + removed_newsletters = newsletter_added - active_newsletters |
| 262 | + if removed_newsletters: |
| 263 | + entity_registry = er.async_get(hass) |
| 264 | + for newsletter_id in removed_newsletters: |
| 265 | + unique_id = f"{entry.unique_id}_newsletter_{newsletter_id}" |
| 266 | + entity_id = entity_registry.async_get_entity_id( |
| 267 | + Platform.SENSOR, DOMAIN, unique_id |
| 268 | + ) |
| 269 | + if entity_id: |
| 270 | + entity_registry.async_remove(entity_id) |
| 271 | + newsletter_added -= removed_newsletters |
| 272 | + |
| 273 | + _async_update_newsletter_entities() |
241 | 274 | entry.async_on_unload( |
242 | | - coordinator.async_add_listener(_async_add_newsletter_entities) |
| 275 | + coordinator.async_add_listener(_async_update_newsletter_entities) |
243 | 276 | ) |
244 | 277 |
|
245 | 278 |
|
@@ -310,9 +343,10 @@ def _get_newsletter_by_id(self) -> dict[str, Any] | None: |
310 | 343 | @property |
311 | 344 | def available(self) -> bool: |
312 | 345 | """Return True if the entity is available.""" |
313 | | - if not super().available or self.coordinator.data is None: |
314 | | - return False |
315 | | - return self._newsletter_id in self.coordinator.data.newsletters |
| 346 | + return ( |
| 347 | + super().available |
| 348 | + and self._newsletter_id in self.coordinator.data.newsletters |
| 349 | + ) |
316 | 350 |
|
317 | 351 | @property |
318 | 352 | def native_value(self) -> int | None: |
|
0 commit comments