diff --git a/homeassistant/components/device_tracker/__init__.py b/homeassistant/components/device_tracker/__init__.py index fa537d4af53..035b1923c4c 100644 --- a/homeassistant/components/device_tracker/__init__.py +++ b/homeassistant/components/device_tracker/__init__.py @@ -19,6 +19,7 @@ from .const import ( # noqa: F401 CONF_SCAN_INTERVAL, CONF_TRACK_NEW, DOMAIN, + ENTITY_ID_FORMAT, SOURCE_TYPE_BLUETOOTH, SOURCE_TYPE_BLUETOOTH_LE, SOURCE_TYPE_GPS, diff --git a/homeassistant/components/device_tracker/const.py b/homeassistant/components/device_tracker/const.py index 09102372db6..216255b9cb6 100644 --- a/homeassistant/components/device_tracker/const.py +++ b/homeassistant/components/device_tracker/const.py @@ -6,6 +6,7 @@ from typing import Final LOGGER: Final = logging.getLogger(__package__) DOMAIN: Final = "device_tracker" +ENTITY_ID_FORMAT: Final = DOMAIN + ".{}" PLATFORM_TYPE_LEGACY: Final = "legacy" PLATFORM_TYPE_ENTITY: Final = "entity_platform" diff --git a/homeassistant/components/humidifier/__init__.py b/homeassistant/components/humidifier/__init__.py index d15f70f181a..48a71662be1 100644 --- a/homeassistant/components/humidifier/__init__.py +++ b/homeassistant/components/humidifier/__init__.py @@ -47,6 +47,8 @@ _LOGGER = logging.getLogger(__name__) SCAN_INTERVAL = timedelta(seconds=60) +ENTITY_ID_FORMAT = DOMAIN + ".{}" + DEVICE_CLASSES = [DEVICE_CLASS_HUMIDIFIER, DEVICE_CLASS_DEHUMIDIFIER] DEVICE_CLASSES_SCHEMA = vol.All(vol.Lower, vol.In(DEVICE_CLASSES)) diff --git a/homeassistant/components/mqtt/abbreviations.py b/homeassistant/components/mqtt/abbreviations.py index 155667b00cb..71a8d109c3f 100644 --- a/homeassistant/components/mqtt/abbreviations.py +++ b/homeassistant/components/mqtt/abbreviations.py @@ -97,6 +97,7 @@ ABBREVIATIONS = { "mode_stat_tpl": "mode_state_template", "modes": "modes", "name": "name", + "obj_id": "object_id", "off_dly": "off_delay", "on_cmd_type": "on_command_type", "ops": "options", diff --git a/homeassistant/components/mqtt/alarm_control_panel.py b/homeassistant/components/mqtt/alarm_control_panel.py index 5ac6e5ea89a..ffea92f14c3 100644 --- a/homeassistant/components/mqtt/alarm_control_panel.py +++ b/homeassistant/components/mqtt/alarm_control_panel.py @@ -126,6 +126,7 @@ async def _async_setup_entity( class MqttAlarm(MqttEntity, alarm.AlarmControlPanelEntity): """Representation of a MQTT alarm status.""" + _entity_id_format = alarm.ENTITY_ID_FORMAT _attributes_extra_blocked = MQTT_ALARM_ATTRIBUTES_BLOCKED def __init__(self, hass, config, config_entry, discovery_data): diff --git a/homeassistant/components/mqtt/binary_sensor.py b/homeassistant/components/mqtt/binary_sensor.py index 213aabdb006..1928f79032d 100644 --- a/homeassistant/components/mqtt/binary_sensor.py +++ b/homeassistant/components/mqtt/binary_sensor.py @@ -87,6 +87,8 @@ async def _async_setup_entity( class MqttBinarySensor(MqttEntity, BinarySensorEntity): """Representation a binary sensor that is updated by MQTT.""" + _entity_id_format = binary_sensor.ENTITY_ID_FORMAT + def __init__(self, hass, config, config_entry, discovery_data): """Initialize the MQTT binary sensor.""" self._state = None diff --git a/homeassistant/components/mqtt/camera.py b/homeassistant/components/mqtt/camera.py index 39457dbd629..a9fdfb96a6c 100644 --- a/homeassistant/components/mqtt/camera.py +++ b/homeassistant/components/mqtt/camera.py @@ -66,6 +66,7 @@ async def _async_setup_entity( class MqttCamera(MqttEntity, Camera): """representation of a MQTT camera.""" + _entity_id_format = camera.ENTITY_ID_FORMAT _attributes_extra_blocked = MQTT_CAMERA_ATTRIBUTES_BLOCKED def __init__(self, hass, config, config_entry, discovery_data): diff --git a/homeassistant/components/mqtt/climate.py b/homeassistant/components/mqtt/climate.py index 5b186ff9126..b4b1875c4df 100644 --- a/homeassistant/components/mqtt/climate.py +++ b/homeassistant/components/mqtt/climate.py @@ -297,6 +297,7 @@ async def _async_setup_entity( class MqttClimate(MqttEntity, ClimateEntity): """Representation of an MQTT climate device.""" + _entity_id_format = climate.ENTITY_ID_FORMAT _attributes_extra_blocked = MQTT_CLIMATE_ATTRIBUTES_BLOCKED def __init__(self, hass, config, config_entry, discovery_data): diff --git a/homeassistant/components/mqtt/cover.py b/homeassistant/components/mqtt/cover.py index 859d9811617..c2800cc8239 100644 --- a/homeassistant/components/mqtt/cover.py +++ b/homeassistant/components/mqtt/cover.py @@ -224,6 +224,7 @@ async def _async_setup_entity( class MqttCover(MqttEntity, CoverEntity): """Representation of a cover that can be controlled using MQTT.""" + _entity_id_format = cover.ENTITY_ID_FORMAT _attributes_extra_blocked = MQTT_COVER_ATTRIBUTES_BLOCKED def __init__(self, hass, config, config_entry, discovery_data): diff --git a/homeassistant/components/mqtt/device_tracker/schema_discovery.py b/homeassistant/components/mqtt/device_tracker/schema_discovery.py index f962d9208a4..1ccf03423de 100644 --- a/homeassistant/components/mqtt/device_tracker/schema_discovery.py +++ b/homeassistant/components/mqtt/device_tracker/schema_discovery.py @@ -58,6 +58,8 @@ async def _async_setup_entity( class MqttDeviceTracker(MqttEntity, TrackerEntity): """Representation of a device tracker using MQTT.""" + _entity_id_format = device_tracker.ENTITY_ID_FORMAT + def __init__(self, hass, config, config_entry, discovery_data): """Initialize the tracker.""" self._location_name = None diff --git a/homeassistant/components/mqtt/fan.py b/homeassistant/components/mqtt/fan.py index f1040825cdf..9d0c954f3ab 100644 --- a/homeassistant/components/mqtt/fan.py +++ b/homeassistant/components/mqtt/fan.py @@ -230,6 +230,7 @@ async def _async_setup_entity( class MqttFan(MqttEntity, FanEntity): """A MQTT fan component.""" + _entity_id_format = fan.ENTITY_ID_FORMAT _attributes_extra_blocked = MQTT_FAN_ATTRIBUTES_BLOCKED def __init__(self, hass, config, config_entry, discovery_data): diff --git a/homeassistant/components/mqtt/humidifier.py b/homeassistant/components/mqtt/humidifier.py index e4f578ef94c..a5346c0bf58 100644 --- a/homeassistant/components/mqtt/humidifier.py +++ b/homeassistant/components/mqtt/humidifier.py @@ -163,6 +163,7 @@ async def _async_setup_entity( class MqttHumidifier(MqttEntity, HumidifierEntity): """A MQTT humidifier component.""" + _entity_id_format = humidifier.ENTITY_ID_FORMAT _attributes_extra_blocked = MQTT_HUMIDIFIER_ATTRIBUTES_BLOCKED def __init__(self, hass, config, config_entry, discovery_data): diff --git a/homeassistant/components/mqtt/light/schema_basic.py b/homeassistant/components/mqtt/light/schema_basic.py index 1909d7e136b..c0fc65610fd 100644 --- a/homeassistant/components/mqtt/light/schema_basic.py +++ b/homeassistant/components/mqtt/light/schema_basic.py @@ -29,6 +29,7 @@ from homeassistant.components.light import ( COLOR_MODE_UNKNOWN, COLOR_MODE_WHITE, COLOR_MODE_XY, + ENTITY_ID_FORMAT, SUPPORT_BRIGHTNESS, SUPPORT_COLOR, SUPPORT_COLOR_TEMP, @@ -239,6 +240,7 @@ async def async_setup_entity_basic( class MqttLight(MqttEntity, LightEntity, RestoreEntity): """Representation of a MQTT light.""" + _entity_id_format = ENTITY_ID_FORMAT _attributes_extra_blocked = MQTT_LIGHT_ATTRIBUTES_BLOCKED def __init__(self, hass, config, config_entry, discovery_data): diff --git a/homeassistant/components/mqtt/light/schema_json.py b/homeassistant/components/mqtt/light/schema_json.py index 412205ea9cf..0ba796df4e7 100644 --- a/homeassistant/components/mqtt/light/schema_json.py +++ b/homeassistant/components/mqtt/light/schema_json.py @@ -24,6 +24,7 @@ from homeassistant.components.light import ( COLOR_MODE_RGBW, COLOR_MODE_RGBWW, COLOR_MODE_XY, + ENTITY_ID_FORMAT, FLASH_LONG, FLASH_SHORT, SUPPORT_BRIGHTNESS, @@ -167,6 +168,7 @@ async def async_setup_entity_json( class MqttLightJson(MqttEntity, LightEntity, RestoreEntity): """Representation of a MQTT JSON light.""" + _entity_id_format = ENTITY_ID_FORMAT _attributes_extra_blocked = MQTT_LIGHT_ATTRIBUTES_BLOCKED def __init__(self, hass, config, config_entry, discovery_data): diff --git a/homeassistant/components/mqtt/light/schema_template.py b/homeassistant/components/mqtt/light/schema_template.py index 0a19fbb9836..838daab5860 100644 --- a/homeassistant/components/mqtt/light/schema_template.py +++ b/homeassistant/components/mqtt/light/schema_template.py @@ -11,6 +11,7 @@ from homeassistant.components.light import ( ATTR_HS_COLOR, ATTR_TRANSITION, ATTR_WHITE_VALUE, + ENTITY_ID_FORMAT, SUPPORT_BRIGHTNESS, SUPPORT_COLOR, SUPPORT_COLOR_TEMP, @@ -97,6 +98,7 @@ async def async_setup_entity_template( class MqttLightTemplate(MqttEntity, LightEntity, RestoreEntity): """Representation of a MQTT Template light.""" + _entity_id_format = ENTITY_ID_FORMAT _attributes_extra_blocked = MQTT_LIGHT_ATTRIBUTES_BLOCKED def __init__(self, hass, config, config_entry, discovery_data): diff --git a/homeassistant/components/mqtt/lock.py b/homeassistant/components/mqtt/lock.py index 8de4c4431b9..5410af5d38c 100644 --- a/homeassistant/components/mqtt/lock.py +++ b/homeassistant/components/mqtt/lock.py @@ -78,6 +78,7 @@ async def _async_setup_entity( class MqttLock(MqttEntity, LockEntity): """Representation of a lock that can be toggled using MQTT.""" + _entity_id_format = lock.ENTITY_ID_FORMAT _attributes_extra_blocked = MQTT_LOCK_ATTRIBUTES_BLOCKED def __init__(self, hass, config, config_entry, discovery_data): diff --git a/homeassistant/components/mqtt/mixins.py b/homeassistant/components/mqtt/mixins.py index 7cfc00da578..3a374070f2f 100644 --- a/homeassistant/components/mqtt/mixins.py +++ b/homeassistant/components/mqtt/mixins.py @@ -28,7 +28,12 @@ from homeassistant.helpers.dispatcher import ( async_dispatcher_connect, async_dispatcher_send, ) -from homeassistant.helpers.entity import ENTITY_CATEGORIES_SCHEMA, DeviceInfo, Entity +from homeassistant.helpers.entity import ( + ENTITY_CATEGORIES_SCHEMA, + DeviceInfo, + Entity, + async_generate_entity_id, +) from homeassistant.helpers.typing import ConfigType from . import DATA_MQTT, debug_info, publish, subscription @@ -82,6 +87,7 @@ CONF_VIA_DEVICE = "via_device" CONF_DEPRECATED_VIA_HUB = "via_hub" CONF_SUGGESTED_AREA = "suggested_area" CONF_CONFIGURATION_URL = "configuration_url" +CONF_OBJECT_ID = "object_id" MQTT_ATTRIBUTES_BLOCKED = { "assumed_state", @@ -183,6 +189,7 @@ MQTT_ENTITY_COMMON_SCHEMA = MQTT_AVAILABILITY_SCHEMA.extend( vol.Optional(CONF_ICON): cv.icon, vol.Optional(CONF_JSON_ATTRS_TOPIC): valid_subscribe_topic, vol.Optional(CONF_JSON_ATTRS_TEMPLATE): cv.template, + vol.Optional(CONF_OBJECT_ID): cv.string, vol.Optional(CONF_UNIQUE_ID): cv.string, } ) @@ -210,6 +217,14 @@ async def async_setup_entry_helper(hass, domain, async_setup, schema): ) +def init_entity_id_from_config(hass, entity, config, entity_id_format): + """Set entity_id from object_id if defined in config.""" + if CONF_OBJECT_ID in config: + entity.entity_id = async_generate_entity_id( + entity_id_format, config[CONF_OBJECT_ID], None, hass + ) + + class MqttAttributes(Entity): """Mixin used for platforms that support JSON attributes.""" @@ -588,6 +603,8 @@ class MqttEntity( ): """Representation of an MQTT entity.""" + _entity_id_format: str + def __init__(self, hass, config, config_entry, discovery_data): """Init the MQTT Entity.""" self.hass = hass @@ -598,12 +615,21 @@ class MqttEntity( # Load config self._setup_from_config(self._config) + # Initialize entity_id from config + self._init_entity_id() + # Initialize mixin classes MqttAttributes.__init__(self, config) MqttAvailability.__init__(self, config) MqttDiscoveryUpdate.__init__(self, discovery_data, self.discovery_update) MqttEntityDeviceInfo.__init__(self, config.get(CONF_DEVICE), config_entry) + def _init_entity_id(self): + """Set entity_id from object_id if defined in config.""" + init_entity_id_from_config( + self.hass, self, self._config, self._entity_id_format + ) + async def async_added_to_hass(self): """Subscribe mqtt events.""" await super().async_added_to_hass() diff --git a/homeassistant/components/mqtt/number.py b/homeassistant/components/mqtt/number.py index 6d0163abe32..29f6b4bad21 100644 --- a/homeassistant/components/mqtt/number.py +++ b/homeassistant/components/mqtt/number.py @@ -114,6 +114,7 @@ async def _async_setup_entity( class MqttNumber(MqttEntity, NumberEntity, RestoreEntity): """representation of an MQTT number.""" + _entity_id_format = number.ENTITY_ID_FORMAT _attributes_extra_blocked = MQTT_NUMBER_ATTRIBUTES_BLOCKED def __init__(self, hass, config, config_entry, discovery_data): diff --git a/homeassistant/components/mqtt/scene.py b/homeassistant/components/mqtt/scene.py index c2b201e20e6..67b757e5e8a 100644 --- a/homeassistant/components/mqtt/scene.py +++ b/homeassistant/components/mqtt/scene.py @@ -15,10 +15,12 @@ from . import PLATFORMS from .. import mqtt from .const import CONF_COMMAND_TOPIC, CONF_QOS, CONF_RETAIN, DOMAIN from .mixins import ( + CONF_OBJECT_ID, MQTT_AVAILABILITY_SCHEMA, MqttAvailability, MqttDiscoveryUpdate, async_setup_entry_helper, + init_entity_id_from_config, ) DEFAULT_NAME = "MQTT Scene" @@ -32,6 +34,7 @@ PLATFORM_SCHEMA = mqtt.MQTT_BASE_PLATFORM_SCHEMA.extend( vol.Optional(CONF_PAYLOAD_ON): cv.string, vol.Optional(CONF_UNIQUE_ID): cv.string, vol.Optional(CONF_RETAIN, default=DEFAULT_RETAIN): cv.boolean, + vol.Optional(CONF_OBJECT_ID): cv.string, } ).extend(MQTT_AVAILABILITY_SCHEMA.schema) @@ -43,22 +46,22 @@ async def async_setup_platform( ): """Set up MQTT scene through configuration.yaml.""" await async_setup_reload_service(hass, DOMAIN, PLATFORMS) - await _async_setup_entity(async_add_entities, config) + await _async_setup_entity(hass, async_add_entities, config) async def async_setup_entry(hass, config_entry, async_add_entities): """Set up MQTT scene dynamically through MQTT discovery.""" setup = functools.partial( - _async_setup_entity, async_add_entities, config_entry=config_entry + _async_setup_entity, hass, async_add_entities, config_entry=config_entry ) await async_setup_entry_helper(hass, scene.DOMAIN, setup, DISCOVERY_SCHEMA) async def _async_setup_entity( - async_add_entities, config, config_entry=None, discovery_data=None + hass, async_add_entities, config, config_entry=None, discovery_data=None ): """Set up the MQTT scene.""" - async_add_entities([MqttScene(config, config_entry, discovery_data)]) + async_add_entities([MqttScene(hass, config, config_entry, discovery_data)]) class MqttScene( @@ -68,8 +71,11 @@ class MqttScene( ): """Representation of a scene that can be activated using MQTT.""" - def __init__(self, config, config_entry, discovery_data): + _entity_id_format = scene.DOMAIN + ".{}" + + def __init__(self, hass, config, config_entry, discovery_data): """Initialize the MQTT scene.""" + self.hass = hass self._state = False self._sub_state = None @@ -78,9 +84,18 @@ class MqttScene( # Load config self._setup_from_config(config) + # Initialize entity_id from config + self._init_entity_id() + MqttAvailability.__init__(self, config) MqttDiscoveryUpdate.__init__(self, discovery_data, self.discovery_update) + def _init_entity_id(self): + """Set entity_id from object_id if defined in config.""" + init_entity_id_from_config( + self.hass, self, self._config, self._entity_id_format + ) + async def async_added_to_hass(self): """Subscribe to MQTT events.""" await super().async_added_to_hass() diff --git a/homeassistant/components/mqtt/select.py b/homeassistant/components/mqtt/select.py index c43593dfc4b..45304d68079 100644 --- a/homeassistant/components/mqtt/select.py +++ b/homeassistant/components/mqtt/select.py @@ -90,6 +90,8 @@ async def _async_setup_entity( class MqttSelect(MqttEntity, SelectEntity, RestoreEntity): """representation of an MQTT select.""" + _entity_id_format = select.ENTITY_ID_FORMAT + _attributes_extra_blocked = MQTT_SELECT_ATTRIBUTES_BLOCKED def __init__(self, hass, config, config_entry, discovery_data): diff --git a/homeassistant/components/mqtt/sensor.py b/homeassistant/components/mqtt/sensor.py index 3881dfee0e8..4d0f610300f 100644 --- a/homeassistant/components/mqtt/sensor.py +++ b/homeassistant/components/mqtt/sensor.py @@ -11,6 +11,7 @@ from homeassistant.components import sensor from homeassistant.components.sensor import ( CONF_STATE_CLASS, DEVICE_CLASSES_SCHEMA, + ENTITY_ID_FORMAT, STATE_CLASSES_SCHEMA, SensorEntity, ) @@ -132,6 +133,7 @@ async def _async_setup_entity( class MqttSensor(MqttEntity, SensorEntity): """Representation of a sensor that can be updated using MQTT.""" + _entity_id_format = ENTITY_ID_FORMAT _attr_last_reset = None _attributes_extra_blocked = MQTT_SENSOR_ATTRIBUTES_BLOCKED diff --git a/homeassistant/components/mqtt/switch.py b/homeassistant/components/mqtt/switch.py index 9cc13ac94bd..8f9178c15f1 100644 --- a/homeassistant/components/mqtt/switch.py +++ b/homeassistant/components/mqtt/switch.py @@ -84,6 +84,7 @@ async def _async_setup_entity( class MqttSwitch(MqttEntity, SwitchEntity, RestoreEntity): """Representation of a switch that can be toggled using MQTT.""" + _entity_id_format = switch.ENTITY_ID_FORMAT _attributes_extra_blocked = MQTT_SWITCH_ATTRIBUTES_BLOCKED def __init__(self, hass, config, config_entry, discovery_data): diff --git a/homeassistant/components/mqtt/vacuum/schema_legacy.py b/homeassistant/components/mqtt/vacuum/schema_legacy.py index 63bb47ce21b..b19d4afe23e 100644 --- a/homeassistant/components/mqtt/vacuum/schema_legacy.py +++ b/homeassistant/components/mqtt/vacuum/schema_legacy.py @@ -5,6 +5,7 @@ import voluptuous as vol from homeassistant.components.vacuum import ( ATTR_STATUS, + ENTITY_ID_FORMAT, SUPPORT_BATTERY, SUPPORT_CLEAN_SPOT, SUPPORT_FAN_SPEED, @@ -169,6 +170,7 @@ async def async_setup_entity_legacy( class MqttVacuum(MqttEntity, VacuumEntity): """Representation of a MQTT-controlled legacy vacuum.""" + _entity_id_format = ENTITY_ID_FORMAT _attributes_extra_blocked = MQTT_LEGACY_VACUUM_ATTRIBUTES_BLOCKED def __init__(self, hass, config, config_entry, discovery_data): diff --git a/homeassistant/components/mqtt/vacuum/schema_state.py b/homeassistant/components/mqtt/vacuum/schema_state.py index 8c654a526e4..0bfb7289f37 100644 --- a/homeassistant/components/mqtt/vacuum/schema_state.py +++ b/homeassistant/components/mqtt/vacuum/schema_state.py @@ -4,6 +4,7 @@ import json import voluptuous as vol from homeassistant.components.vacuum import ( + ENTITY_ID_FORMAT, STATE_CLEANING, STATE_DOCKED, STATE_ERROR, @@ -149,6 +150,7 @@ async def async_setup_entity_state( class MqttStateVacuum(MqttEntity, StateVacuumEntity): """Representation of a MQTT-controlled state vacuum.""" + _entity_id_format = ENTITY_ID_FORMAT _attributes_extra_blocked = MQTT_VACUUM_ATTRIBUTES_BLOCKED def __init__(self, hass, config, config_entry, discovery_data): diff --git a/homeassistant/components/vacuum/__init__.py b/homeassistant/components/vacuum/__init__.py index 87d8d6f49f8..db186a464fa 100644 --- a/homeassistant/components/vacuum/__init__.py +++ b/homeassistant/components/vacuum/__init__.py @@ -40,6 +40,7 @@ from homeassistant.loader import bind_hass _LOGGER = logging.getLogger(__name__) DOMAIN = "vacuum" +ENTITY_ID_FORMAT = DOMAIN + ".{}" SCAN_INTERVAL = timedelta(seconds=20) ATTR_BATTERY_ICON = "battery_icon" diff --git a/tests/components/mqtt/test_discovery.py b/tests/components/mqtt/test_discovery.py index 60c3961477b..08eb4b882c5 100644 --- a/tests/components/mqtt/test_discovery.py +++ b/tests/components/mqtt/test_discovery.py @@ -191,6 +191,158 @@ async def test_discover_alarm_control_panel(hass, mqtt_mock, caplog): assert ("alarm_control_panel", "bla") in hass.data[ALREADY_DISCOVERED] +@pytest.mark.parametrize( + "topic, config, entity_id, name, domain", + [ + ( + "homeassistant/alarm_control_panel/object/bla/config", + '{ "name": "Hello World 1", "obj_id": "hello_id", "state_topic": "test-topic", "command_topic": "test-topic" }', + "alarm_control_panel.hello_id", + "Hello World 1", + "alarm_control_panel", + ), + ( + "homeassistant/binary_sensor/object/bla/config", + '{ "name": "Hello World 2", "obj_id": "hello_id", "state_topic": "test-topic" }', + "binary_sensor.hello_id", + "Hello World 2", + "binary_sensor", + ), + ( + "homeassistant/camera/object/bla/config", + '{ "name": "Hello World 3", "obj_id": "hello_id", "state_topic": "test-topic", "topic": "test-topic" }', + "camera.hello_id", + "Hello World 3", + "camera", + ), + ( + "homeassistant/climate/object/bla/config", + '{ "name": "Hello World 4", "obj_id": "hello_id", "state_topic": "test-topic" }', + "climate.hello_id", + "Hello World 4", + "climate", + ), + ( + "homeassistant/cover/object/bla/config", + '{ "name": "Hello World 5", "obj_id": "hello_id", "state_topic": "test-topic" }', + "cover.hello_id", + "Hello World 5", + "cover", + ), + ( + "homeassistant/fan/object/bla/config", + '{ "name": "Hello World 6", "obj_id": "hello_id", "state_topic": "test-topic", "command_topic": "test-topic" }', + "fan.hello_id", + "Hello World 6", + "fan", + ), + ( + "homeassistant/humidifier/object/bla/config", + '{ "name": "Hello World 7", "obj_id": "hello_id", "state_topic": "test-topic", "target_humidity_command_topic": "test-topic", "command_topic": "test-topic" }', + "humidifier.hello_id", + "Hello World 7", + "humidifier", + ), + ( + "homeassistant/number/object/bla/config", + '{ "name": "Hello World 8", "obj_id": "hello_id", "state_topic": "test-topic", "command_topic": "test-topic" }', + "number.hello_id", + "Hello World 8", + "number", + ), + ( + "homeassistant/scene/object/bla/config", + '{ "name": "Hello World 9", "obj_id": "hello_id", "state_topic": "test-topic", "command_topic": "test-topic" }', + "scene.hello_id", + "Hello World 9", + "scene", + ), + ( + "homeassistant/select/object/bla/config", + '{ "name": "Hello World 10", "obj_id": "hello_id", "state_topic": "test-topic", "options": [ "opt1", "opt2" ], "command_topic": "test-topic" }', + "select.hello_id", + "Hello World 10", + "select", + ), + ( + "homeassistant/sensor/object/bla/config", + '{ "name": "Hello World 11", "obj_id": "hello_id", "state_topic": "test-topic" }', + "sensor.hello_id", + "Hello World 11", + "sensor", + ), + ( + "homeassistant/switch/object/bla/config", + '{ "name": "Hello World 12", "obj_id": "hello_id", "state_topic": "test-topic", "command_topic": "test-topic" }', + "switch.hello_id", + "Hello World 12", + "switch", + ), + ( + "homeassistant/light/object/bla/config", + '{ "name": "Hello World 13", "obj_id": "hello_id", "state_topic": "test-topic", "command_topic": "test-topic" }', + "light.hello_id", + "Hello World 13", + "light", + ), + ( + "homeassistant/light/object/bla/config", + '{ "name": "Hello World 14", "obj_id": "hello_id", "state_topic": "test-topic", "command_topic": "test-topic", "schema": "json" }', + "light.hello_id", + "Hello World 14", + "light", + ), + ( + "homeassistant/light/object/bla/config", + '{ "name": "Hello World 15", "obj_id": "hello_id", "state_topic": "test-topic", "command_off_template": "template", "command_on_template": "template", "command_topic": "test-topic", "schema": "template" }', + "light.hello_id", + "Hello World 15", + "light", + ), + ( + "homeassistant/vacuum/object/bla/config", + '{ "name": "Hello World 16", "obj_id": "hello_id", "state_topic": "test-topic", "schema": "state" }', + "vacuum.hello_id", + "Hello World 16", + "vacuum", + ), + ( + "homeassistant/vacuum/object/bla/config", + '{ "name": "Hello World 17", "obj_id": "hello_id", "state_topic": "test-topic", "schema": "legacy" }', + "vacuum.hello_id", + "Hello World 17", + "vacuum", + ), + ( + "homeassistant/lock/object/bla/config", + '{ "name": "Hello World 18", "obj_id": "hello_id", "state_topic": "test-topic", "command_topic": "test-topic" }', + "lock.hello_id", + "Hello World 18", + "lock", + ), + ( + "homeassistant/device_tracker/object/bla/config", + '{ "name": "Hello World 19", "obj_id": "hello_id", "state_topic": "test-topic" }', + "device_tracker.hello_id", + "Hello World 19", + "device_tracker", + ), + ], +) +async def test_discovery_with_object_id( + hass, mqtt_mock, caplog, topic, config, entity_id, name, domain +): + """Test discovering an MQTT entity with object_id.""" + async_fire_mqtt_message(hass, topic, config) + await hass.async_block_till_done() + + state = hass.states.get(entity_id) + + assert state is not None + assert state.name == name + assert (domain, "object bla") in hass.data[ALREADY_DISCOVERED] + + async def test_discovery_incl_nodeid(hass, mqtt_mock, caplog): """Test sending in correct JSON with optional node_id included.""" async_fire_mqtt_message(