Move manual configuration of MQTT fan and light to the integration key (#71676)
* Processing yaml config through entry setup * Setup all platforms * Update homeassistant/components/mqtt/__init__.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * adjust mock_mqtt - reference config from cache * Fix test config entry override * Add tests yaml setup * additional tests * Introduce PLATFORM_SCHEMA_MODERN * recover temporary MQTT_BASE_PLATFORM_SCHEMA * Allow extra key in light base schema, restore test * Fix test for exception on platform key * One deprecation message per platform * Remove deprecation checks from modern schema * Update homeassistant/components/mqtt/fan.py Co-authored-by: Erik Montnemery <erik@montnemery.com> * Update homeassistant/components/mqtt/fan.py Co-authored-by: Erik Montnemery <erik@montnemery.com> * Update homeassistant/components/mqtt/light/__init__.py Co-authored-by: Erik Montnemery <erik@montnemery.com> * Update homeassistant/components/mqtt/light/__init__.py Co-authored-by: Erik Montnemery <erik@montnemery.com> * Update homeassistant/components/mqtt/light/schema_json.py Co-authored-by: Erik Montnemery <erik@montnemery.com> * Update homeassistant/components/mqtt/light/schema_template.py Co-authored-by: Erik Montnemery <erik@montnemery.com> * Update homeassistant/components/mqtt/mixins.py Co-authored-by: Erik Montnemery <erik@montnemery.com> * rename validate_modern_schema * Do not fail platform if a single config is broken * Update homeassistant/components/mqtt/__init__.py Co-authored-by: Erik Montnemery <erik@montnemery.com> * Fix tests on asserting log * Update log. Make helper transparant, remove patch * Perform parallel processing * Update tests/components/mqtt/test_init.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Apply suggestions from code review Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/mqtt/mixins.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * black * Fix tests and add #new_format anchor Co-authored-by: Martin Hjelmare <marhje52@gmail.com> Co-authored-by: Erik Montnemery <erik@montnemery.com>
This commit is contained in:
parent
9d377aabdb
commit
ed1c2ea2b8
16 changed files with 339 additions and 28 deletions
|
@ -81,6 +81,8 @@ from .const import (
|
||||||
CONF_TLS_VERSION,
|
CONF_TLS_VERSION,
|
||||||
CONF_TOPIC,
|
CONF_TOPIC,
|
||||||
CONF_WILL_MESSAGE,
|
CONF_WILL_MESSAGE,
|
||||||
|
CONFIG_ENTRY_IS_SETUP,
|
||||||
|
DATA_CONFIG_ENTRY_LOCK,
|
||||||
DATA_MQTT_CONFIG,
|
DATA_MQTT_CONFIG,
|
||||||
DATA_MQTT_RELOAD_NEEDED,
|
DATA_MQTT_RELOAD_NEEDED,
|
||||||
DEFAULT_BIRTH,
|
DEFAULT_BIRTH,
|
||||||
|
@ -171,7 +173,6 @@ PLATFORMS = [
|
||||||
Platform.VACUUM,
|
Platform.VACUUM,
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
CLIENT_KEY_AUTH_MSG = (
|
CLIENT_KEY_AUTH_MSG = (
|
||||||
"client_key and client_cert must both be present in "
|
"client_key and client_cert must both be present in "
|
||||||
"the MQTT broker configuration"
|
"the MQTT broker configuration"
|
||||||
|
@ -187,7 +188,14 @@ MQTT_WILL_BIRTH_SCHEMA = vol.Schema(
|
||||||
required=True,
|
required=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
CONFIG_SCHEMA_BASE = vol.Schema(
|
PLATFORM_CONFIG_SCHEMA_BASE = vol.Schema(
|
||||||
|
{
|
||||||
|
vol.Optional(Platform.FAN.value): cv.ensure_list,
|
||||||
|
vol.Optional(Platform.LIGHT.value): cv.ensure_list,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
CONFIG_SCHEMA_BASE = PLATFORM_CONFIG_SCHEMA_BASE.extend(
|
||||||
{
|
{
|
||||||
vol.Optional(CONF_CLIENT_ID): cv.string,
|
vol.Optional(CONF_CLIENT_ID): cv.string,
|
||||||
vol.Optional(CONF_KEEPALIVE, default=DEFAULT_KEEPALIVE): vol.All(
|
vol.Optional(CONF_KEEPALIVE, default=DEFAULT_KEEPALIVE): vol.All(
|
||||||
|
@ -253,10 +261,28 @@ SCHEMA_BASE = {
|
||||||
vol.Optional(CONF_ENCODING, default=DEFAULT_ENCODING): cv.string,
|
vol.Optional(CONF_ENCODING, default=DEFAULT_ENCODING): cv.string,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MQTT_BASE_SCHEMA = vol.Schema(SCHEMA_BASE)
|
||||||
|
|
||||||
|
# Will be removed when all platforms support a modern platform schema
|
||||||
MQTT_BASE_PLATFORM_SCHEMA = cv.PLATFORM_SCHEMA.extend(SCHEMA_BASE)
|
MQTT_BASE_PLATFORM_SCHEMA = cv.PLATFORM_SCHEMA.extend(SCHEMA_BASE)
|
||||||
|
# Will be removed when all platforms support a modern platform schema
|
||||||
|
MQTT_RO_PLATFORM_SCHEMA = MQTT_BASE_PLATFORM_SCHEMA.extend(
|
||||||
|
{
|
||||||
|
vol.Required(CONF_STATE_TOPIC): valid_subscribe_topic,
|
||||||
|
vol.Optional(CONF_VALUE_TEMPLATE): cv.template,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
# Will be removed when all platforms support a modern platform schema
|
||||||
|
MQTT_RW_PLATFORM_SCHEMA = MQTT_BASE_PLATFORM_SCHEMA.extend(
|
||||||
|
{
|
||||||
|
vol.Required(CONF_COMMAND_TOPIC): valid_publish_topic,
|
||||||
|
vol.Optional(CONF_RETAIN, default=DEFAULT_RETAIN): cv.boolean,
|
||||||
|
vol.Optional(CONF_STATE_TOPIC): valid_subscribe_topic,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
# Sensor type platforms subscribe to MQTT events
|
# Sensor type platforms subscribe to MQTT events
|
||||||
MQTT_RO_PLATFORM_SCHEMA = MQTT_BASE_PLATFORM_SCHEMA.extend(
|
MQTT_RO_SCHEMA = MQTT_BASE_SCHEMA.extend(
|
||||||
{
|
{
|
||||||
vol.Required(CONF_STATE_TOPIC): valid_subscribe_topic,
|
vol.Required(CONF_STATE_TOPIC): valid_subscribe_topic,
|
||||||
vol.Optional(CONF_VALUE_TEMPLATE): cv.template,
|
vol.Optional(CONF_VALUE_TEMPLATE): cv.template,
|
||||||
|
@ -264,7 +290,7 @@ MQTT_RO_PLATFORM_SCHEMA = MQTT_BASE_PLATFORM_SCHEMA.extend(
|
||||||
)
|
)
|
||||||
|
|
||||||
# Switch type platforms publish to MQTT and may subscribe
|
# Switch type platforms publish to MQTT and may subscribe
|
||||||
MQTT_RW_PLATFORM_SCHEMA = MQTT_BASE_PLATFORM_SCHEMA.extend(
|
MQTT_RW_SCHEMA = MQTT_BASE_SCHEMA.extend(
|
||||||
{
|
{
|
||||||
vol.Required(CONF_COMMAND_TOPIC): valid_publish_topic,
|
vol.Required(CONF_COMMAND_TOPIC): valid_publish_topic,
|
||||||
vol.Optional(CONF_RETAIN, default=DEFAULT_RETAIN): cv.boolean,
|
vol.Optional(CONF_RETAIN, default=DEFAULT_RETAIN): cv.boolean,
|
||||||
|
@ -774,6 +800,19 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# setup platforms and discovery
|
||||||
|
hass.data[DATA_CONFIG_ENTRY_LOCK] = asyncio.Lock()
|
||||||
|
hass.data[CONFIG_ENTRY_IS_SETUP] = set()
|
||||||
|
|
||||||
|
async with hass.data[DATA_CONFIG_ENTRY_LOCK]:
|
||||||
|
for component in PLATFORMS:
|
||||||
|
config_entries_key = f"{component}.mqtt"
|
||||||
|
if config_entries_key not in hass.data[CONFIG_ENTRY_IS_SETUP]:
|
||||||
|
hass.data[CONFIG_ENTRY_IS_SETUP].add(config_entries_key)
|
||||||
|
hass.async_create_task(
|
||||||
|
hass.config_entries.async_forward_entry_setup(entry, component)
|
||||||
|
)
|
||||||
|
|
||||||
if conf.get(CONF_DISCOVERY):
|
if conf.get(CONF_DISCOVERY):
|
||||||
await _async_setup_discovery(hass, conf, entry)
|
await _async_setup_discovery(hass, conf, entry)
|
||||||
|
|
||||||
|
|
|
@ -28,6 +28,8 @@ CONF_CLIENT_CERT = "client_cert"
|
||||||
CONF_TLS_INSECURE = "tls_insecure"
|
CONF_TLS_INSECURE = "tls_insecure"
|
||||||
CONF_TLS_VERSION = "tls_version"
|
CONF_TLS_VERSION = "tls_version"
|
||||||
|
|
||||||
|
CONFIG_ENTRY_IS_SETUP = "mqtt_config_entry_is_setup"
|
||||||
|
DATA_CONFIG_ENTRY_LOCK = "mqtt_config_entry_lock"
|
||||||
DATA_MQTT_CONFIG = "mqtt_config"
|
DATA_MQTT_CONFIG = "mqtt_config"
|
||||||
DATA_MQTT_RELOAD_NEEDED = "mqtt_reload_needed"
|
DATA_MQTT_RELOAD_NEEDED = "mqtt_reload_needed"
|
||||||
|
|
||||||
|
|
|
@ -27,6 +27,8 @@ from .const import (
|
||||||
ATTR_DISCOVERY_TOPIC,
|
ATTR_DISCOVERY_TOPIC,
|
||||||
CONF_AVAILABILITY,
|
CONF_AVAILABILITY,
|
||||||
CONF_TOPIC,
|
CONF_TOPIC,
|
||||||
|
CONFIG_ENTRY_IS_SETUP,
|
||||||
|
DATA_CONFIG_ENTRY_LOCK,
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -62,8 +64,6 @@ SUPPORTED_COMPONENTS = [
|
||||||
|
|
||||||
ALREADY_DISCOVERED = "mqtt_discovered_components"
|
ALREADY_DISCOVERED = "mqtt_discovered_components"
|
||||||
PENDING_DISCOVERED = "mqtt_pending_components"
|
PENDING_DISCOVERED = "mqtt_pending_components"
|
||||||
CONFIG_ENTRY_IS_SETUP = "mqtt_config_entry_is_setup"
|
|
||||||
DATA_CONFIG_ENTRY_LOCK = "mqtt_config_entry_lock"
|
|
||||||
DATA_CONFIG_FLOW_LOCK = "mqtt_discovery_config_flow_lock"
|
DATA_CONFIG_FLOW_LOCK = "mqtt_discovery_config_flow_lock"
|
||||||
DISCOVERY_UNSUBSCRIBE = "mqtt_discovery_unsubscribe"
|
DISCOVERY_UNSUBSCRIBE = "mqtt_discovery_unsubscribe"
|
||||||
INTEGRATION_UNSUBSCRIBE = "mqtt_integration_discovery_unsubscribe"
|
INTEGRATION_UNSUBSCRIBE = "mqtt_integration_discovery_unsubscribe"
|
||||||
|
@ -258,9 +258,7 @@ async def async_start( # noqa: C901
|
||||||
hass, MQTT_DISCOVERY_DONE.format(discovery_hash), None
|
hass, MQTT_DISCOVERY_DONE.format(discovery_hash), None
|
||||||
)
|
)
|
||||||
|
|
||||||
hass.data[DATA_CONFIG_ENTRY_LOCK] = asyncio.Lock()
|
|
||||||
hass.data[DATA_CONFIG_FLOW_LOCK] = asyncio.Lock()
|
hass.data[DATA_CONFIG_FLOW_LOCK] = asyncio.Lock()
|
||||||
hass.data[CONFIG_ENTRY_IS_SETUP] = set()
|
|
||||||
|
|
||||||
hass.data[ALREADY_DISCOVERED] = {}
|
hass.data[ALREADY_DISCOVERED] = {}
|
||||||
hass.data[PENDING_DISCOVERED] = {}
|
hass.data[PENDING_DISCOVERED] = {}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
"""Support for MQTT fans."""
|
"""Support for MQTT fans."""
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import asyncio
|
||||||
import functools
|
import functools
|
||||||
import logging
|
import logging
|
||||||
import math
|
import math
|
||||||
|
@ -49,8 +50,10 @@ from .debug_info import log_messages
|
||||||
from .mixins import (
|
from .mixins import (
|
||||||
MQTT_ENTITY_COMMON_SCHEMA,
|
MQTT_ENTITY_COMMON_SCHEMA,
|
||||||
MqttEntity,
|
MqttEntity,
|
||||||
|
async_get_platform_config_from_yaml,
|
||||||
async_setup_entry_helper,
|
async_setup_entry_helper,
|
||||||
async_setup_platform_helper,
|
async_setup_platform_helper,
|
||||||
|
warn_for_legacy_schema,
|
||||||
)
|
)
|
||||||
|
|
||||||
CONF_PERCENTAGE_STATE_TOPIC = "percentage_state_topic"
|
CONF_PERCENTAGE_STATE_TOPIC = "percentage_state_topic"
|
||||||
|
@ -122,7 +125,7 @@ def valid_preset_mode_configuration(config):
|
||||||
return config
|
return config
|
||||||
|
|
||||||
|
|
||||||
_PLATFORM_SCHEMA_BASE = mqtt.MQTT_RW_PLATFORM_SCHEMA.extend(
|
_PLATFORM_SCHEMA_BASE = mqtt.MQTT_RW_SCHEMA.extend(
|
||||||
{
|
{
|
||||||
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
|
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
|
||||||
vol.Optional(CONF_OPTIMISTIC, default=DEFAULT_OPTIMISTIC): cv.boolean,
|
vol.Optional(CONF_OPTIMISTIC, default=DEFAULT_OPTIMISTIC): cv.boolean,
|
||||||
|
@ -172,7 +175,15 @@ _PLATFORM_SCHEMA_BASE = mqtt.MQTT_RW_PLATFORM_SCHEMA.extend(
|
||||||
}
|
}
|
||||||
).extend(MQTT_ENTITY_COMMON_SCHEMA.schema)
|
).extend(MQTT_ENTITY_COMMON_SCHEMA.schema)
|
||||||
|
|
||||||
|
# Configuring MQTT Fans under the fan platform key is deprecated in HA Core 2022.6
|
||||||
PLATFORM_SCHEMA = vol.All(
|
PLATFORM_SCHEMA = vol.All(
|
||||||
|
cv.PLATFORM_SCHEMA.extend(_PLATFORM_SCHEMA_BASE.schema),
|
||||||
|
valid_speed_range_configuration,
|
||||||
|
valid_preset_mode_configuration,
|
||||||
|
warn_for_legacy_schema(fan.DOMAIN),
|
||||||
|
)
|
||||||
|
|
||||||
|
PLATFORM_SCHEMA_MODERN = vol.All(
|
||||||
_PLATFORM_SCHEMA_BASE,
|
_PLATFORM_SCHEMA_BASE,
|
||||||
valid_speed_range_configuration,
|
valid_speed_range_configuration,
|
||||||
valid_preset_mode_configuration,
|
valid_preset_mode_configuration,
|
||||||
|
@ -201,7 +212,8 @@ async def async_setup_platform(
|
||||||
async_add_entities: AddEntitiesCallback,
|
async_add_entities: AddEntitiesCallback,
|
||||||
discovery_info: DiscoveryInfoType | None = None,
|
discovery_info: DiscoveryInfoType | None = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Set up MQTT fan through configuration.yaml."""
|
"""Set up MQTT fans configured under the fan platform key (deprecated)."""
|
||||||
|
# Deprecated in HA Core 2022.6
|
||||||
await async_setup_platform_helper(
|
await async_setup_platform_helper(
|
||||||
hass, fan.DOMAIN, config, async_add_entities, _async_setup_entity
|
hass, fan.DOMAIN, config, async_add_entities, _async_setup_entity
|
||||||
)
|
)
|
||||||
|
@ -212,7 +224,17 @@ async def async_setup_entry(
|
||||||
config_entry: ConfigEntry,
|
config_entry: ConfigEntry,
|
||||||
async_add_entities: AddEntitiesCallback,
|
async_add_entities: AddEntitiesCallback,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Set up MQTT fan dynamically through MQTT discovery."""
|
"""Set up MQTT fan through configuration.yaml and dynamically through MQTT discovery."""
|
||||||
|
# load and initialize platform config from configuration.yaml
|
||||||
|
await asyncio.gather(
|
||||||
|
*(
|
||||||
|
_async_setup_entity(hass, async_add_entities, config, config_entry)
|
||||||
|
for config in await async_get_platform_config_from_yaml(
|
||||||
|
hass, fan.DOMAIN, PLATFORM_SCHEMA_MODERN
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
# setup for discovery
|
||||||
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
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,36 +1,47 @@
|
||||||
"""Support for MQTT lights."""
|
"""Support for MQTT lights."""
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import asyncio
|
||||||
import functools
|
import functools
|
||||||
|
|
||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
|
|
||||||
from homeassistant.components import light
|
from homeassistant.components import light
|
||||||
|
from homeassistant.config_entries import ConfigEntry
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
|
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.typing import ConfigType, DiscoveryInfoType
|
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
|
||||||
|
|
||||||
from ..mixins import async_setup_entry_helper, async_setup_platform_helper
|
from ..mixins import (
|
||||||
|
async_get_platform_config_from_yaml,
|
||||||
|
async_setup_entry_helper,
|
||||||
|
async_setup_platform_helper,
|
||||||
|
warn_for_legacy_schema,
|
||||||
|
)
|
||||||
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,
|
||||||
PLATFORM_SCHEMA_BASIC,
|
PLATFORM_SCHEMA_BASIC,
|
||||||
|
PLATFORM_SCHEMA_MODERN_BASIC,
|
||||||
async_setup_entity_basic,
|
async_setup_entity_basic,
|
||||||
)
|
)
|
||||||
from .schema_json import (
|
from .schema_json import (
|
||||||
DISCOVERY_SCHEMA_JSON,
|
DISCOVERY_SCHEMA_JSON,
|
||||||
PLATFORM_SCHEMA_JSON,
|
PLATFORM_SCHEMA_JSON,
|
||||||
|
PLATFORM_SCHEMA_MODERN_JSON,
|
||||||
async_setup_entity_json,
|
async_setup_entity_json,
|
||||||
)
|
)
|
||||||
from .schema_template import (
|
from .schema_template import (
|
||||||
DISCOVERY_SCHEMA_TEMPLATE,
|
DISCOVERY_SCHEMA_TEMPLATE,
|
||||||
|
PLATFORM_SCHEMA_MODERN_TEMPLATE,
|
||||||
PLATFORM_SCHEMA_TEMPLATE,
|
PLATFORM_SCHEMA_TEMPLATE,
|
||||||
async_setup_entity_template,
|
async_setup_entity_template,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def validate_mqtt_light_discovery(value):
|
def validate_mqtt_light_discovery(value):
|
||||||
"""Validate MQTT light schema."""
|
"""Validate MQTT light schema for."""
|
||||||
schemas = {
|
schemas = {
|
||||||
"basic": DISCOVERY_SCHEMA_BASIC,
|
"basic": DISCOVERY_SCHEMA_BASIC,
|
||||||
"json": DISCOVERY_SCHEMA_JSON,
|
"json": DISCOVERY_SCHEMA_JSON,
|
||||||
|
@ -49,14 +60,31 @@ def validate_mqtt_light(value):
|
||||||
return schemas[value[CONF_SCHEMA]](value)
|
return schemas[value[CONF_SCHEMA]](value)
|
||||||
|
|
||||||
|
|
||||||
|
def validate_mqtt_light_modern(value):
|
||||||
|
"""Validate MQTT light schema."""
|
||||||
|
schemas = {
|
||||||
|
"basic": PLATFORM_SCHEMA_MODERN_BASIC,
|
||||||
|
"json": PLATFORM_SCHEMA_MODERN_JSON,
|
||||||
|
"template": PLATFORM_SCHEMA_MODERN_TEMPLATE,
|
||||||
|
}
|
||||||
|
return schemas[value[CONF_SCHEMA]](value)
|
||||||
|
|
||||||
|
|
||||||
DISCOVERY_SCHEMA = vol.All(
|
DISCOVERY_SCHEMA = vol.All(
|
||||||
MQTT_LIGHT_SCHEMA_SCHEMA.extend({}, extra=vol.ALLOW_EXTRA),
|
MQTT_LIGHT_SCHEMA_SCHEMA.extend({}, extra=vol.ALLOW_EXTRA),
|
||||||
validate_mqtt_light_discovery,
|
validate_mqtt_light_discovery,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Configuring MQTT Lights under the light platform key is deprecated in HA Core 2022.6
|
||||||
PLATFORM_SCHEMA = vol.All(
|
PLATFORM_SCHEMA = vol.All(
|
||||||
MQTT_LIGHT_SCHEMA_SCHEMA.extend({}, extra=vol.ALLOW_EXTRA), validate_mqtt_light
|
cv.PLATFORM_SCHEMA.extend(MQTT_LIGHT_SCHEMA_SCHEMA.schema, extra=vol.ALLOW_EXTRA),
|
||||||
|
validate_mqtt_light,
|
||||||
|
warn_for_legacy_schema(light.DOMAIN),
|
||||||
|
)
|
||||||
|
|
||||||
|
PLATFORM_SCHEMA_MODERN = vol.All(
|
||||||
|
MQTT_LIGHT_SCHEMA_SCHEMA.extend({}, extra=vol.ALLOW_EXTRA),
|
||||||
|
validate_mqtt_light_modern,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -66,14 +94,29 @@ async def async_setup_platform(
|
||||||
async_add_entities: AddEntitiesCallback,
|
async_add_entities: AddEntitiesCallback,
|
||||||
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 (deprecated)."""
|
||||||
|
# Deprecated in HA Core 2022.6
|
||||||
await async_setup_platform_helper(
|
await async_setup_platform_helper(
|
||||||
hass, light.DOMAIN, config, async_add_entities, _async_setup_entity
|
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(
|
||||||
"""Set up MQTT light dynamically through MQTT discovery."""
|
hass: HomeAssistant,
|
||||||
|
config_entry: ConfigEntry,
|
||||||
|
async_add_entities: AddEntitiesCallback,
|
||||||
|
) -> None:
|
||||||
|
"""Set up MQTT lights configured under the light platform key (deprecated)."""
|
||||||
|
# load and initialize platform config from configuration.yaml
|
||||||
|
await asyncio.gather(
|
||||||
|
*(
|
||||||
|
_async_setup_entity(hass, async_add_entities, config, config_entry)
|
||||||
|
for config in await async_get_platform_config_from_yaml(
|
||||||
|
hass, light.DOMAIN, PLATFORM_SCHEMA_MODERN
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
# setup for discovery
|
||||||
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
|
||||||
)
|
)
|
||||||
|
|
|
@ -156,7 +156,7 @@ VALUE_TEMPLATE_KEYS = [
|
||||||
]
|
]
|
||||||
|
|
||||||
_PLATFORM_SCHEMA_BASE = (
|
_PLATFORM_SCHEMA_BASE = (
|
||||||
mqtt.MQTT_RW_PLATFORM_SCHEMA.extend(
|
mqtt.MQTT_RW_SCHEMA.extend(
|
||||||
{
|
{
|
||||||
vol.Optional(CONF_BRIGHTNESS_COMMAND_TEMPLATE): cv.template,
|
vol.Optional(CONF_BRIGHTNESS_COMMAND_TEMPLATE): cv.template,
|
||||||
vol.Optional(CONF_BRIGHTNESS_COMMAND_TOPIC): mqtt.valid_publish_topic,
|
vol.Optional(CONF_BRIGHTNESS_COMMAND_TOPIC): mqtt.valid_publish_topic,
|
||||||
|
@ -220,13 +220,14 @@ _PLATFORM_SCHEMA_BASE = (
|
||||||
.extend(MQTT_LIGHT_SCHEMA_SCHEMA.schema)
|
.extend(MQTT_LIGHT_SCHEMA_SCHEMA.schema)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# The use of PLATFORM_SCHEMA is deprecated in HA Core 2022.6
|
||||||
PLATFORM_SCHEMA_BASIC = vol.All(
|
PLATFORM_SCHEMA_BASIC = vol.All(
|
||||||
# CONF_WHITE_VALUE_* is deprecated, support will be removed in release 2022.9
|
# CONF_WHITE_VALUE_* is deprecated, support will be removed in release 2022.9
|
||||||
cv.deprecated(CONF_WHITE_VALUE_COMMAND_TOPIC),
|
cv.deprecated(CONF_WHITE_VALUE_COMMAND_TOPIC),
|
||||||
cv.deprecated(CONF_WHITE_VALUE_SCALE),
|
cv.deprecated(CONF_WHITE_VALUE_SCALE),
|
||||||
cv.deprecated(CONF_WHITE_VALUE_STATE_TOPIC),
|
cv.deprecated(CONF_WHITE_VALUE_STATE_TOPIC),
|
||||||
cv.deprecated(CONF_WHITE_VALUE_TEMPLATE),
|
cv.deprecated(CONF_WHITE_VALUE_TEMPLATE),
|
||||||
_PLATFORM_SCHEMA_BASE,
|
cv.PLATFORM_SCHEMA.extend(_PLATFORM_SCHEMA_BASE.schema),
|
||||||
)
|
)
|
||||||
|
|
||||||
DISCOVERY_SCHEMA_BASIC = vol.All(
|
DISCOVERY_SCHEMA_BASIC = vol.All(
|
||||||
|
@ -240,6 +241,8 @@ DISCOVERY_SCHEMA_BASIC = vol.All(
|
||||||
_PLATFORM_SCHEMA_BASE.extend({}, extra=vol.REMOVE_EXTRA),
|
_PLATFORM_SCHEMA_BASE.extend({}, extra=vol.REMOVE_EXTRA),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
PLATFORM_SCHEMA_MODERN_BASIC = _PLATFORM_SCHEMA_BASE
|
||||||
|
|
||||||
|
|
||||||
async def async_setup_entity_basic(
|
async def async_setup_entity_basic(
|
||||||
hass, config, async_add_entities, config_entry, discovery_data=None
|
hass, config, async_add_entities, config_entry, discovery_data=None
|
||||||
|
|
|
@ -103,7 +103,7 @@ def valid_color_configuration(config):
|
||||||
|
|
||||||
|
|
||||||
_PLATFORM_SCHEMA_BASE = (
|
_PLATFORM_SCHEMA_BASE = (
|
||||||
mqtt.MQTT_RW_PLATFORM_SCHEMA.extend(
|
mqtt.MQTT_RW_SCHEMA.extend(
|
||||||
{
|
{
|
||||||
vol.Optional(CONF_BRIGHTNESS, default=DEFAULT_BRIGHTNESS): cv.boolean,
|
vol.Optional(CONF_BRIGHTNESS, default=DEFAULT_BRIGHTNESS): cv.boolean,
|
||||||
vol.Optional(
|
vol.Optional(
|
||||||
|
@ -146,10 +146,11 @@ _PLATFORM_SCHEMA_BASE = (
|
||||||
.extend(MQTT_LIGHT_SCHEMA_SCHEMA.schema)
|
.extend(MQTT_LIGHT_SCHEMA_SCHEMA.schema)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Configuring MQTT Lights under the light platform key is deprecated in HA Core 2022.6
|
||||||
PLATFORM_SCHEMA_JSON = vol.All(
|
PLATFORM_SCHEMA_JSON = vol.All(
|
||||||
# CONF_WHITE_VALUE is deprecated, support will be removed in release 2022.9
|
# CONF_WHITE_VALUE is deprecated, support will be removed in release 2022.9
|
||||||
cv.deprecated(CONF_WHITE_VALUE),
|
cv.deprecated(CONF_WHITE_VALUE),
|
||||||
_PLATFORM_SCHEMA_BASE,
|
cv.PLATFORM_SCHEMA.extend(_PLATFORM_SCHEMA_BASE.schema),
|
||||||
valid_color_configuration,
|
valid_color_configuration,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -160,6 +161,11 @@ DISCOVERY_SCHEMA_JSON = vol.All(
|
||||||
valid_color_configuration,
|
valid_color_configuration,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
PLATFORM_SCHEMA_MODERN_JSON = vol.All(
|
||||||
|
_PLATFORM_SCHEMA_BASE,
|
||||||
|
valid_color_configuration,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
async def async_setup_entity_json(
|
async def async_setup_entity_json(
|
||||||
hass, config: ConfigType, async_add_entities, config_entry, discovery_data
|
hass, config: ConfigType, async_add_entities, config_entry, discovery_data
|
||||||
|
|
|
@ -67,7 +67,7 @@ CONF_RED_TEMPLATE = "red_template"
|
||||||
CONF_WHITE_VALUE_TEMPLATE = "white_value_template"
|
CONF_WHITE_VALUE_TEMPLATE = "white_value_template"
|
||||||
|
|
||||||
_PLATFORM_SCHEMA_BASE = (
|
_PLATFORM_SCHEMA_BASE = (
|
||||||
mqtt.MQTT_RW_PLATFORM_SCHEMA.extend(
|
mqtt.MQTT_RW_SCHEMA.extend(
|
||||||
{
|
{
|
||||||
vol.Optional(CONF_BLUE_TEMPLATE): cv.template,
|
vol.Optional(CONF_BLUE_TEMPLATE): cv.template,
|
||||||
vol.Optional(CONF_BRIGHTNESS_TEMPLATE): cv.template,
|
vol.Optional(CONF_BRIGHTNESS_TEMPLATE): cv.template,
|
||||||
|
@ -90,10 +90,11 @@ _PLATFORM_SCHEMA_BASE = (
|
||||||
.extend(MQTT_LIGHT_SCHEMA_SCHEMA.schema)
|
.extend(MQTT_LIGHT_SCHEMA_SCHEMA.schema)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Configuring MQTT Lights under the light platform key is deprecated in HA Core 2022.6
|
||||||
PLATFORM_SCHEMA_TEMPLATE = vol.All(
|
PLATFORM_SCHEMA_TEMPLATE = vol.All(
|
||||||
# CONF_WHITE_VALUE_TEMPLATE is deprecated, support will be removed in release 2022.9
|
# CONF_WHITE_VALUE_TEMPLATE is deprecated, support will be removed in release 2022.9
|
||||||
cv.deprecated(CONF_WHITE_VALUE_TEMPLATE),
|
cv.deprecated(CONF_WHITE_VALUE_TEMPLATE),
|
||||||
_PLATFORM_SCHEMA_BASE,
|
cv.PLATFORM_SCHEMA.extend(_PLATFORM_SCHEMA_BASE.schema),
|
||||||
)
|
)
|
||||||
|
|
||||||
DISCOVERY_SCHEMA_TEMPLATE = vol.All(
|
DISCOVERY_SCHEMA_TEMPLATE = vol.All(
|
||||||
|
@ -102,6 +103,8 @@ DISCOVERY_SCHEMA_TEMPLATE = vol.All(
|
||||||
_PLATFORM_SCHEMA_BASE.extend({}, extra=vol.REMOVE_EXTRA),
|
_PLATFORM_SCHEMA_BASE.extend({}, extra=vol.REMOVE_EXTRA),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
PLATFORM_SCHEMA_MODERN_TEMPLATE = _PLATFORM_SCHEMA_BASE
|
||||||
|
|
||||||
|
|
||||||
async def async_setup_entity_template(
|
async def async_setup_entity_template(
|
||||||
hass, config, async_add_entities, config_entry, discovery_data
|
hass, config, async_add_entities, config_entry, discovery_data
|
||||||
|
|
|
@ -9,6 +9,7 @@ from typing import Any, Protocol, cast, final
|
||||||
|
|
||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
|
|
||||||
|
from homeassistant.config import async_log_exception
|
||||||
from homeassistant.config_entries import ConfigEntry
|
from homeassistant.config_entries import ConfigEntry
|
||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
ATTR_CONFIGURATION_URL,
|
ATTR_CONFIGURATION_URL,
|
||||||
|
@ -64,6 +65,7 @@ from .const import (
|
||||||
CONF_ENCODING,
|
CONF_ENCODING,
|
||||||
CONF_QOS,
|
CONF_QOS,
|
||||||
CONF_TOPIC,
|
CONF_TOPIC,
|
||||||
|
DATA_MQTT_CONFIG,
|
||||||
DATA_MQTT_RELOAD_NEEDED,
|
DATA_MQTT_RELOAD_NEEDED,
|
||||||
DEFAULT_ENCODING,
|
DEFAULT_ENCODING,
|
||||||
DEFAULT_PAYLOAD_AVAILABLE,
|
DEFAULT_PAYLOAD_AVAILABLE,
|
||||||
|
@ -223,6 +225,31 @@ MQTT_ENTITY_COMMON_SCHEMA = MQTT_AVAILABILITY_SCHEMA.extend(
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def warn_for_legacy_schema(domain: str) -> Callable:
|
||||||
|
"""Warn once when a legacy platform schema is used."""
|
||||||
|
warned = set()
|
||||||
|
|
||||||
|
def validator(config: ConfigType) -> ConfigType:
|
||||||
|
"""Return a validator."""
|
||||||
|
nonlocal warned
|
||||||
|
|
||||||
|
if domain in warned:
|
||||||
|
return config
|
||||||
|
|
||||||
|
_LOGGER.warning(
|
||||||
|
"Manually configured MQTT %s(s) found under platform key '%s', "
|
||||||
|
"please move to the mqtt integration key, see "
|
||||||
|
"https://www.home-assistant.io/integrations/%s.mqtt/#new_format",
|
||||||
|
domain,
|
||||||
|
domain,
|
||||||
|
domain,
|
||||||
|
)
|
||||||
|
warned.add(domain)
|
||||||
|
return config
|
||||||
|
|
||||||
|
return validator
|
||||||
|
|
||||||
|
|
||||||
class SetupEntity(Protocol):
|
class SetupEntity(Protocol):
|
||||||
"""Protocol type for async_setup_entities."""
|
"""Protocol type for async_setup_entities."""
|
||||||
|
|
||||||
|
@ -237,6 +264,31 @@ class SetupEntity(Protocol):
|
||||||
"""Define setup_entities type."""
|
"""Define setup_entities type."""
|
||||||
|
|
||||||
|
|
||||||
|
async def async_get_platform_config_from_yaml(
|
||||||
|
hass: HomeAssistant, domain: str, schema: vol.Schema
|
||||||
|
) -> list[ConfigType]:
|
||||||
|
"""Return a list of validated configurations for the domain."""
|
||||||
|
|
||||||
|
def async_validate_config(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
config: list[ConfigType],
|
||||||
|
) -> list[ConfigType]:
|
||||||
|
"""Validate config."""
|
||||||
|
validated_config = []
|
||||||
|
for config_item in config:
|
||||||
|
try:
|
||||||
|
validated_config.append(schema(config_item))
|
||||||
|
except vol.MultipleInvalid as err:
|
||||||
|
async_log_exception(err, domain, config_item, hass)
|
||||||
|
|
||||||
|
return validated_config
|
||||||
|
|
||||||
|
config_yaml: ConfigType = hass.data.get(DATA_MQTT_CONFIG, {})
|
||||||
|
if not (platform_configs := config_yaml.get(domain)):
|
||||||
|
return []
|
||||||
|
return async_validate_config(hass, platform_configs)
|
||||||
|
|
||||||
|
|
||||||
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."""
|
||||||
|
|
||||||
|
|
|
@ -1690,3 +1690,24 @@ async def help_test_reloadable_late(hass, caplog, tmp_path, domain, config):
|
||||||
assert hass.states.get(f"{domain}.test_new_1")
|
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_2")
|
||||||
assert hass.states.get(f"{domain}.test_new_3")
|
assert hass.states.get(f"{domain}.test_new_3")
|
||||||
|
|
||||||
|
|
||||||
|
async def help_test_setup_manual_entity_from_yaml(
|
||||||
|
hass,
|
||||||
|
caplog,
|
||||||
|
tmp_path,
|
||||||
|
platform,
|
||||||
|
config,
|
||||||
|
):
|
||||||
|
"""Help to test setup from yaml through configuration entry."""
|
||||||
|
config_structure = {mqtt.DOMAIN: {platform: config}}
|
||||||
|
|
||||||
|
await async_setup_component(hass, mqtt.DOMAIN, config_structure)
|
||||||
|
# Mock config entry
|
||||||
|
entry = MockConfigEntry(domain=mqtt.DOMAIN, data={mqtt.CONF_BROKER: "test-broker"})
|
||||||
|
entry.add_to_hass(hass)
|
||||||
|
|
||||||
|
with patch("paho.mqtt.client.Client") as mock_client:
|
||||||
|
mock_client().connect = lambda *args: 0
|
||||||
|
assert await hass.config_entries.async_setup(entry.entry_id)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
|
@ -55,6 +55,7 @@ from .test_common import (
|
||||||
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,
|
||||||
|
help_test_setup_manual_entity_from_yaml,
|
||||||
help_test_unique_id,
|
help_test_unique_id,
|
||||||
help_test_update_with_json_attrs_bad_JSON,
|
help_test_update_with_json_attrs_bad_JSON,
|
||||||
help_test_update_with_json_attrs_not_dict,
|
help_test_update_with_json_attrs_not_dict,
|
||||||
|
@ -1805,3 +1806,15 @@ async def test_reloadable_late(hass, mqtt_client_mock, caplog, tmp_path):
|
||||||
domain = fan.DOMAIN
|
domain = fan.DOMAIN
|
||||||
config = DEFAULT_CONFIG[domain]
|
config = DEFAULT_CONFIG[domain]
|
||||||
await help_test_reloadable_late(hass, caplog, tmp_path, domain, config)
|
await help_test_reloadable_late(hass, caplog, tmp_path, domain, config)
|
||||||
|
|
||||||
|
|
||||||
|
async def test_setup_manual_entity_from_yaml(hass, caplog, tmp_path):
|
||||||
|
"""Test setup manual configured MQTT entity."""
|
||||||
|
platform = fan.DOMAIN
|
||||||
|
config = copy.deepcopy(DEFAULT_CONFIG[platform])
|
||||||
|
config["name"] = "test"
|
||||||
|
del config["platform"]
|
||||||
|
await help_test_setup_manual_entity_from_yaml(
|
||||||
|
hass, caplog, tmp_path, platform, config
|
||||||
|
)
|
||||||
|
assert hass.states.get(f"{platform}.test") is not None
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
"""The tests for the MQTT component."""
|
"""The tests for the MQTT component."""
|
||||||
import asyncio
|
import asyncio
|
||||||
|
import copy
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
from functools import partial
|
from functools import partial
|
||||||
import json
|
import json
|
||||||
|
@ -30,6 +31,8 @@ from homeassistant.helpers.entity import Entity
|
||||||
from homeassistant.setup import async_setup_component
|
from homeassistant.setup import async_setup_component
|
||||||
from homeassistant.util.dt import utcnow
|
from homeassistant.util.dt import utcnow
|
||||||
|
|
||||||
|
from .test_common import help_test_setup_manual_entity_from_yaml
|
||||||
|
|
||||||
from tests.common import (
|
from tests.common import (
|
||||||
MockConfigEntry,
|
MockConfigEntry,
|
||||||
async_fire_mqtt_message,
|
async_fire_mqtt_message,
|
||||||
|
@ -1279,6 +1282,51 @@ async def test_setup_override_configuration(hass, caplog, tmp_path):
|
||||||
assert calls_username_password_set[0][1] == "somepassword"
|
assert calls_username_password_set[0][1] == "somepassword"
|
||||||
|
|
||||||
|
|
||||||
|
async def test_setup_manual_mqtt_with_platform_key(hass, caplog, tmp_path):
|
||||||
|
"""Test set up a manual MQTT item with a platform key."""
|
||||||
|
config = {"platform": "mqtt", "name": "test", "command_topic": "test-topic"}
|
||||||
|
await help_test_setup_manual_entity_from_yaml(
|
||||||
|
hass,
|
||||||
|
caplog,
|
||||||
|
tmp_path,
|
||||||
|
"light",
|
||||||
|
config,
|
||||||
|
)
|
||||||
|
assert (
|
||||||
|
"Invalid config for [light]: [platform] is an invalid option for [light]. "
|
||||||
|
"Check: light->platform. (See ?, line ?)" in caplog.text
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def test_setup_manual_mqtt_with_invalid_config(hass, caplog, tmp_path):
|
||||||
|
"""Test set up a manual MQTT item with an invalid config."""
|
||||||
|
config = {"name": "test"}
|
||||||
|
await help_test_setup_manual_entity_from_yaml(
|
||||||
|
hass,
|
||||||
|
caplog,
|
||||||
|
tmp_path,
|
||||||
|
"light",
|
||||||
|
config,
|
||||||
|
)
|
||||||
|
assert (
|
||||||
|
"Invalid config for [light]: required key not provided @ data['command_topic']."
|
||||||
|
" Got None. (See ?, line ?)" in caplog.text
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def test_setup_manual_mqtt_empty_platform(hass, caplog, tmp_path):
|
||||||
|
"""Test set up a manual MQTT platform without items."""
|
||||||
|
config = None
|
||||||
|
await help_test_setup_manual_entity_from_yaml(
|
||||||
|
hass,
|
||||||
|
caplog,
|
||||||
|
tmp_path,
|
||||||
|
"light",
|
||||||
|
config,
|
||||||
|
)
|
||||||
|
assert "voluptuous.error.MultipleInvalid" not in caplog.text
|
||||||
|
|
||||||
|
|
||||||
async def test_setup_mqtt_client_protocol(hass):
|
async def test_setup_mqtt_client_protocol(hass):
|
||||||
"""Test MQTT client protocol setup."""
|
"""Test MQTT client protocol setup."""
|
||||||
entry = MockConfigEntry(
|
entry = MockConfigEntry(
|
||||||
|
@ -1628,7 +1676,8 @@ async def test_setup_entry_with_config_override(hass, device_reg, mqtt_client_mo
|
||||||
# User sets up a config entry
|
# User sets up a config entry
|
||||||
entry = MockConfigEntry(domain=mqtt.DOMAIN, data={mqtt.CONF_BROKER: "test-broker"})
|
entry = MockConfigEntry(domain=mqtt.DOMAIN, data={mqtt.CONF_BROKER: "test-broker"})
|
||||||
entry.add_to_hass(hass)
|
entry.add_to_hass(hass)
|
||||||
assert await hass.config_entries.async_setup(entry.entry_id)
|
with patch("homeassistant.components.mqtt.PLATFORMS", []):
|
||||||
|
assert await hass.config_entries.async_setup(entry.entry_id)
|
||||||
|
|
||||||
# Discover a device to verify the entry was setup correctly
|
# Discover a device to verify the entry was setup correctly
|
||||||
async_fire_mqtt_message(hass, "homeassistant/sensor/bla/config", data)
|
async_fire_mqtt_message(hass, "homeassistant/sensor/bla/config", data)
|
||||||
|
@ -2413,3 +2462,23 @@ async def test_subscribe_connection_status(hass, mqtt_mock, mqtt_client_mock):
|
||||||
assert len(mqtt_connected_calls) == 2
|
assert len(mqtt_connected_calls) == 2
|
||||||
assert mqtt_connected_calls[0] is True
|
assert mqtt_connected_calls[0] is True
|
||||||
assert mqtt_connected_calls[1] is False
|
assert mqtt_connected_calls[1] is False
|
||||||
|
|
||||||
|
|
||||||
|
async def test_one_deprecation_warning_per_platform(hass, mqtt_mock, caplog):
|
||||||
|
"""Test a deprecation warning is is logged once per platform."""
|
||||||
|
platform = "light"
|
||||||
|
config = {"platform": "mqtt", "command_topic": "test-topic"}
|
||||||
|
config1 = copy.deepcopy(config)
|
||||||
|
config1["name"] = "test1"
|
||||||
|
config2 = copy.deepcopy(config)
|
||||||
|
config2["name"] = "test2"
|
||||||
|
await async_setup_component(hass, platform, {platform: [config1, config2]})
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
count = 0
|
||||||
|
for record in caplog.records:
|
||||||
|
if record.levelname == "WARNING" and (
|
||||||
|
f"Manually configured MQTT {platform}(s) found under platform key '{platform}'"
|
||||||
|
in record.message
|
||||||
|
):
|
||||||
|
count += 1
|
||||||
|
assert count == 1
|
||||||
|
|
|
@ -237,6 +237,7 @@ from .test_common import (
|
||||||
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,
|
||||||
|
help_test_setup_manual_entity_from_yaml,
|
||||||
help_test_unique_id,
|
help_test_unique_id,
|
||||||
help_test_update_with_json_attrs_bad_JSON,
|
help_test_update_with_json_attrs_bad_JSON,
|
||||||
help_test_update_with_json_attrs_not_dict,
|
help_test_update_with_json_attrs_not_dict,
|
||||||
|
@ -3674,3 +3675,15 @@ async def test_sending_mqtt_effect_command_with_template(hass, mqtt_mock):
|
||||||
state = hass.states.get("light.test")
|
state = hass.states.get("light.test")
|
||||||
assert state.state == STATE_ON
|
assert state.state == STATE_ON
|
||||||
assert state.attributes.get("effect") == "colorloop"
|
assert state.attributes.get("effect") == "colorloop"
|
||||||
|
|
||||||
|
|
||||||
|
async def test_setup_manual_entity_from_yaml(hass, caplog, tmp_path):
|
||||||
|
"""Test setup manual configured MQTT entity."""
|
||||||
|
platform = light.DOMAIN
|
||||||
|
config = copy.deepcopy(DEFAULT_CONFIG[platform])
|
||||||
|
config["name"] = "test"
|
||||||
|
del config["platform"]
|
||||||
|
await help_test_setup_manual_entity_from_yaml(
|
||||||
|
hass, caplog, tmp_path, platform, config
|
||||||
|
)
|
||||||
|
assert hass.states.get(f"{platform}.test") is not None
|
||||||
|
|
|
@ -131,6 +131,7 @@ from .test_common import (
|
||||||
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,
|
||||||
|
help_test_setup_manual_entity_from_yaml,
|
||||||
help_test_unique_id,
|
help_test_unique_id,
|
||||||
help_test_update_with_json_attrs_bad_JSON,
|
help_test_update_with_json_attrs_bad_JSON,
|
||||||
help_test_update_with_json_attrs_not_dict,
|
help_test_update_with_json_attrs_not_dict,
|
||||||
|
@ -2038,3 +2039,15 @@ async def test_encoding_subscribable_topics(
|
||||||
init_payload,
|
init_payload,
|
||||||
skip_raw_test=True,
|
skip_raw_test=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def test_setup_manual_entity_from_yaml(hass, caplog, tmp_path):
|
||||||
|
"""Test setup manual configured MQTT entity."""
|
||||||
|
platform = light.DOMAIN
|
||||||
|
config = copy.deepcopy(DEFAULT_CONFIG[platform])
|
||||||
|
config["name"] = "test"
|
||||||
|
del config["platform"]
|
||||||
|
await help_test_setup_manual_entity_from_yaml(
|
||||||
|
hass, caplog, tmp_path, platform, config
|
||||||
|
)
|
||||||
|
assert hass.states.get(f"{platform}.test") is not None
|
||||||
|
|
|
@ -69,6 +69,7 @@ from .test_common import (
|
||||||
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,
|
||||||
|
help_test_setup_manual_entity_from_yaml,
|
||||||
help_test_unique_id,
|
help_test_unique_id,
|
||||||
help_test_update_with_json_attrs_bad_JSON,
|
help_test_update_with_json_attrs_bad_JSON,
|
||||||
help_test_update_with_json_attrs_not_dict,
|
help_test_update_with_json_attrs_not_dict,
|
||||||
|
@ -1213,3 +1214,15 @@ async def test_encoding_subscribable_topics(
|
||||||
attribute_value,
|
attribute_value,
|
||||||
init_payload,
|
init_payload,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def test_setup_manual_entity_from_yaml(hass, caplog, tmp_path):
|
||||||
|
"""Test setup manual configured MQTT entity."""
|
||||||
|
platform = light.DOMAIN
|
||||||
|
config = copy.deepcopy(DEFAULT_CONFIG[platform])
|
||||||
|
config["name"] = "test"
|
||||||
|
del config["platform"]
|
||||||
|
await help_test_setup_manual_entity_from_yaml(
|
||||||
|
hass, caplog, tmp_path, platform, config
|
||||||
|
)
|
||||||
|
assert hass.states.get(f"{platform}.test") is not None
|
||||||
|
|
|
@ -561,9 +561,10 @@ async def mqtt_mock(hass, mqtt_client_mock, mqtt_config):
|
||||||
)
|
)
|
||||||
|
|
||||||
entry.add_to_hass(hass)
|
entry.add_to_hass(hass)
|
||||||
|
# Do not forward the entry setup to the components here
|
||||||
assert await hass.config_entries.async_setup(entry.entry_id)
|
with patch("homeassistant.components.mqtt.PLATFORMS", []):
|
||||||
await hass.async_block_till_done()
|
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"],
|
||||||
|
|
Loading…
Add table
Reference in a new issue