Drop MQTT import flow (#66160)

* Drop MQTT import flow

* Reload manually configured MQTT entities when config entry is setup

* Address review comments

* Actually remove the import flow
This commit is contained in:
Erik Montnemery 2022-02-10 21:09:57 +01:00 committed by GitHub
parent dc7ab40acd
commit fe38e6ba87
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
45 changed files with 494 additions and 155 deletions

View file

@ -21,7 +21,6 @@ import certifi
import jinja2 import jinja2
import voluptuous as vol import voluptuous as vol
from homeassistant import config_entries
from homeassistant.components import websocket_api from homeassistant.components import websocket_api
from homeassistant.config_entries import ConfigEntry from homeassistant.config_entries import ConfigEntry
from homeassistant.const import ( from homeassistant.const import (
@ -37,6 +36,7 @@ from homeassistant.const import (
CONF_VALUE_TEMPLATE, CONF_VALUE_TEMPLATE,
EVENT_HOMEASSISTANT_STARTED, EVENT_HOMEASSISTANT_STARTED,
EVENT_HOMEASSISTANT_STOP, EVENT_HOMEASSISTANT_STOP,
SERVICE_RELOAD,
Platform, Platform,
) )
from homeassistant.core import ( from homeassistant.core import (
@ -76,6 +76,7 @@ from .const import (
CONF_TOPIC, CONF_TOPIC,
CONF_WILL_MESSAGE, CONF_WILL_MESSAGE,
DATA_MQTT_CONFIG, DATA_MQTT_CONFIG,
DATA_MQTT_RELOAD_NEEDED,
DEFAULT_BIRTH, DEFAULT_BIRTH,
DEFAULT_DISCOVERY, DEFAULT_DISCOVERY,
DEFAULT_ENCODING, DEFAULT_ENCODING,
@ -580,22 +581,9 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
websocket_api.async_register_command(hass, websocket_mqtt_info) websocket_api.async_register_command(hass, websocket_mqtt_info)
debug_info.initialize(hass) debug_info.initialize(hass)
if conf is None: if conf:
# If we have a config entry, setup is done by that config entry. conf = dict(conf)
# If there is no config entry, this should fail. hass.data[DATA_MQTT_CONFIG] = conf
return bool(hass.config_entries.async_entries(DOMAIN))
conf = dict(conf)
hass.data[DATA_MQTT_CONFIG] = conf
# Only import if we haven't before.
if not hass.config_entries.async_entries(DOMAIN):
hass.async_create_task(
hass.config_entries.flow.async_init(
DOMAIN, context={"source": config_entries.SOURCE_IMPORT}, data={}
)
)
return True return True
@ -609,12 +597,6 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Load a config entry.""" """Load a config entry."""
conf = hass.data.get(DATA_MQTT_CONFIG) conf = hass.data.get(DATA_MQTT_CONFIG)
# Config entry was created because user had configuration.yaml entry
# They removed that, so remove entry.
if conf is None and entry.source == config_entries.SOURCE_IMPORT:
hass.async_create_task(hass.config_entries.async_remove(entry.entry_id))
return False
# If user didn't have configuration.yaml config, generate defaults # If user didn't have configuration.yaml config, generate defaults
if conf is None: if conf is None:
conf = CONFIG_SCHEMA({DOMAIN: dict(entry.data)})[DOMAIN] conf = CONFIG_SCHEMA({DOMAIN: dict(entry.data)})[DOMAIN]
@ -735,6 +717,15 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
if conf.get(CONF_DISCOVERY): if conf.get(CONF_DISCOVERY):
await _async_setup_discovery(hass, conf, entry) await _async_setup_discovery(hass, conf, entry)
if DATA_MQTT_RELOAD_NEEDED in hass.data:
hass.data.pop(DATA_MQTT_RELOAD_NEEDED)
await hass.services.async_call(
DOMAIN,
SERVICE_RELOAD,
{},
blocking=False,
)
return True return True

View file

@ -35,10 +35,9 @@ from homeassistant.const import (
from homeassistant.core import HomeAssistant, callback from homeassistant.core import HomeAssistant, callback
import homeassistant.helpers.config_validation as cv import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.reload import async_setup_reload_service
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
from . import PLATFORMS, MqttCommandTemplate, MqttValueTemplate, subscription from . import MqttCommandTemplate, MqttValueTemplate, subscription
from .. import mqtt from .. import mqtt
from .const import ( from .const import (
CONF_COMMAND_TEMPLATE, CONF_COMMAND_TEMPLATE,
@ -47,10 +46,14 @@ from .const import (
CONF_QOS, CONF_QOS,
CONF_RETAIN, CONF_RETAIN,
CONF_STATE_TOPIC, CONF_STATE_TOPIC,
DOMAIN,
) )
from .debug_info import log_messages from .debug_info import log_messages
from .mixins import MQTT_ENTITY_COMMON_SCHEMA, MqttEntity, async_setup_entry_helper from .mixins import (
MQTT_ENTITY_COMMON_SCHEMA,
MqttEntity,
async_setup_entry_helper,
async_setup_platform_helper,
)
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@ -124,8 +127,9 @@ async def async_setup_platform(
discovery_info: DiscoveryInfoType | None = None, discovery_info: DiscoveryInfoType | None = None,
) -> None: ) -> None:
"""Set up MQTT alarm control panel through configuration.yaml.""" """Set up MQTT alarm control panel through configuration.yaml."""
await async_setup_reload_service(hass, DOMAIN, PLATFORMS) await async_setup_platform_helper(
await _async_setup_entity(hass, async_add_entities, config) hass, alarm.DOMAIN, config, async_add_entities, _async_setup_entity
)
async def async_setup_entry( async def async_setup_entry(

View file

@ -28,20 +28,20 @@ import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.entity_platform import AddEntitiesCallback
import homeassistant.helpers.event as evt import homeassistant.helpers.event as evt
from homeassistant.helpers.event import async_track_point_in_utc_time from homeassistant.helpers.event import async_track_point_in_utc_time
from homeassistant.helpers.reload import async_setup_reload_service
from homeassistant.helpers.restore_state import RestoreEntity from homeassistant.helpers.restore_state import RestoreEntity
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
from homeassistant.util import dt as dt_util from homeassistant.util import dt as dt_util
from . import PLATFORMS, MqttValueTemplate, subscription from . import MqttValueTemplate, subscription
from .. import mqtt from .. import mqtt
from .const import CONF_ENCODING, CONF_QOS, CONF_STATE_TOPIC, DOMAIN, PAYLOAD_NONE from .const import CONF_ENCODING, CONF_QOS, CONF_STATE_TOPIC, PAYLOAD_NONE
from .debug_info import log_messages from .debug_info import log_messages
from .mixins import ( from .mixins import (
MQTT_ENTITY_COMMON_SCHEMA, MQTT_ENTITY_COMMON_SCHEMA,
MqttAvailability, MqttAvailability,
MqttEntity, MqttEntity,
async_setup_entry_helper, async_setup_entry_helper,
async_setup_platform_helper,
) )
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@ -75,8 +75,9 @@ async def async_setup_platform(
discovery_info: DiscoveryInfoType | None = None, discovery_info: DiscoveryInfoType | None = None,
) -> None: ) -> None:
"""Set up MQTT binary sensor through configuration.yaml.""" """Set up MQTT binary sensor through configuration.yaml."""
await async_setup_reload_service(hass, DOMAIN, PLATFORMS) await async_setup_platform_helper(
await _async_setup_entity(hass, async_add_entities, config) hass, binary_sensor.DOMAIN, config, async_add_entities, _async_setup_entity
)
async def async_setup_entry( async def async_setup_entry(

View file

@ -12,10 +12,9 @@ from homeassistant.const import CONF_DEVICE_CLASS, CONF_NAME
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
import homeassistant.helpers.config_validation as cv import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.reload import async_setup_reload_service
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
from . import PLATFORMS, MqttCommandTemplate from . import MqttCommandTemplate
from .. import mqtt from .. import mqtt
from .const import ( from .const import (
CONF_COMMAND_TEMPLATE, CONF_COMMAND_TEMPLATE,
@ -23,9 +22,13 @@ from .const import (
CONF_ENCODING, CONF_ENCODING,
CONF_QOS, CONF_QOS,
CONF_RETAIN, CONF_RETAIN,
DOMAIN,
) )
from .mixins import MQTT_ENTITY_COMMON_SCHEMA, MqttEntity, async_setup_entry_helper from .mixins import (
MQTT_ENTITY_COMMON_SCHEMA,
MqttEntity,
async_setup_entry_helper,
async_setup_platform_helper,
)
CONF_PAYLOAD_PRESS = "payload_press" CONF_PAYLOAD_PRESS = "payload_press"
DEFAULT_NAME = "MQTT Button" DEFAULT_NAME = "MQTT Button"
@ -52,8 +55,9 @@ async def async_setup_platform(
discovery_info: DiscoveryInfoType | None = None, discovery_info: DiscoveryInfoType | None = None,
) -> None: ) -> None:
"""Set up MQTT button through configuration.yaml.""" """Set up MQTT button through configuration.yaml."""
await async_setup_reload_service(hass, DOMAIN, PLATFORMS) await async_setup_platform_helper(
await _async_setup_entity(hass, async_add_entities, config) hass, button.DOMAIN, config, async_add_entities, _async_setup_entity
)
async def async_setup_entry( async def async_setup_entry(

View file

@ -12,14 +12,18 @@ from homeassistant.const import CONF_NAME
from homeassistant.core import HomeAssistant, callback from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers import config_validation as cv from homeassistant.helpers import config_validation as cv
from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.reload import async_setup_reload_service
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
from . import PLATFORMS, subscription from . import subscription
from .. import mqtt from .. import mqtt
from .const import CONF_QOS, CONF_TOPIC, DOMAIN from .const import CONF_QOS, CONF_TOPIC
from .debug_info import log_messages from .debug_info import log_messages
from .mixins import MQTT_ENTITY_COMMON_SCHEMA, MqttEntity, async_setup_entry_helper from .mixins import (
MQTT_ENTITY_COMMON_SCHEMA,
MqttEntity,
async_setup_entry_helper,
async_setup_platform_helper,
)
DEFAULT_NAME = "MQTT Camera" DEFAULT_NAME = "MQTT Camera"
@ -49,8 +53,9 @@ async def async_setup_platform(
discovery_info: DiscoveryInfoType | None = None, discovery_info: DiscoveryInfoType | None = None,
) -> None: ) -> None:
"""Set up MQTT camera through configuration.yaml.""" """Set up MQTT camera through configuration.yaml."""
await async_setup_reload_service(hass, DOMAIN, PLATFORMS) await async_setup_platform_helper(
await _async_setup_entity(hass, async_add_entities, config) hass, camera.DOMAIN, config, async_add_entities, _async_setup_entity
)
async def async_setup_entry( async def async_setup_entry(

View file

@ -53,20 +53,23 @@ from homeassistant.const import (
from homeassistant.core import HomeAssistant, callback from homeassistant.core import HomeAssistant, callback
import homeassistant.helpers.config_validation as cv import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.reload import async_setup_reload_service
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
from . import ( from . import (
MQTT_BASE_PLATFORM_SCHEMA, MQTT_BASE_PLATFORM_SCHEMA,
PLATFORMS,
MqttCommandTemplate, MqttCommandTemplate,
MqttValueTemplate, MqttValueTemplate,
subscription, subscription,
) )
from .. import mqtt from .. import mqtt
from .const import CONF_ENCODING, CONF_QOS, CONF_RETAIN, DOMAIN, PAYLOAD_NONE from .const import CONF_ENCODING, CONF_QOS, CONF_RETAIN, PAYLOAD_NONE
from .debug_info import log_messages from .debug_info import log_messages
from .mixins import MQTT_ENTITY_COMMON_SCHEMA, MqttEntity, async_setup_entry_helper from .mixins import (
MQTT_ENTITY_COMMON_SCHEMA,
MqttEntity,
async_setup_entry_helper,
async_setup_platform_helper,
)
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@ -303,8 +306,9 @@ async def async_setup_platform(
discovery_info: DiscoveryInfoType | None = None, discovery_info: DiscoveryInfoType | None = None,
) -> None: ) -> None:
"""Set up MQTT climate device through configuration.yaml.""" """Set up MQTT climate device through configuration.yaml."""
await async_setup_reload_service(hass, DOMAIN, PLATFORMS) await async_setup_platform_helper(
await _async_setup_entity(hass, async_add_entities, config) hass, climate.DOMAIN, config, async_add_entities, _async_setup_entity
)
async def async_setup_entry( async def async_setup_entry(

View file

@ -84,17 +84,6 @@ class FlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
step_id="broker", data_schema=vol.Schema(fields), errors=errors step_id="broker", data_schema=vol.Schema(fields), errors=errors
) )
async def async_step_import(self, user_input):
"""Import a config entry.
Special type of import, we're not actually going to store any data.
Instead, we're going to rely on the values that are in config file.
"""
if self._async_current_entries():
return self.async_abort(reason="single_instance_allowed")
return self.async_create_entry(title="configuration.yaml", data={})
async def async_step_hassio(self, discovery_info: HassioServiceInfo) -> FlowResult: async def async_step_hassio(self, discovery_info: HassioServiceInfo) -> FlowResult:
"""Receive a Hass.io discovery.""" """Receive a Hass.io discovery."""
await self._async_handle_discovery_without_unique_id() await self._async_handle_discovery_without_unique_id()

View file

@ -23,6 +23,7 @@ CONF_TOPIC = "topic"
CONF_WILL_MESSAGE = "will_message" CONF_WILL_MESSAGE = "will_message"
DATA_MQTT_CONFIG = "mqtt_config" DATA_MQTT_CONFIG = "mqtt_config"
DATA_MQTT_RELOAD_NEEDED = "mqtt_reload_needed"
DEFAULT_PREFIX = "homeassistant" DEFAULT_PREFIX = "homeassistant"
DEFAULT_BIRTH_WILL_TOPIC = DEFAULT_PREFIX + "/status" DEFAULT_BIRTH_WILL_TOPIC = DEFAULT_PREFIX + "/status"

View file

@ -37,10 +37,9 @@ from homeassistant.const import (
from homeassistant.core import HomeAssistant, callback from homeassistant.core import HomeAssistant, callback
import homeassistant.helpers.config_validation as cv import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.reload import async_setup_reload_service
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
from . import PLATFORMS, MqttCommandTemplate, MqttValueTemplate, subscription from . import MqttCommandTemplate, MqttValueTemplate, subscription
from .. import mqtt from .. import mqtt
from .const import ( from .const import (
CONF_COMMAND_TOPIC, CONF_COMMAND_TOPIC,
@ -48,10 +47,14 @@ from .const import (
CONF_QOS, CONF_QOS,
CONF_RETAIN, CONF_RETAIN,
CONF_STATE_TOPIC, CONF_STATE_TOPIC,
DOMAIN,
) )
from .debug_info import log_messages from .debug_info import log_messages
from .mixins import MQTT_ENTITY_COMMON_SCHEMA, MqttEntity, async_setup_entry_helper from .mixins import (
MQTT_ENTITY_COMMON_SCHEMA,
MqttEntity,
async_setup_entry_helper,
async_setup_platform_helper,
)
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@ -217,8 +220,9 @@ async def async_setup_platform(
discovery_info: DiscoveryInfoType | None = None, discovery_info: DiscoveryInfoType | None = None,
) -> None: ) -> None:
"""Set up MQTT cover through configuration.yaml.""" """Set up MQTT cover through configuration.yaml."""
await async_setup_reload_service(hass, DOMAIN, PLATFORMS) await async_setup_platform_helper(
await _async_setup_entity(hass, async_add_entities, config) hass, cover.DOMAIN, config, async_add_entities, _async_setup_entity
)
async def async_setup_entry( async def async_setup_entry(

View file

@ -32,7 +32,6 @@ from homeassistant.const import (
from homeassistant.core import HomeAssistant, callback from homeassistant.core import HomeAssistant, callback
import homeassistant.helpers.config_validation as cv import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.reload import async_setup_reload_service
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
from homeassistant.util.percentage import ( from homeassistant.util.percentage import (
int_states_in_range, int_states_in_range,
@ -40,7 +39,7 @@ from homeassistant.util.percentage import (
ranged_value_to_percentage, ranged_value_to_percentage,
) )
from . import PLATFORMS, MqttCommandTemplate, MqttValueTemplate, subscription from . import MqttCommandTemplate, MqttValueTemplate, subscription
from .. import mqtt from .. import mqtt
from .const import ( from .const import (
CONF_COMMAND_TEMPLATE, CONF_COMMAND_TEMPLATE,
@ -50,11 +49,15 @@ from .const import (
CONF_RETAIN, CONF_RETAIN,
CONF_STATE_TOPIC, CONF_STATE_TOPIC,
CONF_STATE_VALUE_TEMPLATE, CONF_STATE_VALUE_TEMPLATE,
DOMAIN,
PAYLOAD_NONE, PAYLOAD_NONE,
) )
from .debug_info import log_messages from .debug_info import log_messages
from .mixins import MQTT_ENTITY_COMMON_SCHEMA, MqttEntity, async_setup_entry_helper from .mixins import (
MQTT_ENTITY_COMMON_SCHEMA,
MqttEntity,
async_setup_entry_helper,
async_setup_platform_helper,
)
CONF_PERCENTAGE_STATE_TOPIC = "percentage_state_topic" CONF_PERCENTAGE_STATE_TOPIC = "percentage_state_topic"
CONF_PERCENTAGE_COMMAND_TOPIC = "percentage_command_topic" CONF_PERCENTAGE_COMMAND_TOPIC = "percentage_command_topic"
@ -213,8 +216,9 @@ async def async_setup_platform(
discovery_info: DiscoveryInfoType | None = None, discovery_info: DiscoveryInfoType | None = None,
) -> None: ) -> None:
"""Set up MQTT fan through configuration.yaml.""" """Set up MQTT fan through configuration.yaml."""
await async_setup_reload_service(hass, DOMAIN, PLATFORMS) await async_setup_platform_helper(
await _async_setup_entity(hass, async_add_entities, config) hass, fan.DOMAIN, config, async_add_entities, _async_setup_entity
)
async def async_setup_entry( async def async_setup_entry(

View file

@ -27,10 +27,9 @@ from homeassistant.const import (
from homeassistant.core import HomeAssistant, callback from homeassistant.core import HomeAssistant, callback
import homeassistant.helpers.config_validation as cv import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.reload import async_setup_reload_service
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
from . import PLATFORMS, MqttCommandTemplate, MqttValueTemplate, subscription from . import MqttCommandTemplate, MqttValueTemplate, subscription
from .. import mqtt from .. import mqtt
from .const import ( from .const import (
CONF_COMMAND_TEMPLATE, CONF_COMMAND_TEMPLATE,
@ -40,11 +39,15 @@ from .const import (
CONF_RETAIN, CONF_RETAIN,
CONF_STATE_TOPIC, CONF_STATE_TOPIC,
CONF_STATE_VALUE_TEMPLATE, CONF_STATE_VALUE_TEMPLATE,
DOMAIN,
PAYLOAD_NONE, PAYLOAD_NONE,
) )
from .debug_info import log_messages from .debug_info import log_messages
from .mixins import MQTT_ENTITY_COMMON_SCHEMA, MqttEntity, async_setup_entry_helper from .mixins import (
MQTT_ENTITY_COMMON_SCHEMA,
MqttEntity,
async_setup_entry_helper,
async_setup_platform_helper,
)
CONF_AVAILABLE_MODES_LIST = "modes" CONF_AVAILABLE_MODES_LIST = "modes"
CONF_DEVICE_CLASS = "device_class" CONF_DEVICE_CLASS = "device_class"
@ -157,8 +160,9 @@ async def async_setup_platform(
discovery_info: DiscoveryInfoType | None = None, discovery_info: DiscoveryInfoType | None = None,
) -> None: ) -> None:
"""Set up MQTT humidifier through configuration.yaml.""" """Set up MQTT humidifier through configuration.yaml."""
await async_setup_reload_service(hass, DOMAIN, PLATFORMS) await async_setup_platform_helper(
await _async_setup_entity(hass, async_add_entities, config) hass, humidifier.DOMAIN, config, async_add_entities, _async_setup_entity
)
async def async_setup_entry( async def async_setup_entry(

View file

@ -8,11 +8,9 @@ import voluptuous as vol
from homeassistant.components import light from homeassistant.components import light
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.reload import async_setup_reload_service
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
from .. import DOMAIN, PLATFORMS from ..mixins import async_setup_entry_helper, async_setup_platform_helper
from ..mixins import async_setup_entry_helper
from .schema import CONF_SCHEMA, MQTT_LIGHT_SCHEMA_SCHEMA from .schema import CONF_SCHEMA, MQTT_LIGHT_SCHEMA_SCHEMA
from .schema_basic import ( from .schema_basic import (
DISCOVERY_SCHEMA_BASIC, DISCOVERY_SCHEMA_BASIC,
@ -69,8 +67,9 @@ async def async_setup_platform(
discovery_info: DiscoveryInfoType | None = None, discovery_info: DiscoveryInfoType | None = None,
) -> None: ) -> None:
"""Set up MQTT light through configuration.yaml.""" """Set up MQTT light through configuration.yaml."""
await async_setup_reload_service(hass, DOMAIN, PLATFORMS) await async_setup_platform_helper(
await _async_setup_entity(hass, async_add_entities, config) hass, light.DOMAIN, config, async_add_entities, _async_setup_entity
)
async def async_setup_entry(hass, config_entry, async_add_entities): async def async_setup_entry(hass, config_entry, async_add_entities):

View file

@ -12,10 +12,9 @@ from homeassistant.const import CONF_NAME, CONF_OPTIMISTIC, CONF_VALUE_TEMPLATE
from homeassistant.core import HomeAssistant, callback from homeassistant.core import HomeAssistant, callback
import homeassistant.helpers.config_validation as cv import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.reload import async_setup_reload_service
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
from . import PLATFORMS, MqttValueTemplate, subscription from . import MqttValueTemplate, subscription
from .. import mqtt from .. import mqtt
from .const import ( from .const import (
CONF_COMMAND_TOPIC, CONF_COMMAND_TOPIC,
@ -23,10 +22,14 @@ from .const import (
CONF_QOS, CONF_QOS,
CONF_RETAIN, CONF_RETAIN,
CONF_STATE_TOPIC, CONF_STATE_TOPIC,
DOMAIN,
) )
from .debug_info import log_messages from .debug_info import log_messages
from .mixins import MQTT_ENTITY_COMMON_SCHEMA, MqttEntity, async_setup_entry_helper from .mixins import (
MQTT_ENTITY_COMMON_SCHEMA,
MqttEntity,
async_setup_entry_helper,
async_setup_platform_helper,
)
CONF_PAYLOAD_LOCK = "payload_lock" CONF_PAYLOAD_LOCK = "payload_lock"
CONF_PAYLOAD_UNLOCK = "payload_unlock" CONF_PAYLOAD_UNLOCK = "payload_unlock"
@ -73,8 +76,9 @@ async def async_setup_platform(
discovery_info: DiscoveryInfoType | None = None, discovery_info: DiscoveryInfoType | None = None,
) -> None: ) -> None:
"""Set up MQTT lock panel through configuration.yaml.""" """Set up MQTT lock panel through configuration.yaml."""
await async_setup_reload_service(hass, DOMAIN, PLATFORMS) await async_setup_platform_helper(
await _async_setup_entity(hass, async_add_entities, config) hass, lock.DOMAIN, config, async_add_entities, _async_setup_entity
)
async def async_setup_entry( async def async_setup_entry(

View file

@ -5,9 +5,11 @@ from abc import abstractmethod
from collections.abc import Callable from collections.abc import Callable
import json import json
import logging import logging
from typing import Any, Protocol
import voluptuous as vol import voluptuous as vol
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import ( from homeassistant.const import (
ATTR_CONFIGURATION_URL, ATTR_CONFIGURATION_URL,
ATTR_MANUFACTURER, ATTR_MANUFACTURER,
@ -23,7 +25,7 @@ from homeassistant.const import (
CONF_UNIQUE_ID, CONF_UNIQUE_ID,
CONF_VALUE_TEMPLATE, CONF_VALUE_TEMPLATE,
) )
from homeassistant.core import callback from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers import ( from homeassistant.helpers import (
config_validation as cv, config_validation as cv,
device_registry as dr, device_registry as dr,
@ -40,9 +42,18 @@ from homeassistant.helpers.entity import (
async_generate_entity_id, async_generate_entity_id,
validate_entity_category, validate_entity_category,
) )
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.reload import async_setup_reload_service
from homeassistant.helpers.typing import ConfigType from homeassistant.helpers.typing import ConfigType
from . import DATA_MQTT, MqttValueTemplate, async_publish, debug_info, subscription from . import (
DATA_MQTT,
PLATFORMS,
MqttValueTemplate,
async_publish,
debug_info,
subscription,
)
from .const import ( from .const import (
ATTR_DISCOVERY_HASH, ATTR_DISCOVERY_HASH,
ATTR_DISCOVERY_PAYLOAD, ATTR_DISCOVERY_PAYLOAD,
@ -51,6 +62,7 @@ from .const import (
CONF_ENCODING, CONF_ENCODING,
CONF_QOS, CONF_QOS,
CONF_TOPIC, CONF_TOPIC,
DATA_MQTT_RELOAD_NEEDED,
DEFAULT_ENCODING, DEFAULT_ENCODING,
DEFAULT_PAYLOAD_AVAILABLE, DEFAULT_PAYLOAD_AVAILABLE,
DEFAULT_PAYLOAD_NOT_AVAILABLE, DEFAULT_PAYLOAD_NOT_AVAILABLE,
@ -210,6 +222,20 @@ MQTT_ENTITY_COMMON_SCHEMA = MQTT_AVAILABILITY_SCHEMA.extend(
) )
class SetupEntity(Protocol):
"""Protocol type for async_setup_entities."""
async def __call__(
self,
hass: HomeAssistant,
async_add_entities: AddEntitiesCallback,
config: ConfigType,
config_entry: ConfigEntry | None = None,
discovery_data: dict[str, Any] | None = None,
) -> None:
"""Define setup_entities type."""
async def async_setup_entry_helper(hass, domain, async_setup, schema): async def async_setup_entry_helper(hass, domain, async_setup, schema):
"""Set up entity, automation or tag creation dynamically through MQTT discovery.""" """Set up entity, automation or tag creation dynamically through MQTT discovery."""
@ -232,6 +258,26 @@ async def async_setup_entry_helper(hass, domain, async_setup, schema):
) )
async def async_setup_platform_helper(
hass: HomeAssistant,
platform_domain: str,
config: ConfigType,
async_add_entities: AddEntitiesCallback,
async_setup_entities: SetupEntity,
) -> None:
"""Return true if platform setup should be aborted."""
await async_setup_reload_service(hass, DOMAIN, PLATFORMS)
if not bool(hass.config_entries.async_entries(DOMAIN)):
hass.data[DATA_MQTT_RELOAD_NEEDED] = None
_LOGGER.warning(
"MQTT integration is not setup, skipping setup of manually configured "
"MQTT %s",
platform_domain,
)
return
await async_setup_entities(hass, async_add_entities, config)
def init_entity_id_from_config(hass, entity, config, entity_id_format): def init_entity_id_from_config(hass, entity, config, entity_id_format):
"""Set entity_id from object_id if defined in config.""" """Set entity_id from object_id if defined in config."""
if CONF_OBJECT_ID in config: if CONF_OBJECT_ID in config:

View file

@ -23,11 +23,10 @@ from homeassistant.const import (
from homeassistant.core import HomeAssistant, callback from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers import config_validation as cv from homeassistant.helpers import config_validation as cv
from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.reload import async_setup_reload_service
from homeassistant.helpers.restore_state import RestoreEntity from homeassistant.helpers.restore_state import RestoreEntity
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
from . import PLATFORMS, MqttCommandTemplate, MqttValueTemplate, subscription from . import MqttCommandTemplate, MqttValueTemplate, subscription
from .. import mqtt from .. import mqtt
from .const import ( from .const import (
CONF_COMMAND_TEMPLATE, CONF_COMMAND_TEMPLATE,
@ -36,10 +35,14 @@ from .const import (
CONF_QOS, CONF_QOS,
CONF_RETAIN, CONF_RETAIN,
CONF_STATE_TOPIC, CONF_STATE_TOPIC,
DOMAIN,
) )
from .debug_info import log_messages from .debug_info import log_messages
from .mixins import MQTT_ENTITY_COMMON_SCHEMA, MqttEntity, async_setup_entry_helper from .mixins import (
MQTT_ENTITY_COMMON_SCHEMA,
MqttEntity,
async_setup_entry_helper,
async_setup_platform_helper,
)
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@ -103,8 +106,9 @@ async def async_setup_platform(
discovery_info: DiscoveryInfoType | None = None, discovery_info: DiscoveryInfoType | None = None,
) -> None: ) -> None:
"""Set up MQTT number through configuration.yaml.""" """Set up MQTT number through configuration.yaml."""
await async_setup_reload_service(hass, DOMAIN, PLATFORMS) await async_setup_platform_helper(
await _async_setup_entity(hass, async_add_entities, config) hass, number.DOMAIN, config, async_add_entities, _async_setup_entity
)
async def async_setup_entry( async def async_setup_entry(

View file

@ -12,18 +12,17 @@ from homeassistant.const import CONF_ICON, CONF_NAME, CONF_PAYLOAD_ON, CONF_UNIQ
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
import homeassistant.helpers.config_validation as cv import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.reload import async_setup_reload_service
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
from . import PLATFORMS
from .. import mqtt from .. import mqtt
from .const import CONF_COMMAND_TOPIC, CONF_ENCODING, CONF_QOS, CONF_RETAIN, DOMAIN from .const import CONF_COMMAND_TOPIC, CONF_ENCODING, CONF_QOS, CONF_RETAIN
from .mixins import ( from .mixins import (
CONF_OBJECT_ID, CONF_OBJECT_ID,
MQTT_AVAILABILITY_SCHEMA, MQTT_AVAILABILITY_SCHEMA,
MqttAvailability, MqttAvailability,
MqttDiscoveryUpdate, MqttDiscoveryUpdate,
async_setup_entry_helper, async_setup_entry_helper,
async_setup_platform_helper,
init_entity_id_from_config, init_entity_id_from_config,
) )
@ -52,8 +51,9 @@ async def async_setup_platform(
discovery_info: DiscoveryInfoType | None = None, discovery_info: DiscoveryInfoType | None = None,
) -> None: ) -> None:
"""Set up MQTT scene through configuration.yaml.""" """Set up MQTT scene through configuration.yaml."""
await async_setup_reload_service(hass, DOMAIN, PLATFORMS) await async_setup_platform_helper(
await _async_setup_entity(hass, async_add_entities, config) hass, scene.DOMAIN, config, async_add_entities, _async_setup_entity
)
async def async_setup_entry( async def async_setup_entry(

View file

@ -13,11 +13,10 @@ from homeassistant.const import CONF_NAME, CONF_OPTIMISTIC, CONF_VALUE_TEMPLATE
from homeassistant.core import HomeAssistant, callback from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers import config_validation as cv from homeassistant.helpers import config_validation as cv
from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.reload import async_setup_reload_service
from homeassistant.helpers.restore_state import RestoreEntity from homeassistant.helpers.restore_state import RestoreEntity
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
from . import PLATFORMS, MqttCommandTemplate, MqttValueTemplate, subscription from . import MqttCommandTemplate, MqttValueTemplate, subscription
from .. import mqtt from .. import mqtt
from .const import ( from .const import (
CONF_COMMAND_TEMPLATE, CONF_COMMAND_TEMPLATE,
@ -26,10 +25,14 @@ from .const import (
CONF_QOS, CONF_QOS,
CONF_RETAIN, CONF_RETAIN,
CONF_STATE_TOPIC, CONF_STATE_TOPIC,
DOMAIN,
) )
from .debug_info import log_messages from .debug_info import log_messages
from .mixins import MQTT_ENTITY_COMMON_SCHEMA, MqttEntity, async_setup_entry_helper from .mixins import (
MQTT_ENTITY_COMMON_SCHEMA,
MqttEntity,
async_setup_entry_helper,
async_setup_platform_helper,
)
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@ -67,8 +70,9 @@ async def async_setup_platform(
discovery_info: DiscoveryInfoType | None = None, discovery_info: DiscoveryInfoType | None = None,
) -> None: ) -> None:
"""Set up MQTT select through configuration.yaml.""" """Set up MQTT select through configuration.yaml."""
await async_setup_reload_service(hass, DOMAIN, PLATFORMS) await async_setup_platform_helper(
await _async_setup_entity(hass, async_add_entities, config) hass, select.DOMAIN, config, async_add_entities, _async_setup_entity
)
async def async_setup_entry( async def async_setup_entry(

View file

@ -30,20 +30,20 @@ from homeassistant.core import HomeAssistant, callback
import homeassistant.helpers.config_validation as cv import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.event import async_track_point_in_utc_time from homeassistant.helpers.event import async_track_point_in_utc_time
from homeassistant.helpers.reload import async_setup_reload_service
from homeassistant.helpers.restore_state import RestoreEntity from homeassistant.helpers.restore_state import RestoreEntity
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
from homeassistant.util import dt as dt_util from homeassistant.util import dt as dt_util
from . import PLATFORMS, MqttValueTemplate, subscription from . import MqttValueTemplate, subscription
from .. import mqtt from .. import mqtt
from .const import CONF_ENCODING, CONF_QOS, CONF_STATE_TOPIC, DOMAIN from .const import CONF_ENCODING, CONF_QOS, CONF_STATE_TOPIC
from .debug_info import log_messages from .debug_info import log_messages
from .mixins import ( from .mixins import (
MQTT_ENTITY_COMMON_SCHEMA, MQTT_ENTITY_COMMON_SCHEMA,
MqttAvailability, MqttAvailability,
MqttEntity, MqttEntity,
async_setup_entry_helper, async_setup_entry_helper,
async_setup_platform_helper,
) )
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@ -120,8 +120,9 @@ async def async_setup_platform(
discovery_info: DiscoveryInfoType | None = None, discovery_info: DiscoveryInfoType | None = None,
) -> None: ) -> None:
"""Set up MQTT sensors through configuration.yaml.""" """Set up MQTT sensors through configuration.yaml."""
await async_setup_reload_service(hass, DOMAIN, PLATFORMS) await async_setup_platform_helper(
await _async_setup_entity(hass, async_add_entities, config) hass, sensor.DOMAIN, config, async_add_entities, _async_setup_entity
)
async def async_setup_entry( async def async_setup_entry(

View file

@ -36,10 +36,9 @@ from homeassistant.const import (
from homeassistant.core import HomeAssistant, callback from homeassistant.core import HomeAssistant, callback
import homeassistant.helpers.config_validation as cv import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.reload import async_setup_reload_service
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
from . import PLATFORMS, MqttCommandTemplate, MqttValueTemplate, subscription from . import MqttCommandTemplate, MqttValueTemplate, subscription
from .. import mqtt from .. import mqtt
from .const import ( from .const import (
CONF_COMMAND_TEMPLATE, CONF_COMMAND_TEMPLATE,
@ -49,12 +48,16 @@ from .const import (
CONF_RETAIN, CONF_RETAIN,
CONF_STATE_TOPIC, CONF_STATE_TOPIC,
CONF_STATE_VALUE_TEMPLATE, CONF_STATE_VALUE_TEMPLATE,
DOMAIN,
PAYLOAD_EMPTY_JSON, PAYLOAD_EMPTY_JSON,
PAYLOAD_NONE, PAYLOAD_NONE,
) )
from .debug_info import log_messages from .debug_info import log_messages
from .mixins import MQTT_ENTITY_COMMON_SCHEMA, MqttEntity, async_setup_entry_helper from .mixins import (
MQTT_ENTITY_COMMON_SCHEMA,
MqttEntity,
async_setup_entry_helper,
async_setup_platform_helper,
)
DEFAULT_NAME = "MQTT Siren" DEFAULT_NAME = "MQTT Siren"
DEFAULT_PAYLOAD_ON = "ON" DEFAULT_PAYLOAD_ON = "ON"
@ -118,8 +121,9 @@ async def async_setup_platform(
discovery_info: DiscoveryInfoType | None = None, discovery_info: DiscoveryInfoType | None = None,
) -> None: ) -> None:
"""Set up MQTT siren through configuration.yaml.""" """Set up MQTT siren through configuration.yaml."""
await async_setup_reload_service(hass, DOMAIN, PLATFORMS) await async_setup_platform_helper(
await _async_setup_entity(hass, async_add_entities, config) hass, siren.DOMAIN, config, async_add_entities, _async_setup_entity
)
async def async_setup_entry( async def async_setup_entry(

View file

@ -20,11 +20,10 @@ from homeassistant.const import (
from homeassistant.core import HomeAssistant, callback from homeassistant.core import HomeAssistant, callback
import homeassistant.helpers.config_validation as cv import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.reload import async_setup_reload_service
from homeassistant.helpers.restore_state import RestoreEntity from homeassistant.helpers.restore_state import RestoreEntity
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
from . import PLATFORMS, MqttValueTemplate, subscription from . import MqttValueTemplate, subscription
from .. import mqtt from .. import mqtt
from .const import ( from .const import (
CONF_COMMAND_TOPIC, CONF_COMMAND_TOPIC,
@ -32,11 +31,15 @@ from .const import (
CONF_QOS, CONF_QOS,
CONF_RETAIN, CONF_RETAIN,
CONF_STATE_TOPIC, CONF_STATE_TOPIC,
DOMAIN,
PAYLOAD_NONE, PAYLOAD_NONE,
) )
from .debug_info import log_messages from .debug_info import log_messages
from .mixins import MQTT_ENTITY_COMMON_SCHEMA, MqttEntity, async_setup_entry_helper from .mixins import (
MQTT_ENTITY_COMMON_SCHEMA,
MqttEntity,
async_setup_entry_helper,
async_setup_platform_helper,
)
MQTT_SWITCH_ATTRIBUTES_BLOCKED = frozenset( MQTT_SWITCH_ATTRIBUTES_BLOCKED = frozenset(
{ {
@ -75,8 +78,9 @@ async def async_setup_platform(
discovery_info: DiscoveryInfoType | None = None, discovery_info: DiscoveryInfoType | None = None,
) -> None: ) -> None:
"""Set up MQTT switch through configuration.yaml.""" """Set up MQTT switch through configuration.yaml."""
await async_setup_reload_service(hass, DOMAIN, PLATFORMS) await async_setup_platform_helper(
await _async_setup_entity(hass, async_add_entities, config) hass, switch.DOMAIN, config, async_add_entities, _async_setup_entity
)
async def async_setup_entry( async def async_setup_entry(

View file

@ -3,11 +3,9 @@ import functools
import voluptuous as vol import voluptuous as vol
from homeassistant.components.vacuum import DOMAIN from homeassistant.components import vacuum
from homeassistant.helpers.reload import async_setup_reload_service
from .. import DOMAIN as MQTT_DOMAIN, PLATFORMS from ..mixins import async_setup_entry_helper, async_setup_platform_helper
from ..mixins import async_setup_entry_helper
from .schema import CONF_SCHEMA, LEGACY, MQTT_VACUUM_SCHEMA, STATE from .schema import CONF_SCHEMA, LEGACY, MQTT_VACUUM_SCHEMA, STATE
from .schema_legacy import ( from .schema_legacy import (
DISCOVERY_SCHEMA_LEGACY, DISCOVERY_SCHEMA_LEGACY,
@ -44,8 +42,9 @@ PLATFORM_SCHEMA = vol.All(
async def async_setup_platform(hass, config, async_add_entities, discovery_info=None): async def async_setup_platform(hass, config, async_add_entities, discovery_info=None):
"""Set up MQTT vacuum through configuration.yaml.""" """Set up MQTT vacuum through configuration.yaml."""
await async_setup_reload_service(hass, MQTT_DOMAIN, PLATFORMS) await async_setup_platform_helper(
await _async_setup_entity(hass, async_add_entities, config) hass, vacuum.DOMAIN, config, async_add_entities, _async_setup_entity
)
async def async_setup_entry(hass, config_entry, async_add_entities): async def async_setup_entry(hass, config_entry, async_add_entities):
@ -53,7 +52,7 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
setup = functools.partial( setup = functools.partial(
_async_setup_entity, hass, async_add_entities, config_entry=config_entry _async_setup_entity, hass, async_add_entities, config_entry=config_entry
) )
await async_setup_entry_helper(hass, DOMAIN, setup, DISCOVERY_SCHEMA) await async_setup_entry_helper(hass, vacuum.DOMAIN, setup, DISCOVERY_SCHEMA)
async def _async_setup_entity( async def _async_setup_entity(

View file

@ -53,6 +53,7 @@ from .test_common import (
help_test_entity_id_update_subscriptions, help_test_entity_id_update_subscriptions,
help_test_publishing_with_custom_encoding, help_test_publishing_with_custom_encoding,
help_test_reloadable, help_test_reloadable,
help_test_reloadable_late,
help_test_setting_attribute_via_mqtt_json_message, help_test_setting_attribute_via_mqtt_json_message,
help_test_setting_attribute_with_template, help_test_setting_attribute_with_template,
help_test_setting_blocked_attribute_via_mqtt_json_message, help_test_setting_blocked_attribute_via_mqtt_json_message,
@ -840,3 +841,10 @@ async def test_reloadable(hass, mqtt_mock, caplog, tmp_path):
domain = alarm_control_panel.DOMAIN domain = alarm_control_panel.DOMAIN
config = DEFAULT_CONFIG[domain] config = DEFAULT_CONFIG[domain]
await help_test_reloadable(hass, mqtt_mock, caplog, tmp_path, domain, config) await help_test_reloadable(hass, mqtt_mock, caplog, tmp_path, domain, config)
async def test_reloadable_late(hass, mqtt_client_mock, caplog, tmp_path):
"""Test reloading the MQTT platform with late entry setup."""
domain = alarm_control_panel.DOMAIN
config = DEFAULT_CONFIG[domain]
await help_test_reloadable_late(hass, caplog, tmp_path, domain, config)

View file

@ -38,6 +38,7 @@ from .test_common import (
help_test_entity_id_update_subscriptions, help_test_entity_id_update_subscriptions,
help_test_reload_with_config, help_test_reload_with_config,
help_test_reloadable, help_test_reloadable,
help_test_reloadable_late,
help_test_setting_attribute_via_mqtt_json_message, help_test_setting_attribute_via_mqtt_json_message,
help_test_setting_attribute_with_template, help_test_setting_attribute_with_template,
help_test_unique_id, help_test_unique_id,
@ -879,6 +880,13 @@ async def test_reloadable(hass, mqtt_mock, caplog, tmp_path):
await help_test_reloadable(hass, mqtt_mock, caplog, tmp_path, domain, config) await help_test_reloadable(hass, mqtt_mock, caplog, tmp_path, domain, config)
async def test_reloadable_late(hass, mqtt_client_mock, caplog, tmp_path):
"""Test reloading the MQTT platform with late entry setup."""
domain = binary_sensor.DOMAIN
config = DEFAULT_CONFIG[domain]
await help_test_reloadable_late(hass, caplog, tmp_path, domain, config)
async def test_cleanup_triggers_and_restoring_state( async def test_cleanup_triggers_and_restoring_state(
hass, mqtt_mock, caplog, tmp_path, freezer hass, mqtt_mock, caplog, tmp_path, freezer
): ):

View file

@ -26,6 +26,7 @@ from .test_common import (
help_test_entity_id_update_discovery_update, help_test_entity_id_update_discovery_update,
help_test_publishing_with_custom_encoding, help_test_publishing_with_custom_encoding,
help_test_reloadable, help_test_reloadable,
help_test_reloadable_late,
help_test_setting_attribute_via_mqtt_json_message, help_test_setting_attribute_via_mqtt_json_message,
help_test_setting_attribute_with_template, help_test_setting_attribute_with_template,
help_test_setting_blocked_attribute_via_mqtt_json_message, help_test_setting_blocked_attribute_via_mqtt_json_message,
@ -405,3 +406,10 @@ async def test_reloadable(hass, mqtt_mock, caplog, tmp_path):
domain = button.DOMAIN domain = button.DOMAIN
config = DEFAULT_CONFIG[domain] config = DEFAULT_CONFIG[domain]
await help_test_reloadable(hass, mqtt_mock, caplog, tmp_path, domain, config) await help_test_reloadable(hass, mqtt_mock, caplog, tmp_path, domain, config)
async def test_reloadable_late(hass, mqtt_client_mock, caplog, tmp_path):
"""Test reloading the MQTT platform with late entry setup."""
domain = button.DOMAIN
config = DEFAULT_CONFIG[domain]
await help_test_reloadable_late(hass, caplog, tmp_path, domain, config)

View file

@ -27,6 +27,7 @@ from .test_common import (
help_test_entity_id_update_discovery_update, help_test_entity_id_update_discovery_update,
help_test_entity_id_update_subscriptions, help_test_entity_id_update_subscriptions,
help_test_reloadable, help_test_reloadable,
help_test_reloadable_late,
help_test_setting_attribute_via_mqtt_json_message, help_test_setting_attribute_via_mqtt_json_message,
help_test_setting_attribute_with_template, help_test_setting_attribute_with_template,
help_test_setting_blocked_attribute_via_mqtt_json_message, help_test_setting_blocked_attribute_via_mqtt_json_message,
@ -252,3 +253,10 @@ async def test_reloadable(hass, mqtt_mock, caplog, tmp_path):
domain = camera.DOMAIN domain = camera.DOMAIN
config = DEFAULT_CONFIG[domain] config = DEFAULT_CONFIG[domain]
await help_test_reloadable(hass, mqtt_mock, caplog, tmp_path, domain, config) await help_test_reloadable(hass, mqtt_mock, caplog, tmp_path, domain, config)
async def test_reloadable_late(hass, mqtt_client_mock, caplog, tmp_path):
"""Test reloading the MQTT platform with late entry setup."""
domain = camera.DOMAIN
config = DEFAULT_CONFIG[domain]
await help_test_reloadable_late(hass, caplog, tmp_path, domain, config)

View file

@ -58,6 +58,7 @@ from .test_common import (
help_test_entity_id_update_subscriptions, help_test_entity_id_update_subscriptions,
help_test_publishing_with_custom_encoding, help_test_publishing_with_custom_encoding,
help_test_reloadable, help_test_reloadable,
help_test_reloadable_late,
help_test_setting_attribute_via_mqtt_json_message, help_test_setting_attribute_via_mqtt_json_message,
help_test_setting_attribute_with_template, help_test_setting_attribute_with_template,
help_test_setting_blocked_attribute_via_mqtt_json_message, help_test_setting_blocked_attribute_via_mqtt_json_message,
@ -1422,3 +1423,10 @@ async def test_reloadable(hass, mqtt_mock, caplog, tmp_path):
domain = CLIMATE_DOMAIN domain = CLIMATE_DOMAIN
config = DEFAULT_CONFIG[domain] config = DEFAULT_CONFIG[domain]
await help_test_reloadable(hass, mqtt_mock, caplog, tmp_path, domain, config) await help_test_reloadable(hass, mqtt_mock, caplog, tmp_path, domain, config)
async def test_reloadable_late(hass, mqtt_client_mock, caplog, tmp_path):
"""Test reloading the MQTT platform with late entry setup."""
domain = CLIMATE_DOMAIN
config = DEFAULT_CONFIG[domain]
await help_test_reloadable_late(hass, caplog, tmp_path, domain, config)

View file

@ -21,7 +21,7 @@ from homeassistant.helpers import device_registry as dr, entity_registry as er
from homeassistant.helpers.dispatcher import async_dispatcher_send from homeassistant.helpers.dispatcher import async_dispatcher_send
from homeassistant.setup import async_setup_component from homeassistant.setup import async_setup_component
from tests.common import async_fire_mqtt_message, mock_registry from tests.common import MockConfigEntry, async_fire_mqtt_message, mock_registry
DEFAULT_CONFIG_DEVICE_INFO_ID = { DEFAULT_CONFIG_DEVICE_INFO_ID = {
"identifiers": ["helloworld"], "identifiers": ["helloworld"],
@ -1619,7 +1619,61 @@ async def help_test_reloadable(hass, mqtt_mock, caplog, tmp_path, domain, config
assert hass.states.get(f"{domain}.test_old_2") assert hass.states.get(f"{domain}.test_old_2")
assert len(hass.states.async_all(domain)) == 2 assert len(hass.states.async_all(domain)) == 2
# Create temporary fixture for configuration.yaml based on the supplied config and test a reload with this new config # Create temporary fixture for configuration.yaml based on the supplied config and
# test a reload with this new config
new_config_1 = copy.deepcopy(config)
new_config_1["name"] = "test_new_1"
new_config_2 = copy.deepcopy(config)
new_config_2["name"] = "test_new_2"
new_config_3 = copy.deepcopy(config)
new_config_3["name"] = "test_new_3"
await help_test_reload_with_config(
hass, caplog, tmp_path, domain, [new_config_1, new_config_2, new_config_3]
)
assert len(hass.states.async_all(domain)) == 3
assert hass.states.get(f"{domain}.test_new_1")
assert hass.states.get(f"{domain}.test_new_2")
assert hass.states.get(f"{domain}.test_new_3")
async def help_test_reloadable_late(hass, caplog, tmp_path, domain, config):
"""Test reloading an MQTT platform when config entry is setup late."""
# Create and test an old config of 2 entities based on the config supplied
old_config_1 = copy.deepcopy(config)
old_config_1["name"] = "test_old_1"
old_config_2 = copy.deepcopy(config)
old_config_2["name"] = "test_old_2"
old_yaml_config_file = tmp_path / "configuration.yaml"
old_yaml_config = yaml.dump({domain: [old_config_1, old_config_2]})
old_yaml_config_file.write_text(old_yaml_config)
assert old_yaml_config_file.read_text() == old_yaml_config
assert await async_setup_component(
hass, domain, {domain: [old_config_1, old_config_2]}
)
await hass.async_block_till_done()
# No MQTT config entry, there should be a warning and no entities
assert (
"MQTT integration is not setup, skipping setup of manually "
f"configured MQTT {domain}"
) in caplog.text
assert len(hass.states.async_all(domain)) == 0
# User sets up a config entry, should succeed and entities will setup
entry = MockConfigEntry(domain=mqtt.DOMAIN, data={mqtt.CONF_BROKER: "test-broker"})
entry.add_to_hass(hass)
with patch.object(hass_config, "YAML_CONFIG_FILE", old_yaml_config_file):
assert await hass.config_entries.async_setup(entry.entry_id)
await hass.async_block_till_done()
assert len(hass.states.async_all(domain)) == 2
# Create temporary fixture for configuration.yaml based on the supplied config and
# test a reload with this new config
new_config_1 = copy.deepcopy(config) new_config_1 = copy.deepcopy(config)
new_config_1["name"] = "test_new_1" new_config_1["name"] = "test_new_1"
new_config_2 = copy.deepcopy(config) new_config_2 = copy.deepcopy(config)

View file

@ -82,17 +82,34 @@ async def test_user_connection_fails(hass, mock_try_connection, mock_finish_setu
async def test_manual_config_set( async def test_manual_config_set(
hass, mock_try_connection, mock_finish_setup, mqtt_client_mock hass, mock_try_connection, mock_finish_setup, mqtt_client_mock
): ):
"""Test we ignore entry if manual config available.""" """Test manual config does not create an entry, and entry can be setup late."""
# MQTT config present in yaml config
assert await async_setup_component(hass, "mqtt", {"mqtt": {"broker": "bla"}}) assert await async_setup_component(hass, "mqtt", {"mqtt": {"broker": "bla"}})
await hass.async_block_till_done() await hass.async_block_till_done()
assert len(mock_finish_setup.mock_calls) == 1 assert len(mock_finish_setup.mock_calls) == 0
mock_try_connection.return_value = True mock_try_connection.return_value = True
# Start config flow
result = await hass.config_entries.flow.async_init( result = await hass.config_entries.flow.async_init(
"mqtt", context={"source": config_entries.SOURCE_USER} "mqtt", context={"source": config_entries.SOURCE_USER}
) )
assert result["type"] == "abort" assert result["type"] == "form"
result = await hass.config_entries.flow.async_configure(
result["flow_id"], {"broker": "127.0.0.1"}
)
assert result["type"] == "create_entry"
assert result["result"].data == {
"broker": "127.0.0.1",
"port": 1883,
"discovery": True,
}
# Check we tried the connection, with precedence for config entry settings
mock_try_connection.assert_called_once_with("127.0.0.1", 1883, None, None)
# Check config entry got setup
assert len(mock_finish_setup.mock_calls) == 1
async def test_user_single_instance(hass): async def test_user_single_instance(hass):

View file

@ -64,6 +64,7 @@ from .test_common import (
help_test_entity_id_update_subscriptions, help_test_entity_id_update_subscriptions,
help_test_publishing_with_custom_encoding, help_test_publishing_with_custom_encoding,
help_test_reloadable, help_test_reloadable,
help_test_reloadable_late,
help_test_setting_attribute_via_mqtt_json_message, help_test_setting_attribute_via_mqtt_json_message,
help_test_setting_attribute_with_template, help_test_setting_attribute_with_template,
help_test_setting_blocked_attribute_via_mqtt_json_message, help_test_setting_blocked_attribute_via_mqtt_json_message,
@ -3173,6 +3174,13 @@ async def test_reloadable(hass, mqtt_mock, caplog, tmp_path):
await help_test_reloadable(hass, mqtt_mock, caplog, tmp_path, domain, config) await help_test_reloadable(hass, mqtt_mock, caplog, tmp_path, domain, config)
async def test_reloadable_late(hass, mqtt_client_mock, caplog, tmp_path):
"""Test reloading the MQTT platform with late entry setup."""
domain = cover.DOMAIN
config = DEFAULT_CONFIG[domain]
await help_test_reloadable_late(hass, caplog, tmp_path, domain, config)
@pytest.mark.parametrize( @pytest.mark.parametrize(
"topic,value,attribute,attribute_value", "topic,value,attribute,attribute_value",
[ [

View file

@ -51,6 +51,7 @@ from .test_common import (
help_test_entity_id_update_subscriptions, help_test_entity_id_update_subscriptions,
help_test_publishing_with_custom_encoding, help_test_publishing_with_custom_encoding,
help_test_reloadable, help_test_reloadable,
help_test_reloadable_late,
help_test_setting_attribute_via_mqtt_json_message, help_test_setting_attribute_via_mqtt_json_message,
help_test_setting_attribute_with_template, help_test_setting_attribute_with_template,
help_test_setting_blocked_attribute_via_mqtt_json_message, help_test_setting_blocked_attribute_via_mqtt_json_message,
@ -1803,3 +1804,10 @@ async def test_reloadable(hass, mqtt_mock, caplog, tmp_path):
domain = fan.DOMAIN domain = fan.DOMAIN
config = DEFAULT_CONFIG[domain] config = DEFAULT_CONFIG[domain]
await help_test_reloadable(hass, mqtt_mock, caplog, tmp_path, domain, config) await help_test_reloadable(hass, mqtt_mock, caplog, tmp_path, domain, config)
async def test_reloadable_late(hass, mqtt_client_mock, caplog, tmp_path):
"""Test reloading the MQTT platform with late entry setup."""
domain = fan.DOMAIN
config = DEFAULT_CONFIG[domain]
await help_test_reloadable_late(hass, caplog, tmp_path, domain, config)

View file

@ -52,6 +52,7 @@ from .test_common import (
help_test_entity_id_update_subscriptions, help_test_entity_id_update_subscriptions,
help_test_publishing_with_custom_encoding, help_test_publishing_with_custom_encoding,
help_test_reloadable, help_test_reloadable,
help_test_reloadable_late,
help_test_setting_attribute_via_mqtt_json_message, help_test_setting_attribute_via_mqtt_json_message,
help_test_setting_attribute_with_template, help_test_setting_attribute_with_template,
help_test_setting_blocked_attribute_via_mqtt_json_message, help_test_setting_blocked_attribute_via_mqtt_json_message,
@ -1174,3 +1175,10 @@ async def test_reloadable(hass, mqtt_mock, caplog, tmp_path):
domain = humidifier.DOMAIN domain = humidifier.DOMAIN
config = DEFAULT_CONFIG[domain] config = DEFAULT_CONFIG[domain]
await help_test_reloadable(hass, mqtt_mock, caplog, tmp_path, domain, config) await help_test_reloadable(hass, mqtt_mock, caplog, tmp_path, domain, config)
async def test_reloadable_late(hass, mqtt_client_mock, caplog, tmp_path):
"""Test reloading the MQTT platform with late entry setup."""
domain = humidifier.DOMAIN
config = DEFAULT_CONFIG[domain]
await help_test_reloadable_late(hass, caplog, tmp_path, domain, config)

View file

@ -1134,6 +1134,8 @@ async def test_setup_without_tls_config_uses_tlsv1_under_python36(hass):
mqtt.CONF_BIRTH_MESSAGE: { mqtt.CONF_BIRTH_MESSAGE: {
mqtt.ATTR_TOPIC: "birth", mqtt.ATTR_TOPIC: "birth",
mqtt.ATTR_PAYLOAD: "birth", mqtt.ATTR_PAYLOAD: "birth",
mqtt.ATTR_QOS: 0,
mqtt.ATTR_RETAIN: False,
}, },
} }
], ],
@ -1162,6 +1164,8 @@ async def test_custom_birth_message(hass, mqtt_client_mock, mqtt_mock):
mqtt.CONF_BIRTH_MESSAGE: { mqtt.CONF_BIRTH_MESSAGE: {
mqtt.ATTR_TOPIC: "homeassistant/status", mqtt.ATTR_TOPIC: "homeassistant/status",
mqtt.ATTR_PAYLOAD: "online", mqtt.ATTR_PAYLOAD: "online",
mqtt.ATTR_QOS: 0,
mqtt.ATTR_RETAIN: False,
}, },
} }
], ],
@ -1205,6 +1209,8 @@ async def test_no_birth_message(hass, mqtt_client_mock, mqtt_mock):
mqtt.CONF_BIRTH_MESSAGE: { mqtt.CONF_BIRTH_MESSAGE: {
mqtt.ATTR_TOPIC: "homeassistant/status", mqtt.ATTR_TOPIC: "homeassistant/status",
mqtt.ATTR_PAYLOAD: "online", mqtt.ATTR_PAYLOAD: "online",
mqtt.ATTR_QOS: 0,
mqtt.ATTR_RETAIN: False,
}, },
} }
], ],
@ -1214,17 +1220,16 @@ async def test_delayed_birth_message(hass, mqtt_client_mock, mqtt_config):
hass.state = CoreState.starting hass.state = CoreState.starting
birth = asyncio.Event() birth = asyncio.Event()
result = await async_setup_component(hass, mqtt.DOMAIN, {mqtt.DOMAIN: mqtt_config})
assert result
await hass.async_block_till_done() await hass.async_block_till_done()
# Workaround: asynctest==0.13 fails on @functools.lru_cache entry = MockConfigEntry(domain=mqtt.DOMAIN, data=mqtt_config)
spec = dir(hass.data["mqtt"]) entry.add_to_hass(hass)
spec.remove("_matching_subscriptions") assert await hass.config_entries.async_setup(entry.entry_id)
await hass.async_block_till_done()
mqtt_component_mock = MagicMock( mqtt_component_mock = MagicMock(
return_value=hass.data["mqtt"], return_value=hass.data["mqtt"],
spec_set=spec, spec_set=hass.data["mqtt"],
wraps=hass.data["mqtt"], wraps=hass.data["mqtt"],
) )
mqtt_component_mock._mqttc = mqtt_client_mock mqtt_component_mock._mqttc = mqtt_client_mock
@ -1261,6 +1266,8 @@ async def test_delayed_birth_message(hass, mqtt_client_mock, mqtt_config):
mqtt.CONF_WILL_MESSAGE: { mqtt.CONF_WILL_MESSAGE: {
mqtt.ATTR_TOPIC: "death", mqtt.ATTR_TOPIC: "death",
mqtt.ATTR_PAYLOAD: "death", mqtt.ATTR_PAYLOAD: "death",
mqtt.ATTR_QOS: 0,
mqtt.ATTR_RETAIN: False,
}, },
} }
], ],
@ -1317,9 +1324,28 @@ async def test_mqtt_subscribes_topics_on_connect(hass, mqtt_client_mock, mqtt_mo
assert calls == expected assert calls == expected
async def test_setup_fails_without_config(hass): async def test_setup_entry_with_config_override(hass, device_reg, mqtt_client_mock):
"""Test if the MQTT component fails to load with no config.""" """Test if the MQTT component loads with no config and config entry can be setup."""
assert not await async_setup_component(hass, mqtt.DOMAIN, {}) data = (
'{ "device":{"identifiers":["0AFFD2"]},'
' "state_topic": "foobar/sensor",'
' "unique_id": "unique" }'
)
# mqtt present in yaml config
assert await async_setup_component(hass, mqtt.DOMAIN, {})
# User sets up a config entry
entry = MockConfigEntry(domain=mqtt.DOMAIN, data={mqtt.CONF_BROKER: "test-broker"})
entry.add_to_hass(hass)
assert await hass.config_entries.async_setup(entry.entry_id)
# Discover a device to verify the entry was setup correctly
async_fire_mqtt_message(hass, "homeassistant/sensor/bla/config", data)
await hass.async_block_till_done()
device_entry = device_reg.async_get_device({("mqtt", "0AFFD2")})
assert device_entry is not None
@pytest.mark.no_fail_on_log_exception @pytest.mark.no_fail_on_log_exception

View file

@ -51,6 +51,7 @@ from .test_common import (
help_test_entity_id_update_subscriptions, help_test_entity_id_update_subscriptions,
help_test_publishing_with_custom_encoding, help_test_publishing_with_custom_encoding,
help_test_reloadable, help_test_reloadable,
help_test_reloadable_late,
help_test_setting_attribute_via_mqtt_json_message, help_test_setting_attribute_via_mqtt_json_message,
help_test_setting_attribute_with_template, help_test_setting_attribute_with_template,
help_test_setting_blocked_attribute_via_mqtt_json_message, help_test_setting_blocked_attribute_via_mqtt_json_message,
@ -840,6 +841,13 @@ async def test_reloadable(hass, mqtt_mock, caplog, tmp_path):
await help_test_reloadable(hass, mqtt_mock, caplog, tmp_path, domain, config) await help_test_reloadable(hass, mqtt_mock, caplog, tmp_path, domain, config)
async def test_reloadable_late(hass, mqtt_client_mock, caplog, tmp_path):
"""Test reloading the MQTT platform with late entry setup."""
domain = vacuum.DOMAIN
config = DEFAULT_CONFIG
await help_test_reloadable_late(hass, caplog, tmp_path, domain, config)
@pytest.mark.parametrize( @pytest.mark.parametrize(
"topic,value,attribute,attribute_value", "topic,value,attribute,attribute_value",
[ [

View file

@ -202,6 +202,7 @@ from .test_common import (
help_test_entity_id_update_subscriptions, help_test_entity_id_update_subscriptions,
help_test_publishing_with_custom_encoding, help_test_publishing_with_custom_encoding,
help_test_reloadable, help_test_reloadable,
help_test_reloadable_late,
help_test_setting_attribute_via_mqtt_json_message, help_test_setting_attribute_via_mqtt_json_message,
help_test_setting_attribute_with_template, help_test_setting_attribute_with_template,
help_test_setting_blocked_attribute_via_mqtt_json_message, help_test_setting_blocked_attribute_via_mqtt_json_message,
@ -3496,6 +3497,13 @@ async def test_reloadable(hass, mqtt_mock, caplog, tmp_path):
await help_test_reloadable(hass, mqtt_mock, caplog, tmp_path, domain, config) await help_test_reloadable(hass, mqtt_mock, caplog, tmp_path, domain, config)
async def test_reloadable_late(hass, mqtt_client_mock, caplog, tmp_path):
"""Test reloading the MQTT platform with late entry setup."""
domain = light.DOMAIN
config = DEFAULT_CONFIG[domain]
await help_test_reloadable_late(hass, caplog, tmp_path, domain, config)
@pytest.mark.parametrize( @pytest.mark.parametrize(
"topic,value,attribute,attribute_value,init_payload", "topic,value,attribute,attribute_value,init_payload",
[ [

View file

@ -127,6 +127,7 @@ from .test_common import (
help_test_entity_id_update_subscriptions, help_test_entity_id_update_subscriptions,
help_test_publishing_with_custom_encoding, help_test_publishing_with_custom_encoding,
help_test_reloadable, help_test_reloadable,
help_test_reloadable_late,
help_test_setting_attribute_via_mqtt_json_message, help_test_setting_attribute_via_mqtt_json_message,
help_test_setting_attribute_with_template, help_test_setting_attribute_with_template,
help_test_setting_blocked_attribute_via_mqtt_json_message, help_test_setting_blocked_attribute_via_mqtt_json_message,
@ -1991,6 +1992,13 @@ async def test_reloadable(hass, mqtt_mock, caplog, tmp_path):
await help_test_reloadable(hass, mqtt_mock, caplog, tmp_path, domain, config) await help_test_reloadable(hass, mqtt_mock, caplog, tmp_path, domain, config)
async def test_reloadable_late(hass, mqtt_client_mock, caplog, tmp_path):
"""Test reloading the MQTT platform with late entry setup."""
domain = light.DOMAIN
config = DEFAULT_CONFIG[domain]
await help_test_reloadable_late(hass, caplog, tmp_path, domain, config)
@pytest.mark.parametrize( @pytest.mark.parametrize(
"topic,value,attribute,attribute_value,init_payload", "topic,value,attribute,attribute_value,init_payload",
[ [

View file

@ -65,6 +65,7 @@ from .test_common import (
help_test_entity_id_update_subscriptions, help_test_entity_id_update_subscriptions,
help_test_publishing_with_custom_encoding, help_test_publishing_with_custom_encoding,
help_test_reloadable, help_test_reloadable,
help_test_reloadable_late,
help_test_setting_attribute_via_mqtt_json_message, help_test_setting_attribute_via_mqtt_json_message,
help_test_setting_attribute_with_template, help_test_setting_attribute_with_template,
help_test_setting_blocked_attribute_via_mqtt_json_message, help_test_setting_blocked_attribute_via_mqtt_json_message,
@ -1181,6 +1182,13 @@ async def test_reloadable(hass, mqtt_mock, caplog, tmp_path):
await help_test_reloadable(hass, mqtt_mock, caplog, tmp_path, domain, config) await help_test_reloadable(hass, mqtt_mock, caplog, tmp_path, domain, config)
async def test_reloadable_late(hass, mqtt_client_mock, caplog, tmp_path):
"""Test reloading the MQTT platform with late entry setup."""
domain = light.DOMAIN
config = DEFAULT_CONFIG[domain]
await help_test_reloadable_late(hass, caplog, tmp_path, domain, config)
@pytest.mark.parametrize( @pytest.mark.parametrize(
"topic,value,attribute,attribute_value,init_payload", "topic,value,attribute,attribute_value,init_payload",
[ [

View file

@ -40,6 +40,7 @@ from .test_common import (
help_test_entity_id_update_subscriptions, help_test_entity_id_update_subscriptions,
help_test_publishing_with_custom_encoding, help_test_publishing_with_custom_encoding,
help_test_reloadable, help_test_reloadable,
help_test_reloadable_late,
help_test_setting_attribute_via_mqtt_json_message, help_test_setting_attribute_via_mqtt_json_message,
help_test_setting_attribute_with_template, help_test_setting_attribute_with_template,
help_test_setting_blocked_attribute_via_mqtt_json_message, help_test_setting_blocked_attribute_via_mqtt_json_message,
@ -646,6 +647,13 @@ async def test_reloadable(hass, mqtt_mock, caplog, tmp_path):
await help_test_reloadable(hass, mqtt_mock, caplog, tmp_path, domain, config) await help_test_reloadable(hass, mqtt_mock, caplog, tmp_path, domain, config)
async def test_reloadable_late(hass, mqtt_client_mock, caplog, tmp_path):
"""Test reloading the MQTT platform with late entry setup."""
domain = LOCK_DOMAIN
config = DEFAULT_CONFIG[domain]
await help_test_reloadable_late(hass, caplog, tmp_path, domain, config)
@pytest.mark.parametrize( @pytest.mark.parametrize(
"topic,value,attribute,attribute_value", "topic,value,attribute,attribute_value",
[ [

View file

@ -46,6 +46,7 @@ from .test_common import (
help_test_entity_id_update_subscriptions, help_test_entity_id_update_subscriptions,
help_test_publishing_with_custom_encoding, help_test_publishing_with_custom_encoding,
help_test_reloadable, help_test_reloadable,
help_test_reloadable_late,
help_test_setting_attribute_via_mqtt_json_message, help_test_setting_attribute_via_mqtt_json_message,
help_test_setting_attribute_with_template, help_test_setting_attribute_with_template,
help_test_setting_blocked_attribute_via_mqtt_json_message, help_test_setting_blocked_attribute_via_mqtt_json_message,
@ -699,6 +700,13 @@ async def test_reloadable(hass, mqtt_mock, caplog, tmp_path):
await help_test_reloadable(hass, mqtt_mock, caplog, tmp_path, domain, config) await help_test_reloadable(hass, mqtt_mock, caplog, tmp_path, domain, config)
async def test_reloadable_late(hass, mqtt_client_mock, caplog, tmp_path):
"""Test reloading the MQTT platform with late entry setup."""
domain = number.DOMAIN
config = DEFAULT_CONFIG[domain]
await help_test_reloadable_late(hass, caplog, tmp_path, domain, config)
@pytest.mark.parametrize( @pytest.mark.parametrize(
"topic,value,attribute,attribute_value", "topic,value,attribute,attribute_value",
[ [

View file

@ -19,6 +19,7 @@ from .test_common import (
help_test_discovery_update, help_test_discovery_update,
help_test_discovery_update_unchanged, help_test_discovery_update_unchanged,
help_test_reloadable, help_test_reloadable,
help_test_reloadable_late,
help_test_unique_id, help_test_unique_id,
) )
@ -183,3 +184,10 @@ async def test_reloadable(hass, mqtt_mock, caplog, tmp_path):
domain = scene.DOMAIN domain = scene.DOMAIN
config = DEFAULT_CONFIG[domain] config = DEFAULT_CONFIG[domain]
await help_test_reloadable(hass, mqtt_mock, caplog, tmp_path, domain, config) await help_test_reloadable(hass, mqtt_mock, caplog, tmp_path, domain, config)
async def test_reloadable_late(hass, mqtt_client_mock, caplog, tmp_path):
"""Test reloading the MQTT platform with late entry setup."""
domain = scene.DOMAIN
config = DEFAULT_CONFIG[domain]
await help_test_reloadable_late(hass, caplog, tmp_path, domain, config)

View file

@ -37,6 +37,7 @@ from .test_common import (
help_test_entity_id_update_subscriptions, help_test_entity_id_update_subscriptions,
help_test_publishing_with_custom_encoding, help_test_publishing_with_custom_encoding,
help_test_reloadable, help_test_reloadable,
help_test_reloadable_late,
help_test_setting_attribute_via_mqtt_json_message, help_test_setting_attribute_via_mqtt_json_message,
help_test_setting_attribute_with_template, help_test_setting_attribute_with_template,
help_test_setting_blocked_attribute_via_mqtt_json_message, help_test_setting_blocked_attribute_via_mqtt_json_message,
@ -578,6 +579,13 @@ async def test_reloadable(hass, mqtt_mock, caplog, tmp_path):
await help_test_reloadable(hass, mqtt_mock, caplog, tmp_path, domain, config) await help_test_reloadable(hass, mqtt_mock, caplog, tmp_path, domain, config)
async def test_reloadable_late(hass, mqtt_client_mock, caplog, tmp_path):
"""Test reloading the MQTT platform with late entry setup."""
domain = select.DOMAIN
config = DEFAULT_CONFIG[domain]
await help_test_reloadable_late(hass, caplog, tmp_path, domain, config)
@pytest.mark.parametrize( @pytest.mark.parametrize(
"topic,value,attribute,attribute_value", "topic,value,attribute,attribute_value",
[ [

View file

@ -45,6 +45,7 @@ from .test_common import (
help_test_entity_id_update_subscriptions, help_test_entity_id_update_subscriptions,
help_test_reload_with_config, help_test_reload_with_config,
help_test_reloadable, help_test_reloadable,
help_test_reloadable_late,
help_test_setting_attribute_via_mqtt_json_message, help_test_setting_attribute_via_mqtt_json_message,
help_test_setting_attribute_with_template, help_test_setting_attribute_with_template,
help_test_setting_blocked_attribute_via_mqtt_json_message, help_test_setting_blocked_attribute_via_mqtt_json_message,
@ -972,6 +973,13 @@ async def test_reloadable(hass, mqtt_mock, caplog, tmp_path):
await help_test_reloadable(hass, mqtt_mock, caplog, tmp_path, domain, config) await help_test_reloadable(hass, mqtt_mock, caplog, tmp_path, domain, config)
async def test_reloadable_late(hass, mqtt_client_mock, caplog, tmp_path):
"""Test reloading the MQTT platform with late entry setup."""
domain = sensor.DOMAIN
config = DEFAULT_CONFIG[domain]
await help_test_reloadable_late(hass, caplog, tmp_path, domain, config)
async def test_cleanup_triggers_and_restoring_state( async def test_cleanup_triggers_and_restoring_state(
hass, mqtt_mock, caplog, tmp_path, freezer hass, mqtt_mock, caplog, tmp_path, freezer
): ):

View file

@ -38,6 +38,7 @@ from .test_common import (
help_test_entity_id_update_subscriptions, help_test_entity_id_update_subscriptions,
help_test_publishing_with_custom_encoding, help_test_publishing_with_custom_encoding,
help_test_reloadable, help_test_reloadable,
help_test_reloadable_late,
help_test_setting_attribute_via_mqtt_json_message, help_test_setting_attribute_via_mqtt_json_message,
help_test_setting_attribute_with_template, help_test_setting_attribute_with_template,
help_test_setting_blocked_attribute_via_mqtt_json_message, help_test_setting_blocked_attribute_via_mqtt_json_message,
@ -866,6 +867,13 @@ async def test_reloadable(hass, mqtt_mock, caplog, tmp_path):
await help_test_reloadable(hass, mqtt_mock, caplog, tmp_path, domain, config) await help_test_reloadable(hass, mqtt_mock, caplog, tmp_path, domain, config)
async def test_reloadable_late(hass, mqtt_client_mock, caplog, tmp_path):
"""Test reloading the MQTT platform with late entry setup."""
domain = siren.DOMAIN
config = DEFAULT_CONFIG[domain]
await help_test_reloadable_late(hass, caplog, tmp_path, domain, config)
@pytest.mark.parametrize( @pytest.mark.parametrize(
"topic,value,attribute,attribute_value", "topic,value,attribute,attribute_value",
[ [

View file

@ -54,6 +54,7 @@ from .test_common import (
help_test_entity_id_update_subscriptions, help_test_entity_id_update_subscriptions,
help_test_publishing_with_custom_encoding, help_test_publishing_with_custom_encoding,
help_test_reloadable, help_test_reloadable,
help_test_reloadable_late,
help_test_setting_attribute_via_mqtt_json_message, help_test_setting_attribute_via_mqtt_json_message,
help_test_setting_attribute_with_template, help_test_setting_attribute_with_template,
help_test_setting_blocked_attribute_via_mqtt_json_message, help_test_setting_blocked_attribute_via_mqtt_json_message,
@ -607,6 +608,13 @@ async def test_reloadable(hass, mqtt_mock, caplog, tmp_path):
await help_test_reloadable(hass, mqtt_mock, caplog, tmp_path, domain, config) await help_test_reloadable(hass, mqtt_mock, caplog, tmp_path, domain, config)
async def test_reloadable_late(hass, mqtt_client_mock, caplog, tmp_path):
"""Test reloading the MQTT platform with late entry setup."""
domain = vacuum.DOMAIN
config = DEFAULT_CONFIG
await help_test_reloadable_late(hass, caplog, tmp_path, domain, config)
@pytest.mark.parametrize( @pytest.mark.parametrize(
"topic,value,attribute,attribute_value", "topic,value,attribute,attribute_value",
[ [

View file

@ -36,6 +36,7 @@ from .test_common import (
help_test_entity_id_update_subscriptions, help_test_entity_id_update_subscriptions,
help_test_publishing_with_custom_encoding, help_test_publishing_with_custom_encoding,
help_test_reloadable, help_test_reloadable,
help_test_reloadable_late,
help_test_setting_attribute_via_mqtt_json_message, help_test_setting_attribute_via_mqtt_json_message,
help_test_setting_attribute_with_template, help_test_setting_attribute_with_template,
help_test_setting_blocked_attribute_via_mqtt_json_message, help_test_setting_blocked_attribute_via_mqtt_json_message,
@ -557,6 +558,13 @@ async def test_reloadable(hass, mqtt_mock, caplog, tmp_path):
await help_test_reloadable(hass, mqtt_mock, caplog, tmp_path, domain, config) await help_test_reloadable(hass, mqtt_mock, caplog, tmp_path, domain, config)
async def test_reloadable_late(hass, mqtt_client_mock, caplog, tmp_path):
"""Test reloading the MQTT platform with late entry setup."""
domain = switch.DOMAIN
config = DEFAULT_CONFIG[domain]
await help_test_reloadable_late(hass, caplog, tmp_path, domain, config)
@pytest.mark.parametrize( @pytest.mark.parametrize(
"topic,value,attribute,attribute_value", "topic,value,attribute,attribute_value",
[ [

View file

@ -38,6 +38,7 @@ pytest.register_assert_rewrite("tests.common")
from tests.common import ( # noqa: E402, isort:skip from tests.common import ( # noqa: E402, isort:skip
CLIENT_ID, CLIENT_ID,
INSTANCES, INSTANCES,
MockConfigEntry,
MockUser, MockUser,
async_fire_mqtt_message, async_fire_mqtt_message,
async_test_home_assistant, async_test_home_assistant,
@ -590,17 +591,22 @@ async def mqtt_mock(hass, mqtt_client_mock, mqtt_config):
if mqtt_config is None: if mqtt_config is None:
mqtt_config = {mqtt.CONF_BROKER: "mock-broker", mqtt.CONF_BIRTH_MESSAGE: {}} mqtt_config = {mqtt.CONF_BROKER: "mock-broker", mqtt.CONF_BIRTH_MESSAGE: {}}
result = await async_setup_component(hass, mqtt.DOMAIN, {mqtt.DOMAIN: mqtt_config})
assert result
await hass.async_block_till_done() await hass.async_block_till_done()
# Workaround: asynctest==0.13 fails on @functools.lru_cache entry = MockConfigEntry(
spec = dir(hass.data["mqtt"]) data=mqtt_config,
spec.remove("_matching_subscriptions") domain=mqtt.DOMAIN,
title="Tasmota",
)
entry.add_to_hass(hass)
assert await hass.config_entries.async_setup(entry.entry_id)
await hass.async_block_till_done()
mqtt_component_mock = MagicMock( mqtt_component_mock = MagicMock(
return_value=hass.data["mqtt"], return_value=hass.data["mqtt"],
spec_set=spec, spec_set=hass.data["mqtt"],
wraps=hass.data["mqtt"], wraps=hass.data["mqtt"],
) )
mqtt_component_mock._mqttc = mqtt_client_mock mqtt_component_mock._mqttc = mqtt_client_mock