@wbyoung here’s the promised code examples for you:
from homeassistant.components.mqtt import DOMAIN as MQTT_DOMAIN
from homeassistant.core import HomeAssistant
from homeassistant.helpers import device_registry as dr, entity_registry as er
from homeassistant.components.mqtt.models import MqttData
from homeassistant.util.hass_dict import HassKey
MQTT_DATA: HassKey[MqttData] = HassKey(MQTT_DOMAIN)
def get_entities(entity: str, hass: HomeAssistant):
device_registry = dr.async_get(hass)
entity_registry = er.async_get(hass)
device_id = entity_registry.async_get('REPLACE_ME_WITH_LIGHT_ENTITY_ID').device_id
all_entities_for_switch = er.async_entries_for_device(entity_registry, device_id)
double_tap_clear_entity = find_entity(all_entities_for_switch, "DoubleTapClearNotifications")
local_protection_entity = find_entity(all_entities_for_switch, "LocalProtection")
hass.data[MQTT_DATA].debug_info_entities.get(double_tap_clear_entity)['discovery_data']['discovery_payload']
hass.data[MQTT_DATA].debug_info_entities.get(local_protection_entity)['discovery_data']['discovery_payload']
def find_entity(entities: list[er.RegistryEntry], original_name: str) -> str:
for entity in entities:
if entity.original_name == original_name:
return entity.entity_id
If you replace REPLACE_ME_WITH_LIGHT_ENTITY_ID with the entity id of the light entity or fan entity coming from Z2M for example: light.office_lights or fan.office_fan (which will be user provided when they select the switch they want to use), the rest of the code will use that to look up the device id, from there get all of the entities that correspond for it and then find the double_tap_clear and local_protection entities. Next, it goes digging inside the MQTT data to get the discovery payload for those entities. This will look like this:
{'availability': [{...}, {...}], 'availability_mode': 'all', 'command_topic': 'zigbee2mqtt/Office Lights/set/doubleTapClearNotifications', 'device': {'configuration_url': 'https://zigbee2mqtt/#/device/0xd44867fffe899d68/info', 'hw_version': 0, 'identifiers': [...], 'manufacturer': 'Inovelli', 'model': 'mmWave Zigbee Dimmer', 'model_id': 'VZM32-SN', 'sw_version': '0.08', 'via_device': 'zigbee2mqtt_bridge_0x00124b002590967b', 'name': 'Office Lights'}, 'entity_category': 'config', 'object_id': 'office_lights_doubleTapClearNotifications', 'options': ['Enabled (Default)', 'Disabled'], 'origin': {'sw_version': '2.5.0', 'name': 'Zigbee2MQTT', 'support_url': 'https://www.zigbee2mqtt.io'}, 'state_topic': 'zigbee2mqtt/Office Lights', 'unique_id': '0xd44867fffe899d68_doubleTapClearNotifications_zigbee2mqtt', 'value_template': '{{ value_json.doubleTapClearNotifications }}', 'name': 'DoubleTapClearNotifications'}
The relevant part for your use case is the state_topic and the value_template. In the example I’ve provided above this looks like:
'state_topic' = 'zigbee2mqtt/Office Lights'
'value_template' = '{{ value_json.doubleTapClearNotifications }}'
You would therefore be able to subscribe to the state topic and then set up a callback for any responses on that topic to parse the template to get the value.
I like this approach because you are not dependent on the user’s naming of any of the entities (except the light/fan entity itself which they will provide your during the entity setup). It does utilize quite a bit of internals from the MQTT integration but it’s a pattern I’ve used in other integrations successfully before.
Oh and one other thing, you’ll probably need to add this block to the beginning of your integration setup code so it waits until MQTT is enabled and connected before continuing on (if it needs MQTT of course):
# Make sure MQTT integration is enabled and the client is available
if not await mqtt.async_wait_for_mqtt_client(hass):
LOGGER.error("MQTT integration is not available")
return False
hass.data.setdefault(DOMAIN, {})
return True