Skip to content

Commit 0b97afc

Browse files
committed
Add rework from #67912 (#1)
* Move notify serviceupdater to Mixins * Move tag discovery handler to Mixins * fix tests
1 parent e10f824 commit 0b97afc

File tree

4 files changed

+198
-241
lines changed

4 files changed

+198
-241
lines changed

homeassistant/components/mqtt/mixins.py

Lines changed: 108 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
device_registry as dr,
3232
entity_registry as er,
3333
)
34+
from homeassistant.helpers.device_registry import EVENT_DEVICE_REGISTRY_UPDATED
3435
from homeassistant.helpers.dispatcher import (
3536
async_dispatcher_connect,
3637
async_dispatcher_send,
@@ -44,7 +45,7 @@
4445
)
4546
from homeassistant.helpers.entity_platform import AddEntitiesCallback
4647
from homeassistant.helpers.reload import async_setup_reload_service
47-
from homeassistant.helpers.typing import ConfigType
48+
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
4849

4950
from . import (
5051
DATA_MQTT,
@@ -54,6 +55,7 @@
5455
debug_info,
5556
subscription,
5657
)
58+
from ..mqtt import publish
5759
from .const import (
5860
ATTR_DISCOVERY_HASH,
5961
ATTR_DISCOVERY_PAYLOAD,
@@ -520,8 +522,112 @@ async def cleanup_device_registry(
520522
)
521523

522524

525+
class MqttDiscoveryDeviceUpdateService:
526+
"""Add support for auto discovery for platforms without an entity."""
527+
528+
def __init__(
529+
self,
530+
hass: HomeAssistant,
531+
log_name: str,
532+
discovery_data: dict[str, Any] | None,
533+
device_id: str | None,
534+
config_entry: ConfigEntry,
535+
) -> None:
536+
"""Initialize the update service."""
537+
538+
# Only activate update service id the parent class has a discover hash
539+
if discovery_data is None:
540+
return
541+
542+
self.hass = hass
543+
config_entry_id = config_entry.entry_id
544+
discovery_hash = discovery_data[ATTR_DISCOVERY_HASH]
545+
discovery_topic = discovery_data[ATTR_DISCOVERY_TOPIC]
546+
_device_removed: bool = False
547+
548+
async def async_discovery_update(
549+
discovery_payload: DiscoveryInfoType | None,
550+
) -> None:
551+
"""Handle discovery update."""
552+
if not discovery_payload:
553+
# unregister the service through auto discovery
554+
async_dispatcher_send(
555+
hass, MQTT_DISCOVERY_DONE.format(discovery_hash), None
556+
)
557+
await _async_tear_down()
558+
return
559+
560+
# update the service through auto discovery
561+
await self.async_discovery_update(discovery_payload)
562+
_LOGGER.debug(
563+
"%s %s update has been processed",
564+
log_name,
565+
discovery_hash,
566+
)
567+
async_dispatcher_send(
568+
hass, MQTT_DISCOVERY_DONE.format(discovery_hash), None
569+
)
570+
571+
async def async_device_removed(event):
572+
"""Handle the removal of a device."""
573+
nonlocal _device_removed
574+
nonlocal _device_removed
575+
if _device_removed or not async_removed_from_device(
576+
hass, event, device_id, config_entry_id
577+
):
578+
return
579+
_device_removed = True
580+
# Clear the discovery topic so the service is not rediscovered after a restart
581+
publish(hass, discovery_topic, "", retain=True)
582+
await _async_tear_down()
583+
584+
async def _async_tear_down() -> None:
585+
"""Handle the removal of the service."""
586+
nonlocal _device_removed, self
587+
await self.async_tear_down()
588+
# remove the service for auto discovery updates and clean up the device registry
589+
if not _device_removed and config_entry:
590+
_device_removed = True
591+
await cleanup_device_registry(hass, device_id, config_entry_id)
592+
clear_discovery_hash(hass, discovery_hash)
593+
_remove_discovery()
594+
_LOGGER.info(
595+
"%s %s has been removed",
596+
log_name,
597+
discovery_hash,
598+
)
599+
del self
600+
601+
_remove_discovery = async_dispatcher_connect(
602+
hass,
603+
MQTT_DISCOVERY_UPDATED.format(discovery_hash),
604+
async_discovery_update,
605+
)
606+
if device_id is not None:
607+
self._remove_device_updated = hass.bus.async_listen(
608+
EVENT_DEVICE_REGISTRY_UPDATED, async_device_removed
609+
)
610+
async_dispatcher_send(hass, MQTT_DISCOVERY_DONE.format(discovery_hash), None)
611+
_LOGGER.info(
612+
"%s %s has been initialized",
613+
log_name,
614+
discovery_hash,
615+
)
616+
617+
async def async_tear_down(self) -> None:
618+
"""Handle the cleanup of platform specific parts."""
619+
raise NotImplementedError()
620+
621+
async def async_discovery_update(
622+
self,
623+
discovery_payload: DiscoveryInfoType,
624+
) -> None:
625+
"""Update the configuration through discovery."""
626+
raise NotImplementedError()
627+
628+
523629
class MqttDiscoveryUpdate(Entity):
524-
"""Mixin used to handle updated discovery message."""
630+
"""Mixin used to handle updated discovery message for entity based platforms."""
525631

526632
def __init__(self, discovery_data, discovery_update=None) -> None:
527633
"""Initialize the discovery update mixin."""

0 commit comments

Comments
 (0)