Merge pull request #72944 from home-assistant/rc

This commit is contained in:
Paulus Schoutsen 2022-06-02 21:53:58 -07:00 committed by GitHub
commit ddc8c0a3b7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
110 changed files with 5983 additions and 3197 deletions

View File

@ -26,7 +26,7 @@ async def async_setup_entry(
) -> None:
"""Set up BAF fan auto comfort."""
data: BAFData = hass.data[DOMAIN][entry.entry_id]
if data.device.has_fan:
if data.device.has_fan and data.device.has_auto_comfort:
async_add_entities(
[BAFAutoComfort(data.device, f"{data.device.name} Auto Comfort")]
)

View File

@ -3,7 +3,7 @@
"name": "Big Ass Fans",
"config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/baf",
"requirements": ["aiobafi6==0.3.0"],
"requirements": ["aiobafi6==0.5.0"],
"codeowners": ["@bdraco", "@jfroy"],
"iot_class": "local_push",
"zeroconf": [

View File

@ -36,27 +36,7 @@ class BAFNumberDescription(NumberEntityDescription, BAFNumberDescriptionMixin):
"""Class describing BAF sensor entities."""
FAN_NUMBER_DESCRIPTIONS = (
BAFNumberDescription(
key="return_to_auto_timeout",
name="Return to Auto Timeout",
min_value=ONE_MIN_SECS,
max_value=HALF_DAY_SECS,
entity_category=EntityCategory.CONFIG,
unit_of_measurement=TIME_SECONDS,
value_fn=lambda device: cast(Optional[int], device.return_to_auto_timeout),
mode=NumberMode.SLIDER,
),
BAFNumberDescription(
key="motion_sense_timeout",
name="Motion Sense Timeout",
min_value=ONE_MIN_SECS,
max_value=ONE_DAY_SECS,
entity_category=EntityCategory.CONFIG,
unit_of_measurement=TIME_SECONDS,
value_fn=lambda device: cast(Optional[int], device.motion_sense_timeout),
mode=NumberMode.SLIDER,
),
AUTO_COMFORT_NUMBER_DESCRIPTIONS = (
BAFNumberDescription(
key="comfort_min_speed",
name="Auto Comfort Minimum Speed",
@ -86,6 +66,29 @@ FAN_NUMBER_DESCRIPTIONS = (
),
)
FAN_NUMBER_DESCRIPTIONS = (
BAFNumberDescription(
key="return_to_auto_timeout",
name="Return to Auto Timeout",
min_value=ONE_MIN_SECS,
max_value=HALF_DAY_SECS,
entity_category=EntityCategory.CONFIG,
unit_of_measurement=TIME_SECONDS,
value_fn=lambda device: cast(Optional[int], device.return_to_auto_timeout),
mode=NumberMode.SLIDER,
),
BAFNumberDescription(
key="motion_sense_timeout",
name="Motion Sense Timeout",
min_value=ONE_MIN_SECS,
max_value=ONE_DAY_SECS,
entity_category=EntityCategory.CONFIG,
unit_of_measurement=TIME_SECONDS,
value_fn=lambda device: cast(Optional[int], device.motion_sense_timeout),
mode=NumberMode.SLIDER,
),
)
LIGHT_NUMBER_DESCRIPTIONS = (
BAFNumberDescription(
key="light_return_to_auto_timeout",
@ -125,6 +128,8 @@ async def async_setup_entry(
descriptions.extend(FAN_NUMBER_DESCRIPTIONS)
if device.has_light:
descriptions.extend(LIGHT_NUMBER_DESCRIPTIONS)
if device.has_auto_comfort:
descriptions.extend(AUTO_COMFORT_NUMBER_DESCRIPTIONS)
async_add_entities(BAFNumber(device, description) for description in descriptions)

View File

@ -39,7 +39,7 @@ class BAFSensorDescription(
"""Class describing BAF sensor entities."""
BASE_SENSORS = (
AUTO_COMFORT_SENSORS = (
BAFSensorDescription(
key="temperature",
name="Temperature",
@ -103,10 +103,12 @@ async def async_setup_entry(
"""Set up BAF fan sensors."""
data: BAFData = hass.data[DOMAIN][entry.entry_id]
device = data.device
sensors_descriptions = list(BASE_SENSORS)
sensors_descriptions: list[BAFSensorDescription] = []
for description in DEFINED_ONLY_SENSORS:
if getattr(device, description.key):
sensors_descriptions.append(description)
if device.has_auto_comfort:
sensors_descriptions.extend(AUTO_COMFORT_SENSORS)
if device.has_fan:
sensors_descriptions.extend(FAN_SENSORS)
async_add_entities(

View File

@ -48,13 +48,16 @@ BASE_SWITCHES = [
),
]
FAN_SWITCHES = [
AUTO_COMFORT_SWITCHES = [
BAFSwitchDescription(
key="comfort_heat_assist_enable",
name="Auto Comfort Heat Assist",
entity_category=EntityCategory.CONFIG,
value_fn=lambda device: cast(Optional[bool], device.comfort_heat_assist_enable),
),
]
FAN_SWITCHES = [
BAFSwitchDescription(
key="fan_beep_enable",
name="Beep",
@ -120,6 +123,8 @@ async def async_setup_entry(
descriptions.extend(FAN_SWITCHES)
if device.has_light:
descriptions.extend(LIGHT_SWITCHES)
if device.has_auto_comfort:
descriptions.extend(AUTO_COMFORT_SWITCHES)
async_add_entities(BAFSwitch(device, description) for description in descriptions)

View File

@ -1,7 +1,6 @@
"""Support for WebDav Calendar."""
from __future__ import annotations
import copy
from datetime import datetime, timedelta
import logging
import re
@ -143,15 +142,13 @@ class WebDavCalendarEntity(CalendarEntity):
def update(self):
"""Update event data."""
self.data.update()
event = copy.deepcopy(self.data.event)
if event is None:
self._event = event
return
(summary, offset) = extract_offset(event.summary, OFFSET)
event.summary = summary
self._event = event
self._event = self.data.event
self._attr_extra_state_attributes = {
"offset_reached": is_offset_reached(event.start_datetime_local, offset)
"offset_reached": is_offset_reached(
self._event.start_datetime_local, self.data.offset
)
if self._event
else False
}
@ -165,6 +162,7 @@ class WebDavCalendarData:
self.include_all_day = include_all_day
self.search = search
self.event = None
self.offset = None
async def async_get_events(
self, hass: HomeAssistant, start_date: datetime, end_date: datetime
@ -264,13 +262,15 @@ class WebDavCalendarData:
return
# Populate the entity attributes with the event values
(summary, offset) = extract_offset(vevent.summary.value, OFFSET)
self.event = CalendarEvent(
summary=vevent.summary.value,
summary=summary,
start=vevent.dtstart.value,
end=self.get_end_date(vevent),
location=self.get_attr_value(vevent, "location"),
description=self.get_attr_value(vevent, "description"),
)
self.offset = offset
@staticmethod
def is_matching(vevent, search):

View File

@ -39,7 +39,6 @@ class CloudGoogleConfig(AbstractConfig):
self._cur_entity_prefs = self._prefs.google_entity_configs
self._cur_default_expose = self._prefs.google_default_expose
self._sync_entities_lock = asyncio.Lock()
self._sync_on_started = False
@property
def enabled(self):
@ -224,7 +223,7 @@ class CloudGoogleConfig(AbstractConfig):
self._cur_entity_prefs = prefs.google_entity_configs
self._cur_default_expose = prefs.google_default_expose
if sync_entities:
if sync_entities and self.hass.is_running:
await self.async_sync_entities_all()
@callback

View File

@ -2,7 +2,7 @@
"domain": "frontend",
"name": "Home Assistant Frontend",
"documentation": "https://www.home-assistant.io/integrations/frontend",
"requirements": ["home-assistant-frontend==20220531.0"],
"requirements": ["home-assistant-frontend==20220601.0"],
"dependencies": [
"api",
"auth",

View File

@ -73,7 +73,8 @@ class HistoryStats:
# History cannot tell the future
self._history_current_period = []
self._previous_run_before_start = True
self._state = HistoryStatsState(None, None, self._period)
return self._state
#
# We avoid querying the database if the below did NOT happen:
#
@ -82,7 +83,7 @@ class HistoryStats:
# - The period shrank in size
# - The previous period ended before now
#
elif (
if (
not self._previous_run_before_start
and current_period_start_timestamp == previous_period_start_timestamp
and (
@ -117,10 +118,6 @@ class HistoryStats:
)
self._previous_run_before_start = False
if not self._history_current_period:
self._state = HistoryStatsState(None, None, self._period)
return self._state
hours_matched, match_count = self._async_compute_hours_and_changes(
now_timestamp,
current_period_start_timestamp,

View File

@ -75,14 +75,9 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Set up Hive from a config entry."""
websession = aiohttp_client.async_get_clientsession(hass)
web_session = aiohttp_client.async_get_clientsession(hass)
hive_config = dict(entry.data)
hive = Hive(
websession,
deviceGroupKey=hive_config["device_data"][0],
deviceKey=hive_config["device_data"][1],
devicePassword=hive_config["device_data"][2],
)
hive = Hive(web_session)
hive_config["options"] = {}
hive_config["options"].update(

View File

@ -102,6 +102,7 @@ class HiveFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
raise UnknownHiveError
# Setup the config entry
await self.hive_auth.device_registration("Home Assistant")
self.data["tokens"] = self.tokens
self.data["device_data"] = await self.hive_auth.getDeviceData()
if self.context["source"] == config_entries.SOURCE_REAUTH:

View File

@ -3,7 +3,7 @@
"name": "Hive",
"config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/hive",
"requirements": ["pyhiveapi==0.5.4"],
"requirements": ["pyhiveapi==0.5.5"],
"codeowners": ["@Rendili", "@KJonline"],
"iot_class": "cloud_polling",
"loggers": ["apyhiveapi"]

View File

@ -12,9 +12,11 @@ from sqlalchemy.sql.selectable import Select
from homeassistant.components.proximity import DOMAIN as PROXIMITY_DOMAIN
from homeassistant.components.recorder.models import (
EVENTS_CONTEXT_ID_INDEX,
OLD_FORMAT_ATTRS_JSON,
OLD_STATE,
SHARED_ATTRS_JSON,
STATES_CONTEXT_ID_INDEX,
EventData,
Events,
StateAttributes,
@ -121,9 +123,7 @@ def select_events_context_only() -> Select:
By marking them as context_only we know they are only for
linking context ids and we can avoid processing them.
"""
return select(*EVENT_ROWS_NO_STATES, CONTEXT_ONLY).outerjoin(
EventData, (Events.data_id == EventData.data_id)
)
return select(*EVENT_ROWS_NO_STATES, CONTEXT_ONLY)
def select_states_context_only() -> Select:
@ -252,3 +252,17 @@ def _not_uom_attributes_matcher() -> ClauseList:
return ~StateAttributes.shared_attrs.like(
UNIT_OF_MEASUREMENT_JSON_LIKE
) | ~States.attributes.like(UNIT_OF_MEASUREMENT_JSON_LIKE)
def apply_states_context_hints(query: Query) -> Query:
"""Force mysql to use the right index on large context_id selects."""
return query.with_hint(
States, f"FORCE INDEX ({STATES_CONTEXT_ID_INDEX})", dialect_name="mysql"
)
def apply_events_context_hints(query: Query) -> Query:
"""Force mysql to use the right index on large context_id selects."""
return query.with_hint(
Events, f"FORCE INDEX ({EVENTS_CONTEXT_ID_INDEX})", dialect_name="mysql"
)

View File

@ -4,15 +4,22 @@ from __future__ import annotations
from collections.abc import Iterable
from datetime import datetime as dt
from sqlalchemy import lambda_stmt, select, union_all
from sqlalchemy import lambda_stmt, select
from sqlalchemy.orm import Query
from sqlalchemy.sql.elements import ClauseList
from sqlalchemy.sql.lambdas import StatementLambdaElement
from sqlalchemy.sql.selectable import CTE, CompoundSelect
from homeassistant.components.recorder.models import DEVICE_ID_IN_EVENT, Events, States
from homeassistant.components.recorder.models import (
DEVICE_ID_IN_EVENT,
EventData,
Events,
States,
)
from .common import (
apply_events_context_hints,
apply_states_context_hints,
select_events_context_id_subquery,
select_events_context_only,
select_events_without_states,
@ -27,13 +34,10 @@ def _select_device_id_context_ids_sub_query(
json_quotable_device_ids: list[str],
) -> CompoundSelect:
"""Generate a subquery to find context ids for multiple devices."""
return select(
union_all(
select_events_context_id_subquery(start_day, end_day, event_types).where(
apply_event_device_id_matchers(json_quotable_device_ids)
),
).c.context_id
inner = select_events_context_id_subquery(start_day, end_day, event_types).where(
apply_event_device_id_matchers(json_quotable_device_ids)
)
return select(inner.c.context_id).group_by(inner.c.context_id)
def _apply_devices_context_union(
@ -51,8 +55,16 @@ def _apply_devices_context_union(
json_quotable_device_ids,
).cte()
return query.union_all(
select_events_context_only().where(Events.context_id.in_(devices_cte.select())),
select_states_context_only().where(States.context_id.in_(devices_cte.select())),
apply_events_context_hints(
select_events_context_only()
.select_from(devices_cte)
.outerjoin(Events, devices_cte.c.context_id == Events.context_id)
).outerjoin(EventData, (Events.data_id == EventData.data_id)),
apply_states_context_hints(
select_states_context_only()
.select_from(devices_cte)
.outerjoin(States, devices_cte.c.context_id == States.context_id)
),
)

View File

@ -14,11 +14,14 @@ from homeassistant.components.recorder.models import (
ENTITY_ID_IN_EVENT,
ENTITY_ID_LAST_UPDATED_INDEX,
OLD_ENTITY_ID_IN_EVENT,
EventData,
Events,
States,
)
from .common import (
apply_events_context_hints,
apply_states_context_hints,
apply_states_filters,
select_events_context_id_subquery,
select_events_context_only,
@ -36,16 +39,15 @@ def _select_entities_context_ids_sub_query(
json_quotable_entity_ids: list[str],
) -> CompoundSelect:
"""Generate a subquery to find context ids for multiple entities."""
return select(
union_all(
select_events_context_id_subquery(start_day, end_day, event_types).where(
apply_event_entity_id_matchers(json_quotable_entity_ids)
),
apply_entities_hints(select(States.context_id))
.filter((States.last_updated > start_day) & (States.last_updated < end_day))
.where(States.entity_id.in_(entity_ids)),
).c.context_id
union = union_all(
select_events_context_id_subquery(start_day, end_day, event_types).where(
apply_event_entity_id_matchers(json_quotable_entity_ids)
),
apply_entities_hints(select(States.context_id))
.filter((States.last_updated > start_day) & (States.last_updated < end_day))
.where(States.entity_id.in_(entity_ids)),
)
return select(union.c.context_id).group_by(union.c.context_id)
def _apply_entities_context_union(
@ -64,14 +66,23 @@ def _apply_entities_context_union(
entity_ids,
json_quotable_entity_ids,
).cte()
# We used to optimize this to exclude rows we already in the union with
# a States.entity_id.not_in(entity_ids) but that made the
# query much slower on MySQL, and since we already filter them away
# in the python code anyways since they will have context_only
# set on them the impact is minimal.
return query.union_all(
states_query_for_entity_ids(start_day, end_day, entity_ids),
select_events_context_only().where(
Events.context_id.in_(entities_cte.select())
apply_events_context_hints(
select_events_context_only()
.select_from(entities_cte)
.outerjoin(Events, entities_cte.c.context_id == Events.context_id)
).outerjoin(EventData, (Events.data_id == EventData.data_id)),
apply_states_context_hints(
select_states_context_only()
.select_from(entities_cte)
.outerjoin(States, entities_cte.c.context_id == States.context_id)
),
select_states_context_only()
.where(States.entity_id.not_in(entity_ids))
.where(States.context_id.in_(entities_cte.select())),
)

View File

@ -10,9 +10,11 @@ from sqlalchemy.orm import Query
from sqlalchemy.sql.lambdas import StatementLambdaElement
from sqlalchemy.sql.selectable import CTE, CompoundSelect
from homeassistant.components.recorder.models import Events, States
from homeassistant.components.recorder.models import EventData, Events, States
from .common import (
apply_events_context_hints,
apply_states_context_hints,
select_events_context_id_subquery,
select_events_context_only,
select_events_without_states,
@ -35,18 +37,17 @@ def _select_entities_device_id_context_ids_sub_query(
json_quotable_device_ids: list[str],
) -> CompoundSelect:
"""Generate a subquery to find context ids for multiple entities and multiple devices."""
return select(
union_all(
select_events_context_id_subquery(start_day, end_day, event_types).where(
_apply_event_entity_id_device_id_matchers(
json_quotable_entity_ids, json_quotable_device_ids
)
),
apply_entities_hints(select(States.context_id))
.filter((States.last_updated > start_day) & (States.last_updated < end_day))
.where(States.entity_id.in_(entity_ids)),
).c.context_id
union = union_all(
select_events_context_id_subquery(start_day, end_day, event_types).where(
_apply_event_entity_id_device_id_matchers(
json_quotable_entity_ids, json_quotable_device_ids
)
),
apply_entities_hints(select(States.context_id))
.filter((States.last_updated > start_day) & (States.last_updated < end_day))
.where(States.entity_id.in_(entity_ids)),
)
return select(union.c.context_id).group_by(union.c.context_id)
def _apply_entities_devices_context_union(
@ -66,14 +67,23 @@ def _apply_entities_devices_context_union(
json_quotable_entity_ids,
json_quotable_device_ids,
).cte()
# We used to optimize this to exclude rows we already in the union with
# a States.entity_id.not_in(entity_ids) but that made the
# query much slower on MySQL, and since we already filter them away
# in the python code anyways since they will have context_only
# set on them the impact is minimal.
return query.union_all(
states_query_for_entity_ids(start_day, end_day, entity_ids),
select_events_context_only().where(
Events.context_id.in_(devices_entities_cte.select())
apply_events_context_hints(
select_events_context_only()
.select_from(devices_entities_cte)
.outerjoin(Events, devices_entities_cte.c.context_id == Events.context_id)
).outerjoin(EventData, (Events.data_id == EventData.data_id)),
apply_states_context_hints(
select_states_context_only()
.select_from(devices_entities_cte)
.outerjoin(States, devices_entities_cte.c.context_id == States.context_id)
),
select_states_context_only()
.where(States.entity_id.not_in(entity_ids))
.where(States.context_id.in_(devices_entities_cte.select())),
)

View File

@ -110,7 +110,7 @@ def _state_schema(state):
PLATFORM_SCHEMA = vol.Schema(
vol.All(
mqtt.MQTT_BASE_PLATFORM_SCHEMA.extend(
mqtt.config.MQTT_BASE_SCHEMA.extend(
{
vol.Required(CONF_PLATFORM): "manual_mqtt",
vol.Optional(CONF_NAME, default=DEFAULT_ALARM_NAME): cv.string,

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,6 @@
"""This platform enables the possibility to control a MQTT alarm."""
from __future__ import annotations
import asyncio
import functools
import logging
import re
@ -31,8 +30,8 @@ import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
from . import MqttCommandTemplate, MqttValueTemplate, subscription
from .. import mqtt
from . import subscription
from .config import DEFAULT_RETAIN, MQTT_BASE_SCHEMA
from .const import (
CONF_COMMAND_TEMPLATE,
CONF_COMMAND_TOPIC,
@ -45,11 +44,13 @@ from .debug_info import log_messages
from .mixins import (
MQTT_ENTITY_COMMON_SCHEMA,
MqttEntity,
async_get_platform_config_from_yaml,
async_setup_entry_helper,
async_setup_platform_discovery,
async_setup_platform_helper,
warn_for_legacy_schema,
)
from .models import MqttCommandTemplate, MqttValueTemplate
from .util import valid_publish_topic, valid_subscribe_topic
_LOGGER = logging.getLogger(__name__)
@ -85,7 +86,7 @@ DEFAULT_NAME = "MQTT Alarm"
REMOTE_CODE = "REMOTE_CODE"
REMOTE_CODE_TEXT = "REMOTE_CODE_TEXT"
PLATFORM_SCHEMA_MODERN = mqtt.MQTT_BASE_SCHEMA.extend(
PLATFORM_SCHEMA_MODERN = MQTT_BASE_SCHEMA.extend(
{
vol.Optional(CONF_CODE): cv.string,
vol.Optional(CONF_CODE_ARM_REQUIRED, default=True): cv.boolean,
@ -94,7 +95,7 @@ PLATFORM_SCHEMA_MODERN = mqtt.MQTT_BASE_SCHEMA.extend(
vol.Optional(
CONF_COMMAND_TEMPLATE, default=DEFAULT_COMMAND_TEMPLATE
): cv.template,
vol.Required(CONF_COMMAND_TOPIC): mqtt.valid_publish_topic,
vol.Required(CONF_COMMAND_TOPIC): valid_publish_topic,
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
vol.Optional(CONF_PAYLOAD_ARM_AWAY, default=DEFAULT_ARM_AWAY): cv.string,
vol.Optional(CONF_PAYLOAD_ARM_HOME, default=DEFAULT_ARM_HOME): cv.string,
@ -107,8 +108,8 @@ PLATFORM_SCHEMA_MODERN = mqtt.MQTT_BASE_SCHEMA.extend(
): cv.string,
vol.Optional(CONF_PAYLOAD_DISARM, default=DEFAULT_DISARM): cv.string,
vol.Optional(CONF_PAYLOAD_TRIGGER, default=DEFAULT_TRIGGER): cv.string,
vol.Optional(CONF_RETAIN, default=mqtt.DEFAULT_RETAIN): cv.boolean,
vol.Required(CONF_STATE_TOPIC): mqtt.valid_subscribe_topic,
vol.Optional(CONF_RETAIN, default=DEFAULT_RETAIN): cv.boolean,
vol.Required(CONF_STATE_TOPIC): valid_subscribe_topic,
vol.Optional(CONF_VALUE_TEMPLATE): cv.template,
}
).extend(MQTT_ENTITY_COMMON_SCHEMA.schema)
@ -131,7 +132,11 @@ async def async_setup_platform(
"""Set up MQTT alarm control panel configured under the alarm_control_panel key (deprecated)."""
# Deprecated in HA Core 2022.6
await async_setup_platform_helper(
hass, alarm.DOMAIN, config, async_add_entities, _async_setup_entity
hass,
alarm.DOMAIN,
discovery_info or config,
async_add_entities,
_async_setup_entity,
)
@ -142,13 +147,8 @@ async def async_setup_entry(
) -> None:
"""Set up MQTT alarm control panel 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, alarm.DOMAIN, PLATFORM_SCHEMA_MODERN
)
)
config_entry.async_on_unload(
await async_setup_platform_discovery(hass, alarm.DOMAIN, PLATFORM_SCHEMA_MODERN)
)
# setup for discovery
setup = functools.partial(

View File

@ -1,7 +1,6 @@
"""Support for MQTT binary sensors."""
from __future__ import annotations
import asyncio
from datetime import timedelta
import functools
import logging
@ -34,19 +33,20 @@ from homeassistant.helpers.restore_state import RestoreEntity
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
from homeassistant.util import dt as dt_util
from . import MqttValueTemplate, subscription
from .. import mqtt
from . import subscription
from .config import MQTT_RO_SCHEMA
from .const import CONF_ENCODING, CONF_QOS, CONF_STATE_TOPIC, PAYLOAD_NONE
from .debug_info import log_messages
from .mixins import (
MQTT_ENTITY_COMMON_SCHEMA,
MqttAvailability,
MqttEntity,
async_get_platform_config_from_yaml,
async_setup_entry_helper,
async_setup_platform_discovery,
async_setup_platform_helper,
warn_for_legacy_schema,
)
from .models import MqttValueTemplate
_LOGGER = logging.getLogger(__name__)
@ -57,7 +57,7 @@ DEFAULT_PAYLOAD_ON = "ON"
DEFAULT_FORCE_UPDATE = False
CONF_EXPIRE_AFTER = "expire_after"
PLATFORM_SCHEMA_MODERN = mqtt.MQTT_RO_SCHEMA.extend(
PLATFORM_SCHEMA_MODERN = MQTT_RO_SCHEMA.extend(
{
vol.Optional(CONF_DEVICE_CLASS): DEVICE_CLASSES_SCHEMA,
vol.Optional(CONF_EXPIRE_AFTER): cv.positive_int,
@ -87,7 +87,11 @@ async def async_setup_platform(
"""Set up MQTT binary sensor configured under the fan platform key (deprecated)."""
# Deprecated in HA Core 2022.6
await async_setup_platform_helper(
hass, binary_sensor.DOMAIN, config, async_add_entities, _async_setup_entity
hass,
binary_sensor.DOMAIN,
discovery_info or config,
async_add_entities,
_async_setup_entity,
)
@ -98,12 +102,9 @@ async def async_setup_entry(
) -> None:
"""Set up MQTT binary sensor 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, binary_sensor.DOMAIN, PLATFORM_SCHEMA_MODERN
)
config_entry.async_on_unload(
await async_setup_platform_discovery(
hass, binary_sensor.DOMAIN, PLATFORM_SCHEMA_MODERN
)
)
# setup for discovery

View File

@ -1,7 +1,6 @@
"""Support for MQTT buttons."""
from __future__ import annotations
import asyncio
import functools
import voluptuous as vol
@ -15,8 +14,7 @@ import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
from . import MqttCommandTemplate
from .. import mqtt
from .config import DEFAULT_RETAIN, MQTT_BASE_SCHEMA
from .const import (
CONF_COMMAND_TEMPLATE,
CONF_COMMAND_TOPIC,
@ -27,24 +25,26 @@ from .const import (
from .mixins import (
MQTT_ENTITY_COMMON_SCHEMA,
MqttEntity,
async_get_platform_config_from_yaml,
async_setup_entry_helper,
async_setup_platform_discovery,
async_setup_platform_helper,
warn_for_legacy_schema,
)
from .models import MqttCommandTemplate
from .util import valid_publish_topic
CONF_PAYLOAD_PRESS = "payload_press"
DEFAULT_NAME = "MQTT Button"
DEFAULT_PAYLOAD_PRESS = "PRESS"
PLATFORM_SCHEMA_MODERN = mqtt.MQTT_BASE_SCHEMA.extend(
PLATFORM_SCHEMA_MODERN = MQTT_BASE_SCHEMA.extend(
{
vol.Optional(CONF_COMMAND_TEMPLATE): cv.template,
vol.Required(CONF_COMMAND_TOPIC): mqtt.valid_publish_topic,
vol.Required(CONF_COMMAND_TOPIC): valid_publish_topic,
vol.Optional(CONF_DEVICE_CLASS): button.DEVICE_CLASSES_SCHEMA,
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
vol.Optional(CONF_PAYLOAD_PRESS, default=DEFAULT_PAYLOAD_PRESS): cv.string,
vol.Optional(CONF_RETAIN, default=mqtt.DEFAULT_RETAIN): cv.boolean,
vol.Optional(CONF_RETAIN, default=DEFAULT_RETAIN): cv.boolean,
}
).extend(MQTT_ENTITY_COMMON_SCHEMA.schema)
@ -67,7 +67,11 @@ async def async_setup_platform(
"""Set up MQTT button configured under the fan platform key (deprecated)."""
# Deprecated in HA Core 2022.6
await async_setup_platform_helper(
hass, button.DOMAIN, config, async_add_entities, _async_setup_entity
hass,
button.DOMAIN,
discovery_info or config,
async_add_entities,
_async_setup_entity,
)
@ -78,12 +82,9 @@ async def async_setup_entry(
) -> None:
"""Set up MQTT button 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, button.DOMAIN, PLATFORM_SCHEMA_MODERN
)
config_entry.async_on_unload(
await async_setup_platform_discovery(
hass, button.DOMAIN, PLATFORM_SCHEMA_MODERN
)
)
# setup for discovery

View File

@ -1,7 +1,6 @@
"""Camera that loads a picture from an MQTT topic."""
from __future__ import annotations
import asyncio
from base64 import b64decode
import functools
@ -17,17 +16,18 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
from . import subscription
from .. import mqtt
from .config import MQTT_BASE_SCHEMA
from .const import CONF_ENCODING, CONF_QOS, CONF_TOPIC
from .debug_info import log_messages
from .mixins import (
MQTT_ENTITY_COMMON_SCHEMA,
MqttEntity,
async_get_platform_config_from_yaml,
async_setup_entry_helper,
async_setup_platform_discovery,
async_setup_platform_helper,
warn_for_legacy_schema,
)
from .util import valid_subscribe_topic
DEFAULT_NAME = "MQTT Camera"
@ -40,10 +40,10 @@ MQTT_CAMERA_ATTRIBUTES_BLOCKED = frozenset(
}
)
PLATFORM_SCHEMA_MODERN = mqtt.MQTT_BASE_SCHEMA.extend(
PLATFORM_SCHEMA_MODERN = MQTT_BASE_SCHEMA.extend(
{
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
vol.Required(CONF_TOPIC): mqtt.valid_subscribe_topic,
vol.Required(CONF_TOPIC): valid_subscribe_topic,
}
).extend(MQTT_ENTITY_COMMON_SCHEMA.schema)
@ -65,7 +65,11 @@ async def async_setup_platform(
"""Set up MQTT camera configured under the camera platform key (deprecated)."""
# Deprecated in HA Core 2022.6
await async_setup_platform_helper(
hass, camera.DOMAIN, config, async_add_entities, _async_setup_entity
hass,
camera.DOMAIN,
discovery_info or config,
async_add_entities,
_async_setup_entity,
)
@ -76,12 +80,9 @@ async def async_setup_entry(
) -> None:
"""Set up MQTT camera 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, camera.DOMAIN, PLATFORM_SCHEMA_MODERN
)
config_entry.async_on_unload(
await async_setup_platform_discovery(
hass, camera.DOMAIN, PLATFORM_SCHEMA_MODERN
)
)
# setup for discovery

View File

@ -0,0 +1,659 @@
"""Support for MQTT message handling."""
from __future__ import annotations
import asyncio
from collections.abc import Awaitable, Callable
from functools import lru_cache, partial, wraps
import inspect
from itertools import groupby
import logging
from operator import attrgetter
import ssl
import time
from typing import TYPE_CHECKING, Any, Union, cast
import uuid
import attr
import certifi
from homeassistant.const import (
CONF_CLIENT_ID,
CONF_PASSWORD,
CONF_PORT,
CONF_PROTOCOL,
CONF_USERNAME,
EVENT_HOMEASSISTANT_STARTED,
)
from homeassistant.core import CoreState, HassJob, HomeAssistant, callback
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers.dispatcher import dispatcher_send
from homeassistant.helpers.typing import ConfigType
from homeassistant.loader import bind_hass
from homeassistant.util import dt as dt_util
from homeassistant.util.async_ import run_callback_threadsafe
from homeassistant.util.logging import catch_log_exception
from .const import (
ATTR_TOPIC,
CONF_BIRTH_MESSAGE,
CONF_BROKER,
CONF_CERTIFICATE,
CONF_CLIENT_CERT,
CONF_CLIENT_KEY,
CONF_KEEPALIVE,
CONF_TLS_INSECURE,
CONF_WILL_MESSAGE,
DATA_MQTT,
DEFAULT_ENCODING,
DEFAULT_QOS,
MQTT_CONNECTED,
MQTT_DISCONNECTED,
PROTOCOL_31,
)
from .discovery import LAST_DISCOVERY
from .models import (
AsyncMessageCallbackType,
MessageCallbackType,
PublishMessage,
PublishPayloadType,
ReceiveMessage,
ReceivePayloadType,
)
if TYPE_CHECKING:
# Only import for paho-mqtt type checking here, imports are done locally
# because integrations should be able to optionally rely on MQTT.
import paho.mqtt.client as mqtt
_LOGGER = logging.getLogger(__name__)
DISCOVERY_COOLDOWN = 2
TIMEOUT_ACK = 10
SubscribePayloadType = Union[str, bytes] # Only bytes if encoding is None
def publish(
hass: HomeAssistant,
topic: str,
payload: PublishPayloadType,
qos: int | None = 0,
retain: bool | None = False,
encoding: str | None = DEFAULT_ENCODING,
) -> None:
"""Publish message to a MQTT topic."""
hass.add_job(async_publish, hass, topic, payload, qos, retain, encoding)
async def async_publish(
hass: HomeAssistant,
topic: str,
payload: PublishPayloadType,
qos: int | None = 0,
retain: bool | None = False,
encoding: str | None = DEFAULT_ENCODING,
) -> None:
"""Publish message to a MQTT topic."""
outgoing_payload = payload
if not isinstance(payload, bytes):
if not encoding:
_LOGGER.error(
"Can't pass-through payload for publishing %s on %s with no encoding set, need 'bytes' got %s",
payload,
topic,
type(payload),
)
return
outgoing_payload = str(payload)
if encoding != DEFAULT_ENCODING:
# a string is encoded as utf-8 by default, other encoding requires bytes as payload
try:
outgoing_payload = outgoing_payload.encode(encoding)
except (AttributeError, LookupError, UnicodeEncodeError):
_LOGGER.error(
"Can't encode payload for publishing %s on %s with encoding %s",
payload,
topic,
encoding,
)
return
await hass.data[DATA_MQTT].async_publish(topic, outgoing_payload, qos, retain)
AsyncDeprecatedMessageCallbackType = Callable[
[str, ReceivePayloadType, int], Awaitable[None]
]
DeprecatedMessageCallbackType = Callable[[str, ReceivePayloadType, int], None]
def wrap_msg_callback(
msg_callback: AsyncDeprecatedMessageCallbackType | DeprecatedMessageCallbackType,
) -> AsyncMessageCallbackType | MessageCallbackType:
"""Wrap an MQTT message callback to support deprecated signature."""
# Check for partials to properly determine if coroutine function
check_func = msg_callback
while isinstance(check_func, partial):
check_func = check_func.func
wrapper_func: AsyncMessageCallbackType | MessageCallbackType
if asyncio.iscoroutinefunction(check_func):
@wraps(msg_callback)
async def async_wrapper(msg: ReceiveMessage) -> None:
"""Call with deprecated signature."""
await cast(AsyncDeprecatedMessageCallbackType, msg_callback)(
msg.topic, msg.payload, msg.qos
)
wrapper_func = async_wrapper
else:
@wraps(msg_callback)
def wrapper(msg: ReceiveMessage) -> None:
"""Call with deprecated signature."""
msg_callback(msg.topic, msg.payload, msg.qos)
wrapper_func = wrapper
return wrapper_func
@bind_hass
async def async_subscribe(
hass: HomeAssistant,
topic: str,
msg_callback: AsyncMessageCallbackType
| MessageCallbackType
| DeprecatedMessageCallbackType
| AsyncDeprecatedMessageCallbackType,
qos: int = DEFAULT_QOS,
encoding: str | None = "utf-8",
):
"""Subscribe to an MQTT topic.
Call the return value to unsubscribe.
"""
# Count callback parameters which don't have a default value
non_default = 0
if msg_callback:
non_default = sum(
p.default == inspect.Parameter.empty
for _, p in inspect.signature(msg_callback).parameters.items()
)
wrapped_msg_callback = msg_callback
# If we have 3 parameters with no default value, wrap the callback
if non_default == 3:
module = inspect.getmodule(msg_callback)
_LOGGER.warning(
"Signature of MQTT msg_callback '%s.%s' is deprecated",
module.__name__ if module else "<unknown>",
msg_callback.__name__,
)
wrapped_msg_callback = wrap_msg_callback(
cast(DeprecatedMessageCallbackType, msg_callback)
)
async_remove = await hass.data[DATA_MQTT].async_subscribe(
topic,
catch_log_exception(
wrapped_msg_callback,
lambda msg: (
f"Exception in {msg_callback.__name__} when handling msg on "
f"'{msg.topic}': '{msg.payload}'"
),
),
qos,
encoding,
)
return async_remove
@bind_hass
def subscribe(
hass: HomeAssistant,
topic: str,
msg_callback: MessageCallbackType,
qos: int = DEFAULT_QOS,
encoding: str = "utf-8",
) -> Callable[[], None]:
"""Subscribe to an MQTT topic."""
async_remove = asyncio.run_coroutine_threadsafe(
async_subscribe(hass, topic, msg_callback, qos, encoding), hass.loop
).result()
def remove():
"""Remove listener convert."""
run_callback_threadsafe(hass.loop, async_remove).result()
return remove
@attr.s(slots=True, frozen=True)
class Subscription:
"""Class to hold data about an active subscription."""
topic: str = attr.ib()
matcher: Any = attr.ib()
job: HassJob = attr.ib()
qos: int = attr.ib(default=0)
encoding: str | None = attr.ib(default="utf-8")
class MqttClientSetup:
"""Helper class to setup the paho mqtt client from config."""
def __init__(self, config: ConfigType) -> None:
"""Initialize the MQTT client setup helper."""
# We don't import on the top because some integrations
# should be able to optionally rely on MQTT.
import paho.mqtt.client as mqtt # pylint: disable=import-outside-toplevel
if config[CONF_PROTOCOL] == PROTOCOL_31:
proto = mqtt.MQTTv31
else:
proto = mqtt.MQTTv311
if (client_id := config.get(CONF_CLIENT_ID)) is None:
# PAHO MQTT relies on the MQTT server to generate random client IDs.
# However, that feature is not mandatory so we generate our own.
client_id = mqtt.base62(uuid.uuid4().int, padding=22)
self._client = mqtt.Client(client_id, protocol=proto)
# Enable logging
self._client.enable_logger()
username = config.get(CONF_USERNAME)
password = config.get(CONF_PASSWORD)
if username is not None:
self._client.username_pw_set(username, password)
if (certificate := config.get(CONF_CERTIFICATE)) == "auto":
certificate = certifi.where()
client_key = config.get(CONF_CLIENT_KEY)
client_cert = config.get(CONF_CLIENT_CERT)
tls_insecure = config.get(CONF_TLS_INSECURE)
if certificate is not None:
self._client.tls_set(
certificate,
certfile=client_cert,
keyfile=client_key,
tls_version=ssl.PROTOCOL_TLS,
)
if tls_insecure is not None:
self._client.tls_insecure_set(tls_insecure)
@property
def client(self) -> mqtt.Client:
"""Return the paho MQTT client."""
return self._client
class MQTT:
"""Home Assistant MQTT client."""
def __init__(
self,
hass: HomeAssistant,
config_entry,
conf,
) -> None:
"""Initialize Home Assistant MQTT client."""
# We don't import on the top because some integrations
# should be able to optionally rely on MQTT.
import paho.mqtt.client as mqtt # pylint: disable=import-outside-toplevel
self.hass = hass
self.config_entry = config_entry
self.conf = conf
self.subscriptions: list[Subscription] = []
self.connected = False
self._ha_started = asyncio.Event()
self._last_subscribe = time.time()
self._mqttc: mqtt.Client = None
self._paho_lock = asyncio.Lock()
self._pending_operations: dict[str, asyncio.Event] = {}
if self.hass.state == CoreState.running:
self._ha_started.set()
else:
@callback
def ha_started(_):
self._ha_started.set()
self.hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STARTED, ha_started)
self.init_client()
def init_client(self):
"""Initialize paho client."""
self._mqttc = MqttClientSetup(self.conf).client
self._mqttc.on_connect = self._mqtt_on_connect
self._mqttc.on_disconnect = self._mqtt_on_disconnect
self._mqttc.on_message = self._mqtt_on_message
self._mqttc.on_publish = self._mqtt_on_callback
self._mqttc.on_subscribe = self._mqtt_on_callback
self._mqttc.on_unsubscribe = self._mqtt_on_callback
if (
CONF_WILL_MESSAGE in self.conf
and ATTR_TOPIC in self.conf[CONF_WILL_MESSAGE]
):
will_message = PublishMessage(**self.conf[CONF_WILL_MESSAGE])
else:
will_message = None
if will_message is not None:
self._mqttc.will_set(
topic=will_message.topic,
payload=will_message.payload,
qos=will_message.qos,
retain=will_message.retain,
)
async def async_publish(
self, topic: str, payload: PublishPayloadType, qos: int, retain: bool
) -> None:
"""Publish a MQTT message."""
async with self._paho_lock:
msg_info = await self.hass.async_add_executor_job(
self._mqttc.publish, topic, payload, qos, retain
)
_LOGGER.debug(
"Transmitting message on %s: '%s', mid: %s",
topic,
payload,
msg_info.mid,
)
_raise_on_error(msg_info.rc)
await self._wait_for_mid(msg_info.mid)
async def async_connect(self) -> None:
"""Connect to the host. Does not process messages yet."""
# pylint: disable-next=import-outside-toplevel
import paho.mqtt.client as mqtt
result: int | None = None
try:
result = await self.hass.async_add_executor_job(
self._mqttc.connect,
self.conf[CONF_BROKER],
self.conf[CONF_PORT],
self.conf[CONF_KEEPALIVE],
)
except OSError as err:
_LOGGER.error("Failed to connect to MQTT server due to exception: %s", err)
if result is not None and result != 0:
_LOGGER.error(
"Failed to connect to MQTT server: %s", mqtt.error_string(result)
)
self._mqttc.loop_start()
async def async_disconnect(self):
"""Stop the MQTT client."""
def stop():
"""Stop the MQTT client."""
# Do not disconnect, we want the broker to always publish will
self._mqttc.loop_stop()
await self.hass.async_add_executor_job(stop)
async def async_subscribe(
self,
topic: str,
msg_callback: MessageCallbackType,
qos: int,
encoding: str | None = None,
) -> Callable[[], None]:
"""Set up a subscription to a topic with the provided qos.
This method is a coroutine.
"""
if not isinstance(topic, str):
raise HomeAssistantError("Topic needs to be a string!")
subscription = Subscription(
topic, _matcher_for_topic(topic), HassJob(msg_callback), qos, encoding
)
self.subscriptions.append(subscription)
self._matching_subscriptions.cache_clear()
# Only subscribe if currently connected.
if self.connected:
self._last_subscribe = time.time()
await self._async_perform_subscription(topic, qos)
@callback
def async_remove() -> None:
"""Remove subscription."""
if subscription not in self.subscriptions:
raise HomeAssistantError("Can't remove subscription twice")
self.subscriptions.remove(subscription)
self._matching_subscriptions.cache_clear()
# Only unsubscribe if currently connected.
if self.connected:
self.hass.async_create_task(self._async_unsubscribe(topic))
return async_remove
async def _async_unsubscribe(self, topic: str) -> None:
"""Unsubscribe from a topic.
This method is a coroutine.
"""
if any(other.topic == topic for other in self.subscriptions):
# Other subscriptions on topic remaining - don't unsubscribe.
return
async with self._paho_lock:
result: int | None = None
result, mid = await self.hass.async_add_executor_job(
self._mqttc.unsubscribe, topic
)
_LOGGER.debug("Unsubscribing from %s, mid: %s", topic, mid)
_raise_on_error(result)
await self._wait_for_mid(mid)
async def _async_perform_subscription(self, topic: str, qos: int) -> None:
"""Perform a paho-mqtt subscription."""
async with self._paho_lock:
result: int | None = None
result, mid = await self.hass.async_add_executor_job(
self._mqttc.subscribe, topic, qos
)
_LOGGER.debug("Subscribing to %s, mid: %s", topic, mid)
_raise_on_error(result)
await self._wait_for_mid(mid)
def _mqtt_on_connect(self, _mqttc, _userdata, _flags, result_code: int) -> None:
"""On connect callback.
Resubscribe to all topics we were subscribed to and publish birth
message.
"""
# pylint: disable-next=import-outside-toplevel
import paho.mqtt.client as mqtt
if result_code != mqtt.CONNACK_ACCEPTED:
_LOGGER.error(
"Unable to connect to the MQTT broker: %s",
mqtt.connack_string(result_code),
)
return
self.connected = True
dispatcher_send(self.hass, MQTT_CONNECTED)
_LOGGER.info(
"Connected to MQTT server %s:%s (%s)",
self.conf[CONF_BROKER],
self.conf[CONF_PORT],
result_code,
)
# Group subscriptions to only re-subscribe once for each topic.
keyfunc = attrgetter("topic")
for topic, subs in groupby(sorted(self.subscriptions, key=keyfunc), keyfunc):
# Re-subscribe with the highest requested qos
max_qos = max(subscription.qos for subscription in subs)
self.hass.add_job(self._async_perform_subscription, topic, max_qos)
if (
CONF_BIRTH_MESSAGE in self.conf
and ATTR_TOPIC in self.conf[CONF_BIRTH_MESSAGE]
):
async def publish_birth_message(birth_message):
await self._ha_started.wait() # Wait for Home Assistant to start
await self._discovery_cooldown() # Wait for MQTT discovery to cool down
await self.async_publish(
topic=birth_message.topic,
payload=birth_message.payload,
qos=birth_message.qos,
retain=birth_message.retain,
)
birth_message = PublishMessage(**self.conf[CONF_BIRTH_MESSAGE])
asyncio.run_coroutine_threadsafe(
publish_birth_message(birth_message), self.hass.loop
)
def _mqtt_on_message(self, _mqttc, _userdata, msg) -> None:
"""Message received callback."""
self.hass.add_job(self._mqtt_handle_message, msg)
@lru_cache(2048)
def _matching_subscriptions(self, topic):
subscriptions = []
for subscription in self.subscriptions:
if subscription.matcher(topic):
subscriptions.append(subscription)
return subscriptions
@callback
def _mqtt_handle_message(self, msg) -> None:
_LOGGER.debug(
"Received message on %s%s: %s",
msg.topic,
" (retained)" if msg.retain else "",
msg.payload[0:8192],
)
timestamp = dt_util.utcnow()
subscriptions = self._matching_subscriptions(msg.topic)
for subscription in subscriptions:
payload: SubscribePayloadType = msg.payload
if subscription.encoding is not None:
try:
payload = msg.payload.decode(subscription.encoding)
except (AttributeError, UnicodeDecodeError):
_LOGGER.warning(
"Can't decode payload %s on %s with encoding %s (for %s)",
msg.payload[0:8192],
msg.topic,
subscription.encoding,
subscription.job,
)
continue
self.hass.async_run_hass_job(
subscription.job,
ReceiveMessage(
msg.topic,
payload,
msg.qos,
msg.retain,
subscription.topic,
timestamp,
),
)
def _mqtt_on_callback(self, _mqttc, _userdata, mid, _granted_qos=None) -> None:
"""Publish / Subscribe / Unsubscribe callback."""
self.hass.add_job(self._mqtt_handle_mid, mid)
@callback
def _mqtt_handle_mid(self, mid) -> None:
# Create the mid event if not created, either _mqtt_handle_mid or _wait_for_mid
# may be executed first.
if mid not in self._pending_operations:
self._pending_operations[mid] = asyncio.Event()
self._pending_operations[mid].set()
def _mqtt_on_disconnect(self, _mqttc, _userdata, result_code: int) -> None:
"""Disconnected callback."""
self.connected = False
dispatcher_send(self.hass, MQTT_DISCONNECTED)
_LOGGER.warning(
"Disconnected from MQTT server %s:%s (%s)",
self.conf[CONF_BROKER],
self.conf[CONF_PORT],
result_code,
)
async def _wait_for_mid(self, mid):
"""Wait for ACK from broker."""
# Create the mid event if not created, either _mqtt_handle_mid or _wait_for_mid
# may be executed first.
if mid not in self._pending_operations:
self._pending_operations[mid] = asyncio.Event()
try:
await asyncio.wait_for(self._pending_operations[mid].wait(), TIMEOUT_ACK)
except asyncio.TimeoutError:
_LOGGER.warning(
"No ACK from MQTT server in %s seconds (mid: %s)", TIMEOUT_ACK, mid
)
finally:
del self._pending_operations[mid]
async def _discovery_cooldown(self):
now = time.time()
# Reset discovery and subscribe cooldowns
self.hass.data[LAST_DISCOVERY] = now
self._last_subscribe = now
last_discovery = self.hass.data[LAST_DISCOVERY]
last_subscribe = self._last_subscribe
wait_until = max(
last_discovery + DISCOVERY_COOLDOWN, last_subscribe + DISCOVERY_COOLDOWN
)
while now < wait_until:
await asyncio.sleep(wait_until - now)
now = time.time()
last_discovery = self.hass.data[LAST_DISCOVERY]
last_subscribe = self._last_subscribe
wait_until = max(
last_discovery + DISCOVERY_COOLDOWN, last_subscribe + DISCOVERY_COOLDOWN
)
def _raise_on_error(result_code: int | None) -> None:
"""Raise error if error result."""
# pylint: disable-next=import-outside-toplevel
import paho.mqtt.client as mqtt
if result_code is not None and result_code != 0:
raise HomeAssistantError(
f"Error talking to MQTT: {mqtt.error_string(result_code)}"
)
def _matcher_for_topic(subscription: str) -> Any:
# pylint: disable-next=import-outside-toplevel
from paho.mqtt.matcher import MQTTMatcher
matcher = MQTTMatcher()
matcher[subscription] = True
return lambda topic: next(matcher.iter_match(topic), False)

View File

@ -1,7 +1,6 @@
"""Support for MQTT climate devices."""
from __future__ import annotations
import asyncio
import functools
import logging
@ -44,18 +43,20 @@ import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
from . import MqttCommandTemplate, MqttValueTemplate, subscription
from .. import mqtt
from . import subscription
from .config import DEFAULT_RETAIN, MQTT_BASE_SCHEMA
from .const import CONF_ENCODING, CONF_QOS, CONF_RETAIN, PAYLOAD_NONE
from .debug_info import log_messages
from .mixins import (
MQTT_ENTITY_COMMON_SCHEMA,
MqttEntity,
async_get_platform_config_from_yaml,
async_setup_entry_helper,
async_setup_platform_discovery,
async_setup_platform_helper,
warn_for_legacy_schema,
)
from .models import MqttCommandTemplate, MqttValueTemplate
from .util import valid_publish_topic, valid_subscribe_topic
_LOGGER = logging.getLogger(__name__)
@ -232,33 +233,33 @@ def valid_preset_mode_configuration(config):
return config
_PLATFORM_SCHEMA_BASE = mqtt.MQTT_BASE_SCHEMA.extend(
_PLATFORM_SCHEMA_BASE = MQTT_BASE_SCHEMA.extend(
{
vol.Optional(CONF_AUX_COMMAND_TOPIC): mqtt.valid_publish_topic,
vol.Optional(CONF_AUX_COMMAND_TOPIC): valid_publish_topic,
vol.Optional(CONF_AUX_STATE_TEMPLATE): cv.template,
vol.Optional(CONF_AUX_STATE_TOPIC): mqtt.valid_subscribe_topic,
vol.Optional(CONF_AUX_STATE_TOPIC): valid_subscribe_topic,
# AWAY and HOLD mode topics and templates are deprecated, support will be removed with release 2022.9
vol.Optional(CONF_AWAY_MODE_COMMAND_TOPIC): mqtt.valid_publish_topic,
vol.Optional(CONF_AWAY_MODE_COMMAND_TOPIC): valid_publish_topic,
vol.Optional(CONF_AWAY_MODE_STATE_TEMPLATE): cv.template,
vol.Optional(CONF_AWAY_MODE_STATE_TOPIC): mqtt.valid_subscribe_topic,
vol.Optional(CONF_AWAY_MODE_STATE_TOPIC): valid_subscribe_topic,
vol.Optional(CONF_CURRENT_TEMP_TEMPLATE): cv.template,
vol.Optional(CONF_CURRENT_TEMP_TOPIC): mqtt.valid_subscribe_topic,
vol.Optional(CONF_CURRENT_TEMP_TOPIC): valid_subscribe_topic,
vol.Optional(CONF_FAN_MODE_COMMAND_TEMPLATE): cv.template,
vol.Optional(CONF_FAN_MODE_COMMAND_TOPIC): mqtt.valid_publish_topic,
vol.Optional(CONF_FAN_MODE_COMMAND_TOPIC): valid_publish_topic,
vol.Optional(
CONF_FAN_MODE_LIST,
default=[FAN_AUTO, FAN_LOW, FAN_MEDIUM, FAN_HIGH],
): cv.ensure_list,
vol.Optional(CONF_FAN_MODE_STATE_TEMPLATE): cv.template,
vol.Optional(CONF_FAN_MODE_STATE_TOPIC): mqtt.valid_subscribe_topic,
vol.Optional(CONF_FAN_MODE_STATE_TOPIC): valid_subscribe_topic,
# AWAY and HOLD mode topics and templates are deprecated, support will be removed with release 2022.9
vol.Optional(CONF_HOLD_COMMAND_TEMPLATE): cv.template,
vol.Optional(CONF_HOLD_COMMAND_TOPIC): mqtt.valid_publish_topic,
vol.Optional(CONF_HOLD_COMMAND_TOPIC): valid_publish_topic,
vol.Optional(CONF_HOLD_STATE_TEMPLATE): cv.template,
vol.Optional(CONF_HOLD_STATE_TOPIC): mqtt.valid_subscribe_topic,
vol.Optional(CONF_HOLD_STATE_TOPIC): valid_subscribe_topic,
vol.Optional(CONF_HOLD_LIST): cv.ensure_list,
vol.Optional(CONF_MODE_COMMAND_TEMPLATE): cv.template,
vol.Optional(CONF_MODE_COMMAND_TOPIC): mqtt.valid_publish_topic,
vol.Optional(CONF_MODE_COMMAND_TOPIC): valid_publish_topic,
vol.Optional(
CONF_MODE_LIST,
default=[
@ -271,54 +272,54 @@ _PLATFORM_SCHEMA_BASE = mqtt.MQTT_BASE_SCHEMA.extend(
],
): cv.ensure_list,
vol.Optional(CONF_MODE_STATE_TEMPLATE): cv.template,
vol.Optional(CONF_MODE_STATE_TOPIC): mqtt.valid_subscribe_topic,
vol.Optional(CONF_MODE_STATE_TOPIC): valid_subscribe_topic,
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
vol.Optional(CONF_PAYLOAD_ON, default="ON"): cv.string,
vol.Optional(CONF_PAYLOAD_OFF, default="OFF"): cv.string,
vol.Optional(CONF_POWER_COMMAND_TOPIC): mqtt.valid_publish_topic,
vol.Optional(CONF_POWER_COMMAND_TOPIC): valid_publish_topic,
vol.Optional(CONF_POWER_STATE_TEMPLATE): cv.template,
vol.Optional(CONF_POWER_STATE_TOPIC): mqtt.valid_subscribe_topic,
vol.Optional(CONF_POWER_STATE_TOPIC): valid_subscribe_topic,
vol.Optional(CONF_PRECISION): vol.In(
[PRECISION_TENTHS, PRECISION_HALVES, PRECISION_WHOLE]
),
vol.Optional(CONF_RETAIN, default=mqtt.DEFAULT_RETAIN): cv.boolean,
vol.Optional(CONF_RETAIN, default=DEFAULT_RETAIN): cv.boolean,
# CONF_SEND_IF_OFF is deprecated, support will be removed with release 2022.9
vol.Optional(CONF_SEND_IF_OFF): cv.boolean,
vol.Optional(CONF_ACTION_TEMPLATE): cv.template,
vol.Optional(CONF_ACTION_TOPIC): mqtt.valid_subscribe_topic,
vol.Optional(CONF_ACTION_TOPIC): valid_subscribe_topic,
# CONF_PRESET_MODE_COMMAND_TOPIC and CONF_PRESET_MODES_LIST must be used together
vol.Inclusive(
CONF_PRESET_MODE_COMMAND_TOPIC, "preset_modes"
): mqtt.valid_publish_topic,
): valid_publish_topic,
vol.Inclusive(
CONF_PRESET_MODES_LIST, "preset_modes", default=[]
): cv.ensure_list,
vol.Optional(CONF_PRESET_MODE_COMMAND_TEMPLATE): cv.template,
vol.Optional(CONF_PRESET_MODE_STATE_TOPIC): mqtt.valid_subscribe_topic,
vol.Optional(CONF_PRESET_MODE_STATE_TOPIC): valid_subscribe_topic,
vol.Optional(CONF_PRESET_MODE_VALUE_TEMPLATE): cv.template,
vol.Optional(CONF_SWING_MODE_COMMAND_TEMPLATE): cv.template,
vol.Optional(CONF_SWING_MODE_COMMAND_TOPIC): mqtt.valid_publish_topic,
vol.Optional(CONF_SWING_MODE_COMMAND_TOPIC): valid_publish_topic,
vol.Optional(
CONF_SWING_MODE_LIST, default=[SWING_ON, SWING_OFF]
): cv.ensure_list,
vol.Optional(CONF_SWING_MODE_STATE_TEMPLATE): cv.template,
vol.Optional(CONF_SWING_MODE_STATE_TOPIC): mqtt.valid_subscribe_topic,
vol.Optional(CONF_SWING_MODE_STATE_TOPIC): valid_subscribe_topic,
vol.Optional(CONF_TEMP_INITIAL, default=21): cv.positive_int,
vol.Optional(CONF_TEMP_MIN, default=DEFAULT_MIN_TEMP): vol.Coerce(float),
vol.Optional(CONF_TEMP_MAX, default=DEFAULT_MAX_TEMP): vol.Coerce(float),
vol.Optional(CONF_TEMP_STEP, default=1.0): vol.Coerce(float),
vol.Optional(CONF_TEMP_COMMAND_TEMPLATE): cv.template,
vol.Optional(CONF_TEMP_COMMAND_TOPIC): mqtt.valid_publish_topic,
vol.Optional(CONF_TEMP_COMMAND_TOPIC): valid_publish_topic,
vol.Optional(CONF_TEMP_HIGH_COMMAND_TEMPLATE): cv.template,
vol.Optional(CONF_TEMP_HIGH_COMMAND_TOPIC): mqtt.valid_publish_topic,
vol.Optional(CONF_TEMP_HIGH_STATE_TOPIC): mqtt.valid_subscribe_topic,
vol.Optional(CONF_TEMP_HIGH_COMMAND_TOPIC): valid_publish_topic,
vol.Optional(CONF_TEMP_HIGH_STATE_TOPIC): valid_subscribe_topic,
vol.Optional(CONF_TEMP_HIGH_STATE_TEMPLATE): cv.template,
vol.Optional(CONF_TEMP_LOW_COMMAND_TEMPLATE): cv.template,
vol.Optional(CONF_TEMP_LOW_COMMAND_TOPIC): mqtt.valid_publish_topic,
vol.Optional(CONF_TEMP_LOW_COMMAND_TOPIC): valid_publish_topic,
vol.Optional(CONF_TEMP_LOW_STATE_TEMPLATE): cv.template,
vol.Optional(CONF_TEMP_LOW_STATE_TOPIC): mqtt.valid_subscribe_topic,
vol.Optional(CONF_TEMP_LOW_STATE_TOPIC): valid_subscribe_topic,
vol.Optional(CONF_TEMP_STATE_TEMPLATE): cv.template,
vol.Optional(CONF_TEMP_STATE_TOPIC): mqtt.valid_subscribe_topic,
vol.Optional(CONF_TEMP_STATE_TOPIC): valid_subscribe_topic,
vol.Optional(CONF_TEMPERATURE_UNIT): cv.temperature_unit,
vol.Optional(CONF_VALUE_TEMPLATE): cv.template,
}
@ -375,7 +376,11 @@ async def async_setup_platform(
"""Set up MQTT climate configured under the fan platform key (deprecated)."""
# The use of PLATFORM_SCHEMA is deprecated in HA Core 2022.6
await async_setup_platform_helper(
hass, climate.DOMAIN, config, async_add_entities, _async_setup_entity
hass,
climate.DOMAIN,
discovery_info or config,
async_add_entities,
_async_setup_entity,
)
@ -386,12 +391,9 @@ async def async_setup_entry(
) -> None:
"""Set up MQTT climate device 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, climate.DOMAIN, PLATFORM_SCHEMA_MODERN
)
config_entry.async_on_unload(
await async_setup_platform_discovery(
hass, climate.DOMAIN, PLATFORM_SCHEMA_MODERN
)
)
# setup for discovery

View File

@ -0,0 +1,148 @@
"""Support for MQTT message handling."""
from __future__ import annotations
import voluptuous as vol
from homeassistant.const import (
CONF_CLIENT_ID,
CONF_DISCOVERY,
CONF_PASSWORD,
CONF_PORT,
CONF_PROTOCOL,
CONF_USERNAME,
CONF_VALUE_TEMPLATE,
)
from homeassistant.helpers import config_validation as cv
from .const import (
ATTR_PAYLOAD,
ATTR_QOS,
ATTR_RETAIN,
ATTR_TOPIC,
CONF_BIRTH_MESSAGE,
CONF_BROKER,
CONF_CERTIFICATE,
CONF_CLIENT_CERT,
CONF_CLIENT_KEY,
CONF_COMMAND_TOPIC,
CONF_DISCOVERY_PREFIX,
CONF_ENCODING,
CONF_KEEPALIVE,
CONF_QOS,
CONF_RETAIN,
CONF_STATE_TOPIC,
CONF_TLS_INSECURE,
CONF_TLS_VERSION,
CONF_WILL_MESSAGE,
DEFAULT_BIRTH,
DEFAULT_DISCOVERY,
DEFAULT_ENCODING,
DEFAULT_PREFIX,
DEFAULT_QOS,
DEFAULT_RETAIN,
DEFAULT_WILL,
PLATFORMS,
PROTOCOL_31,
PROTOCOL_311,
)
from .util import _VALID_QOS_SCHEMA, valid_publish_topic, valid_subscribe_topic
DEFAULT_PORT = 1883
DEFAULT_KEEPALIVE = 60
DEFAULT_PROTOCOL = PROTOCOL_311
DEFAULT_TLS_PROTOCOL = "auto"
DEFAULT_VALUES = {
CONF_BIRTH_MESSAGE: DEFAULT_BIRTH,
CONF_DISCOVERY: DEFAULT_DISCOVERY,
CONF_PORT: DEFAULT_PORT,
CONF_TLS_VERSION: DEFAULT_TLS_PROTOCOL,
CONF_WILL_MESSAGE: DEFAULT_WILL,
}
CLIENT_KEY_AUTH_MSG = (
"client_key and client_cert must both be present in "
"the MQTT broker configuration"
)
MQTT_WILL_BIRTH_SCHEMA = vol.Schema(
{
vol.Inclusive(ATTR_TOPIC, "topic_payload"): valid_publish_topic,
vol.Inclusive(ATTR_PAYLOAD, "topic_payload"): cv.string,
vol.Optional(ATTR_QOS, default=DEFAULT_QOS): _VALID_QOS_SCHEMA,
vol.Optional(ATTR_RETAIN, default=DEFAULT_RETAIN): cv.boolean,
},
required=True,
)
PLATFORM_CONFIG_SCHEMA_BASE = vol.Schema(
{vol.Optional(platform.value): cv.ensure_list for platform in PLATFORMS}
)
CONFIG_SCHEMA_BASE = PLATFORM_CONFIG_SCHEMA_BASE.extend(
{
vol.Optional(CONF_CLIENT_ID): cv.string,
vol.Optional(CONF_KEEPALIVE, default=DEFAULT_KEEPALIVE): vol.All(
vol.Coerce(int), vol.Range(min=15)
),
vol.Optional(CONF_BROKER): cv.string,
vol.Optional(CONF_PORT): cv.port,
vol.Optional(CONF_USERNAME): cv.string,
vol.Optional(CONF_PASSWORD): cv.string,
vol.Optional(CONF_CERTIFICATE): vol.Any("auto", cv.isfile),
vol.Inclusive(
CONF_CLIENT_KEY, "client_key_auth", msg=CLIENT_KEY_AUTH_MSG
): cv.isfile,
vol.Inclusive(
CONF_CLIENT_CERT, "client_key_auth", msg=CLIENT_KEY_AUTH_MSG
): cv.isfile,
vol.Optional(CONF_TLS_INSECURE): cv.boolean,
vol.Optional(CONF_TLS_VERSION): vol.Any("auto", "1.0", "1.1", "1.2"),
vol.Optional(CONF_PROTOCOL, default=DEFAULT_PROTOCOL): vol.All(
cv.string, vol.In([PROTOCOL_31, PROTOCOL_311])
),
vol.Optional(CONF_WILL_MESSAGE): MQTT_WILL_BIRTH_SCHEMA,
vol.Optional(CONF_BIRTH_MESSAGE): MQTT_WILL_BIRTH_SCHEMA,
vol.Optional(CONF_DISCOVERY): cv.boolean,
# discovery_prefix must be a valid publish topic because if no
# state topic is specified, it will be created with the given prefix.
vol.Optional(
CONF_DISCOVERY_PREFIX, default=DEFAULT_PREFIX
): valid_publish_topic,
}
)
DEPRECATED_CONFIG_KEYS = [
CONF_BIRTH_MESSAGE,
CONF_BROKER,
CONF_DISCOVERY,
CONF_PASSWORD,
CONF_PORT,
CONF_TLS_VERSION,
CONF_USERNAME,
CONF_WILL_MESSAGE,
]
SCHEMA_BASE = {
vol.Optional(CONF_QOS, default=DEFAULT_QOS): _VALID_QOS_SCHEMA,
vol.Optional(CONF_ENCODING, default=DEFAULT_ENCODING): cv.string,
}
MQTT_BASE_SCHEMA = vol.Schema(SCHEMA_BASE)
# Sensor type platforms subscribe to MQTT events
MQTT_RO_SCHEMA = MQTT_BASE_SCHEMA.extend(
{
vol.Required(CONF_STATE_TOPIC): valid_subscribe_topic,
vol.Optional(CONF_VALUE_TEMPLATE): cv.template,
}
)
# Switch type platforms publish to MQTT and may subscribe
MQTT_RW_SCHEMA = MQTT_BASE_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,
}
)

View File

@ -17,7 +17,7 @@ from homeassistant.const import (
)
from homeassistant.data_entry_flow import FlowResult
from . import MqttClientSetup
from .client import MqttClientSetup
from .const import (
ATTR_PAYLOAD,
ATTR_QOS,

View File

@ -1,5 +1,5 @@
"""Constants used by multiple MQTT modules."""
from homeassistant.const import CONF_PAYLOAD
from homeassistant.const import CONF_PAYLOAD, Platform
ATTR_DISCOVERY_HASH = "discovery_hash"
ATTR_DISCOVERY_PAYLOAD = "discovery_payload"
@ -14,7 +14,9 @@ CONF_BROKER = "broker"
CONF_BIRTH_MESSAGE = "birth_message"
CONF_COMMAND_TEMPLATE = "command_template"
CONF_COMMAND_TOPIC = "command_topic"
CONF_DISCOVERY_PREFIX = "discovery_prefix"
CONF_ENCODING = "encoding"
CONF_KEEPALIVE = "keepalive"
CONF_QOS = ATTR_QOS
CONF_RETAIN = ATTR_RETAIN
CONF_STATE_TOPIC = "state_topic"
@ -30,6 +32,7 @@ CONF_TLS_VERSION = "tls_version"
CONFIG_ENTRY_IS_SETUP = "mqtt_config_entry_is_setup"
DATA_CONFIG_ENTRY_LOCK = "mqtt_config_entry_lock"
DATA_MQTT = "mqtt"
DATA_MQTT_CONFIG = "mqtt_config"
DATA_MQTT_RELOAD_NEEDED = "mqtt_reload_needed"
@ -66,3 +69,24 @@ PAYLOAD_NONE = "None"
PROTOCOL_31 = "3.1"
PROTOCOL_311 = "3.1.1"
PLATFORMS = [
Platform.ALARM_CONTROL_PANEL,
Platform.BINARY_SENSOR,
Platform.BUTTON,
Platform.CAMERA,
Platform.CLIMATE,
Platform.DEVICE_TRACKER,
Platform.COVER,
Platform.FAN,
Platform.HUMIDIFIER,
Platform.LIGHT,
Platform.LOCK,
Platform.NUMBER,
Platform.SELECT,
Platform.SCENE,
Platform.SENSOR,
Platform.SIREN,
Platform.SWITCH,
Platform.VACUUM,
]

View File

@ -1,7 +1,6 @@
"""Support for MQTT cover devices."""
from __future__ import annotations
import asyncio
import functools
from json import JSONDecodeError, loads as json_loads
import logging
@ -33,8 +32,8 @@ import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
from . import MqttCommandTemplate, MqttValueTemplate, subscription
from .. import mqtt
from . import subscription
from .config import MQTT_BASE_SCHEMA
from .const import (
CONF_COMMAND_TOPIC,
CONF_ENCODING,
@ -46,11 +45,13 @@ from .debug_info import log_messages
from .mixins import (
MQTT_ENTITY_COMMON_SCHEMA,
MqttEntity,
async_get_platform_config_from_yaml,
async_setup_entry_helper,
async_setup_platform_discovery,
async_setup_platform_helper,
warn_for_legacy_schema,
)
from .models import MqttCommandTemplate, MqttValueTemplate
from .util import valid_publish_topic, valid_subscribe_topic
_LOGGER = logging.getLogger(__name__)
@ -152,11 +153,11 @@ def validate_options(value):
return value
_PLATFORM_SCHEMA_BASE = mqtt.MQTT_BASE_SCHEMA.extend(
_PLATFORM_SCHEMA_BASE = MQTT_BASE_SCHEMA.extend(
{
vol.Optional(CONF_COMMAND_TOPIC): mqtt.valid_publish_topic,
vol.Optional(CONF_COMMAND_TOPIC): valid_publish_topic,
vol.Optional(CONF_DEVICE_CLASS): DEVICE_CLASSES_SCHEMA,
vol.Optional(CONF_GET_POSITION_TOPIC): mqtt.valid_subscribe_topic,
vol.Optional(CONF_GET_POSITION_TOPIC): valid_subscribe_topic,
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
vol.Optional(CONF_OPTIMISTIC, default=DEFAULT_OPTIMISTIC): cv.boolean,
vol.Optional(CONF_PAYLOAD_CLOSE, default=DEFAULT_PAYLOAD_CLOSE): vol.Any(
@ -172,24 +173,24 @@ _PLATFORM_SCHEMA_BASE = mqtt.MQTT_BASE_SCHEMA.extend(
vol.Optional(CONF_POSITION_OPEN, default=DEFAULT_POSITION_OPEN): int,
vol.Optional(CONF_RETAIN, default=DEFAULT_RETAIN): cv.boolean,
vol.Optional(CONF_SET_POSITION_TEMPLATE): cv.template,
vol.Optional(CONF_SET_POSITION_TOPIC): mqtt.valid_publish_topic,
vol.Optional(CONF_SET_POSITION_TOPIC): valid_publish_topic,
vol.Optional(CONF_STATE_CLOSED, default=STATE_CLOSED): cv.string,
vol.Optional(CONF_STATE_CLOSING, default=STATE_CLOSING): cv.string,
vol.Optional(CONF_STATE_OPEN, default=STATE_OPEN): cv.string,
vol.Optional(CONF_STATE_OPENING, default=STATE_OPENING): cv.string,
vol.Optional(CONF_STATE_STOPPED, default=DEFAULT_STATE_STOPPED): cv.string,
vol.Optional(CONF_STATE_TOPIC): mqtt.valid_subscribe_topic,
vol.Optional(CONF_STATE_TOPIC): valid_subscribe_topic,
vol.Optional(
CONF_TILT_CLOSED_POSITION, default=DEFAULT_TILT_CLOSED_POSITION
): int,
vol.Optional(CONF_TILT_COMMAND_TOPIC): mqtt.valid_publish_topic,
vol.Optional(CONF_TILT_COMMAND_TOPIC): valid_publish_topic,
vol.Optional(CONF_TILT_MAX, default=DEFAULT_TILT_MAX): int,
vol.Optional(CONF_TILT_MIN, default=DEFAULT_TILT_MIN): int,
vol.Optional(CONF_TILT_OPEN_POSITION, default=DEFAULT_TILT_OPEN_POSITION): int,
vol.Optional(
CONF_TILT_STATE_OPTIMISTIC, default=DEFAULT_TILT_OPTIMISTIC
): cv.boolean,
vol.Optional(CONF_TILT_STATUS_TOPIC): mqtt.valid_subscribe_topic,
vol.Optional(CONF_TILT_STATUS_TOPIC): valid_subscribe_topic,
vol.Optional(CONF_TILT_STATUS_TEMPLATE): cv.template,
vol.Optional(CONF_VALUE_TEMPLATE): cv.template,
vol.Optional(CONF_GET_POSITION_TEMPLATE): cv.template,
@ -225,7 +226,11 @@ async def async_setup_platform(
"""Set up MQTT covers configured under the fan platform key (deprecated)."""
# Deprecated in HA Core 2022.6
await async_setup_platform_helper(
hass, cover.DOMAIN, config, async_add_entities, _async_setup_entity
hass,
cover.DOMAIN,
discovery_info or config,
async_add_entities,
_async_setup_entity,
)
@ -236,13 +241,8 @@ async def async_setup_entry(
) -> None:
"""Set up MQTT cover 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, cover.DOMAIN, PLATFORM_SCHEMA_MODERN
)
)
config_entry.async_on_unload(
await async_setup_platform_discovery(hass, cover.DOMAIN, PLATFORM_SCHEMA_MODERN)
)
# setup for discovery
setup = functools.partial(

View File

@ -3,8 +3,10 @@ import functools
import voluptuous as vol
import homeassistant.helpers.config_validation as cv
from . import device_trigger
from .. import mqtt
from .config import MQTT_BASE_SCHEMA
from .mixins import async_setup_entry_helper
AUTOMATION_TYPE_TRIGGER = "trigger"
@ -12,10 +14,10 @@ AUTOMATION_TYPES = [AUTOMATION_TYPE_TRIGGER]
AUTOMATION_TYPES_SCHEMA = vol.In(AUTOMATION_TYPES)
CONF_AUTOMATION_TYPE = "automation_type"
PLATFORM_SCHEMA = mqtt.MQTT_BASE_PLATFORM_SCHEMA.extend(
PLATFORM_SCHEMA = cv.PLATFORM_SCHEMA.extend(
{vol.Required(CONF_AUTOMATION_TYPE): AUTOMATION_TYPES_SCHEMA},
extra=vol.ALLOW_EXTRA,
)
).extend(MQTT_BASE_SCHEMA.schema)
async def async_setup_entry(hass, config_entry):

View File

@ -19,8 +19,8 @@ from homeassistant.const import (
from homeassistant.core import callback
import homeassistant.helpers.config_validation as cv
from .. import MqttValueTemplate, subscription
from ... import mqtt
from .. import subscription
from ..config import MQTT_RO_SCHEMA
from ..const import CONF_QOS, CONF_STATE_TOPIC
from ..debug_info import log_messages
from ..mixins import (
@ -29,12 +29,13 @@ from ..mixins import (
async_get_platform_config_from_yaml,
async_setup_entry_helper,
)
from ..models import MqttValueTemplate
CONF_PAYLOAD_HOME = "payload_home"
CONF_PAYLOAD_NOT_HOME = "payload_not_home"
CONF_SOURCE_TYPE = "source_type"
PLATFORM_SCHEMA_MODERN = mqtt.MQTT_RO_SCHEMA.extend(
PLATFORM_SCHEMA_MODERN = MQTT_RO_SCHEMA.extend(
{
vol.Optional(CONF_NAME): cv.string,
vol.Optional(CONF_PAYLOAD_HOME, default=STATE_HOME): cv.string,

View File

@ -7,16 +7,18 @@ from homeassistant.const import CONF_DEVICES, STATE_HOME, STATE_NOT_HOME
from homeassistant.core import callback
import homeassistant.helpers.config_validation as cv
from ... import mqtt
from ..client import async_subscribe
from ..config import SCHEMA_BASE
from ..const import CONF_QOS
from ..util import valid_subscribe_topic
CONF_PAYLOAD_HOME = "payload_home"
CONF_PAYLOAD_NOT_HOME = "payload_not_home"
CONF_SOURCE_TYPE = "source_type"
PLATFORM_SCHEMA_YAML = PLATFORM_SCHEMA.extend(mqtt.SCHEMA_BASE).extend(
PLATFORM_SCHEMA_YAML = PLATFORM_SCHEMA.extend(SCHEMA_BASE).extend(
{
vol.Required(CONF_DEVICES): {cv.string: mqtt.valid_subscribe_topic},
vol.Required(CONF_DEVICES): {cv.string: valid_subscribe_topic},
vol.Optional(CONF_PAYLOAD_HOME, default=STATE_HOME): cv.string,
vol.Optional(CONF_PAYLOAD_NOT_HOME, default=STATE_NOT_HOME): cv.string,
vol.Optional(CONF_SOURCE_TYPE): vol.In(SOURCE_TYPES),
@ -50,6 +52,6 @@ async def async_setup_scanner_from_yaml(hass, config, async_see, discovery_info=
hass.async_create_task(async_see(**see_args))
await mqtt.async_subscribe(hass, topic, async_message_received, qos)
await async_subscribe(hass, topic, async_message_received, qos)
return True

View File

@ -29,8 +29,15 @@ from homeassistant.helpers.dispatcher import async_dispatcher_send
from homeassistant.helpers.typing import ConfigType
from . import debug_info, trigger as mqtt_trigger
from .. import mqtt
from .const import ATTR_DISCOVERY_HASH, CONF_PAYLOAD, CONF_QOS, CONF_TOPIC, DOMAIN
from .config import MQTT_BASE_SCHEMA
from .const import (
ATTR_DISCOVERY_HASH,
CONF_ENCODING,
CONF_PAYLOAD,
CONF_QOS,
CONF_TOPIC,
DOMAIN,
)
from .discovery import MQTT_DISCOVERY_DONE
from .mixins import (
MQTT_ENTITY_DEVICE_INFO_SCHEMA,
@ -64,7 +71,7 @@ TRIGGER_SCHEMA = DEVICE_TRIGGER_BASE_SCHEMA.extend(
}
)
TRIGGER_DISCOVERY_SCHEMA = mqtt.MQTT_BASE_PLATFORM_SCHEMA.extend(
TRIGGER_DISCOVERY_SCHEMA = MQTT_BASE_SCHEMA.extend(
{
vol.Required(CONF_AUTOMATION_TYPE): str,
vol.Required(CONF_DEVICE): MQTT_ENTITY_DEVICE_INFO_SCHEMA,
@ -94,10 +101,10 @@ class TriggerInstance:
async def async_attach_trigger(self) -> None:
"""Attach MQTT trigger."""
mqtt_config = {
mqtt_trigger.CONF_PLATFORM: mqtt.DOMAIN,
mqtt_trigger.CONF_TOPIC: self.trigger.topic,
mqtt_trigger.CONF_ENCODING: DEFAULT_ENCODING,
mqtt_trigger.CONF_QOS: self.trigger.qos,
CONF_PLATFORM: DOMAIN,
CONF_TOPIC: self.trigger.topic,
CONF_ENCODING: DEFAULT_ENCODING,
CONF_QOS: self.trigger.qos,
}
if self.trigger.payload:
mqtt_config[CONF_PAYLOAD] = self.trigger.payload

View File

@ -1,7 +1,6 @@
"""Support for MQTT fans."""
from __future__ import annotations
import asyncio
import functools
import logging
import math
@ -34,8 +33,8 @@ from homeassistant.util.percentage import (
ranged_value_to_percentage,
)
from . import MqttCommandTemplate, MqttValueTemplate, subscription
from .. import mqtt
from . import subscription
from .config import MQTT_RW_SCHEMA
from .const import (
CONF_COMMAND_TEMPLATE,
CONF_COMMAND_TOPIC,
@ -50,11 +49,13 @@ from .debug_info import log_messages
from .mixins import (
MQTT_ENTITY_COMMON_SCHEMA,
MqttEntity,
async_get_platform_config_from_yaml,
async_setup_entry_helper,
async_setup_platform_discovery,
async_setup_platform_helper,
warn_for_legacy_schema,
)
from .models import MqttCommandTemplate, MqttValueTemplate
from .util import valid_publish_topic, valid_subscribe_topic
CONF_PERCENTAGE_STATE_TOPIC = "percentage_state_topic"
CONF_PERCENTAGE_COMMAND_TOPIC = "percentage_command_topic"
@ -125,28 +126,28 @@ def valid_preset_mode_configuration(config):
return config
_PLATFORM_SCHEMA_BASE = mqtt.MQTT_RW_SCHEMA.extend(
_PLATFORM_SCHEMA_BASE = MQTT_RW_SCHEMA.extend(
{
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
vol.Optional(CONF_OPTIMISTIC, default=DEFAULT_OPTIMISTIC): cv.boolean,
vol.Optional(CONF_COMMAND_TEMPLATE): cv.template,
vol.Optional(CONF_OSCILLATION_COMMAND_TOPIC): mqtt.valid_publish_topic,
vol.Optional(CONF_OSCILLATION_COMMAND_TOPIC): valid_publish_topic,
vol.Optional(CONF_OSCILLATION_COMMAND_TEMPLATE): cv.template,
vol.Optional(CONF_OSCILLATION_STATE_TOPIC): mqtt.valid_subscribe_topic,
vol.Optional(CONF_OSCILLATION_STATE_TOPIC): valid_subscribe_topic,
vol.Optional(CONF_OSCILLATION_VALUE_TEMPLATE): cv.template,
vol.Optional(CONF_PERCENTAGE_COMMAND_TOPIC): mqtt.valid_publish_topic,
vol.Optional(CONF_PERCENTAGE_COMMAND_TOPIC): valid_publish_topic,
vol.Optional(CONF_PERCENTAGE_COMMAND_TEMPLATE): cv.template,
vol.Optional(CONF_PERCENTAGE_STATE_TOPIC): mqtt.valid_subscribe_topic,
vol.Optional(CONF_PERCENTAGE_STATE_TOPIC): valid_subscribe_topic,
vol.Optional(CONF_PERCENTAGE_VALUE_TEMPLATE): cv.template,
# CONF_PRESET_MODE_COMMAND_TOPIC and CONF_PRESET_MODES_LIST must be used together
vol.Inclusive(
CONF_PRESET_MODE_COMMAND_TOPIC, "preset_modes"
): mqtt.valid_publish_topic,
): valid_publish_topic,
vol.Inclusive(
CONF_PRESET_MODES_LIST, "preset_modes", default=[]
): cv.ensure_list,
vol.Optional(CONF_PRESET_MODE_COMMAND_TEMPLATE): cv.template,
vol.Optional(CONF_PRESET_MODE_STATE_TOPIC): mqtt.valid_subscribe_topic,
vol.Optional(CONF_PRESET_MODE_STATE_TOPIC): valid_subscribe_topic,
vol.Optional(CONF_PRESET_MODE_VALUE_TEMPLATE): cv.template,
vol.Optional(
CONF_SPEED_RANGE_MIN, default=DEFAULT_SPEED_RANGE_MIN
@ -168,8 +169,8 @@ _PLATFORM_SCHEMA_BASE = mqtt.MQTT_RW_SCHEMA.extend(
vol.Optional(
CONF_PAYLOAD_OSCILLATION_ON, default=OSCILLATE_ON_PAYLOAD
): cv.string,
vol.Optional(CONF_SPEED_COMMAND_TOPIC): mqtt.valid_publish_topic,
vol.Optional(CONF_SPEED_STATE_TOPIC): mqtt.valid_subscribe_topic,
vol.Optional(CONF_SPEED_COMMAND_TOPIC): valid_publish_topic,
vol.Optional(CONF_SPEED_STATE_TOPIC): valid_subscribe_topic,
vol.Optional(CONF_SPEED_VALUE_TEMPLATE): cv.template,
vol.Optional(CONF_STATE_VALUE_TEMPLATE): cv.template,
}
@ -215,7 +216,11 @@ async def async_setup_platform(
"""Set up MQTT fans configured under the fan platform key (deprecated)."""
# Deprecated in HA Core 2022.6
await async_setup_platform_helper(
hass, fan.DOMAIN, config, async_add_entities, _async_setup_entity
hass,
fan.DOMAIN,
discovery_info or config,
async_add_entities,
_async_setup_entity,
)
@ -226,13 +231,8 @@ async def async_setup_entry(
) -> None:
"""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
)
)
config_entry.async_on_unload(
await async_setup_platform_discovery(hass, fan.DOMAIN, PLATFORM_SCHEMA_MODERN)
)
# setup for discovery
setup = functools.partial(

View File

@ -1,7 +1,6 @@
"""Support for MQTT humidifiers."""
from __future__ import annotations
import asyncio
import functools
import logging
@ -30,8 +29,8 @@ import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
from . import MqttCommandTemplate, MqttValueTemplate, subscription
from .. import mqtt
from . import subscription
from .config import MQTT_RW_SCHEMA
from .const import (
CONF_COMMAND_TEMPLATE,
CONF_COMMAND_TOPIC,
@ -46,11 +45,13 @@ from .debug_info import log_messages
from .mixins import (
MQTT_ENTITY_COMMON_SCHEMA,
MqttEntity,
async_get_platform_config_from_yaml,
async_setup_entry_helper,
async_setup_platform_discovery,
async_setup_platform_helper,
warn_for_legacy_schema,
)
from .models import MqttCommandTemplate, MqttValueTemplate
from .util import valid_publish_topic, valid_subscribe_topic
CONF_AVAILABLE_MODES_LIST = "modes"
CONF_DEVICE_CLASS = "device_class"
@ -103,15 +104,13 @@ def valid_humidity_range_configuration(config):
return config
_PLATFORM_SCHEMA_BASE = mqtt.MQTT_RW_SCHEMA.extend(
_PLATFORM_SCHEMA_BASE = MQTT_RW_SCHEMA.extend(
{
# CONF_AVAIALABLE_MODES_LIST and CONF_MODE_COMMAND_TOPIC must be used together
vol.Inclusive(
CONF_AVAILABLE_MODES_LIST, "available_modes", default=[]
): cv.ensure_list,
vol.Inclusive(
CONF_MODE_COMMAND_TOPIC, "available_modes"
): mqtt.valid_publish_topic,
vol.Inclusive(CONF_MODE_COMMAND_TOPIC, "available_modes"): valid_publish_topic,
vol.Optional(CONF_COMMAND_TEMPLATE): cv.template,
vol.Optional(
CONF_DEVICE_CLASS, default=HumidifierDeviceClass.HUMIDIFIER
@ -119,14 +118,14 @@ _PLATFORM_SCHEMA_BASE = mqtt.MQTT_RW_SCHEMA.extend(
[HumidifierDeviceClass.HUMIDIFIER, HumidifierDeviceClass.DEHUMIDIFIER]
),
vol.Optional(CONF_MODE_COMMAND_TEMPLATE): cv.template,
vol.Optional(CONF_MODE_STATE_TOPIC): mqtt.valid_subscribe_topic,
vol.Optional(CONF_MODE_STATE_TOPIC): valid_subscribe_topic,
vol.Optional(CONF_MODE_STATE_TEMPLATE): cv.template,
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
vol.Optional(CONF_OPTIMISTIC, default=DEFAULT_OPTIMISTIC): cv.boolean,
vol.Optional(CONF_PAYLOAD_OFF, default=DEFAULT_PAYLOAD_OFF): cv.string,
vol.Optional(CONF_PAYLOAD_ON, default=DEFAULT_PAYLOAD_ON): cv.string,
vol.Optional(CONF_STATE_VALUE_TEMPLATE): cv.template,
vol.Required(CONF_TARGET_HUMIDITY_COMMAND_TOPIC): mqtt.valid_publish_topic,
vol.Required(CONF_TARGET_HUMIDITY_COMMAND_TOPIC): valid_publish_topic,
vol.Optional(CONF_TARGET_HUMIDITY_COMMAND_TEMPLATE): cv.template,
vol.Optional(
CONF_TARGET_HUMIDITY_MAX, default=DEFAULT_MAX_HUMIDITY
@ -135,7 +134,7 @@ _PLATFORM_SCHEMA_BASE = mqtt.MQTT_RW_SCHEMA.extend(
CONF_TARGET_HUMIDITY_MIN, default=DEFAULT_MIN_HUMIDITY
): cv.positive_int,
vol.Optional(CONF_TARGET_HUMIDITY_STATE_TEMPLATE): cv.template,
vol.Optional(CONF_TARGET_HUMIDITY_STATE_TOPIC): mqtt.valid_subscribe_topic,
vol.Optional(CONF_TARGET_HUMIDITY_STATE_TOPIC): valid_subscribe_topic,
vol.Optional(
CONF_PAYLOAD_RESET_HUMIDITY, default=DEFAULT_PAYLOAD_RESET
): cv.string,
@ -173,7 +172,11 @@ async def async_setup_platform(
"""Set up MQTT humidifier configured under the fan platform key (deprecated)."""
# Deprecated in HA Core 2022.6
await async_setup_platform_helper(
hass, humidifier.DOMAIN, config, async_add_entities, _async_setup_entity
hass,
humidifier.DOMAIN,
discovery_info or config,
async_add_entities,
_async_setup_entity,
)
@ -184,14 +187,12 @@ async def async_setup_entry(
) -> None:
"""Set up MQTT humidifier 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, humidifier.DOMAIN, PLATFORM_SCHEMA_MODERN
)
config_entry.async_on_unload(
await async_setup_platform_discovery(
hass, humidifier.DOMAIN, PLATFORM_SCHEMA_MODERN
)
) # setup for discovery
)
# setup for discovery
setup = functools.partial(
_async_setup_entity, hass, async_add_entities, config_entry=config_entry
)

View File

@ -1,7 +1,6 @@
"""Support for MQTT lights."""
from __future__ import annotations
import asyncio
import functools
import voluptuous as vol
@ -14,8 +13,8 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
from ..mixins import (
async_get_platform_config_from_yaml,
async_setup_entry_helper,
async_setup_platform_discovery,
async_setup_platform_helper,
warn_for_legacy_schema,
)
@ -97,7 +96,11 @@ async def async_setup_platform(
"""Set up MQTT light through configuration.yaml (deprecated)."""
# Deprecated in HA Core 2022.6
await async_setup_platform_helper(
hass, light.DOMAIN, config, async_add_entities, _async_setup_entity
hass,
light.DOMAIN,
discovery_info or config,
async_add_entities,
_async_setup_entity,
)
@ -108,13 +111,8 @@ async def async_setup_entry(
) -> 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
)
)
config_entry.async_on_unload(
await async_setup_platform_discovery(hass, light.DOMAIN, PLATFORM_SCHEMA_MODERN)
)
# setup for discovery
setup = functools.partial(

View File

@ -42,8 +42,8 @@ import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.restore_state import RestoreEntity
import homeassistant.util.color as color_util
from .. import MqttCommandTemplate, MqttValueTemplate, subscription
from ... import mqtt
from .. import subscription
from ..config import MQTT_RW_SCHEMA
from ..const import (
CONF_COMMAND_TOPIC,
CONF_ENCODING,
@ -55,6 +55,8 @@ from ..const import (
)
from ..debug_info import log_messages
from ..mixins import MQTT_ENTITY_COMMON_SCHEMA, MqttEntity
from ..models import MqttCommandTemplate, MqttValueTemplate
from ..util import valid_publish_topic, valid_subscribe_topic
from .schema import MQTT_LIGHT_SCHEMA_SCHEMA
_LOGGER = logging.getLogger(__name__)
@ -156,28 +158,28 @@ VALUE_TEMPLATE_KEYS = [
]
_PLATFORM_SCHEMA_BASE = (
mqtt.MQTT_RW_SCHEMA.extend(
MQTT_RW_SCHEMA.extend(
{
vol.Optional(CONF_BRIGHTNESS_COMMAND_TEMPLATE): cv.template,
vol.Optional(CONF_BRIGHTNESS_COMMAND_TOPIC): mqtt.valid_publish_topic,
vol.Optional(CONF_BRIGHTNESS_COMMAND_TOPIC): valid_publish_topic,
vol.Optional(
CONF_BRIGHTNESS_SCALE, default=DEFAULT_BRIGHTNESS_SCALE
): vol.All(vol.Coerce(int), vol.Range(min=1)),
vol.Optional(CONF_BRIGHTNESS_STATE_TOPIC): mqtt.valid_subscribe_topic,
vol.Optional(CONF_BRIGHTNESS_STATE_TOPIC): valid_subscribe_topic,
vol.Optional(CONF_BRIGHTNESS_VALUE_TEMPLATE): cv.template,
vol.Optional(CONF_COLOR_MODE_STATE_TOPIC): mqtt.valid_subscribe_topic,
vol.Optional(CONF_COLOR_MODE_STATE_TOPIC): valid_subscribe_topic,
vol.Optional(CONF_COLOR_MODE_VALUE_TEMPLATE): cv.template,
vol.Optional(CONF_COLOR_TEMP_COMMAND_TEMPLATE): cv.template,
vol.Optional(CONF_COLOR_TEMP_COMMAND_TOPIC): mqtt.valid_publish_topic,
vol.Optional(CONF_COLOR_TEMP_STATE_TOPIC): mqtt.valid_subscribe_topic,
vol.Optional(CONF_COLOR_TEMP_COMMAND_TOPIC): valid_publish_topic,
vol.Optional(CONF_COLOR_TEMP_STATE_TOPIC): valid_subscribe_topic,
vol.Optional(CONF_COLOR_TEMP_VALUE_TEMPLATE): cv.template,
vol.Optional(CONF_EFFECT_COMMAND_TEMPLATE): cv.template,
vol.Optional(CONF_EFFECT_COMMAND_TOPIC): mqtt.valid_publish_topic,
vol.Optional(CONF_EFFECT_COMMAND_TOPIC): valid_publish_topic,
vol.Optional(CONF_EFFECT_LIST): vol.All(cv.ensure_list, [cv.string]),
vol.Optional(CONF_EFFECT_STATE_TOPIC): mqtt.valid_subscribe_topic,
vol.Optional(CONF_EFFECT_STATE_TOPIC): valid_subscribe_topic,
vol.Optional(CONF_EFFECT_VALUE_TEMPLATE): cv.template,
vol.Optional(CONF_HS_COMMAND_TOPIC): mqtt.valid_publish_topic,
vol.Optional(CONF_HS_STATE_TOPIC): mqtt.valid_subscribe_topic,
vol.Optional(CONF_HS_COMMAND_TOPIC): valid_publish_topic,
vol.Optional(CONF_HS_STATE_TOPIC): valid_subscribe_topic,
vol.Optional(CONF_HS_VALUE_TEMPLATE): cv.template,
vol.Optional(CONF_MAX_MIREDS): cv.positive_int,
vol.Optional(CONF_MIN_MIREDS): cv.positive_int,
@ -189,30 +191,30 @@ _PLATFORM_SCHEMA_BASE = (
vol.Optional(CONF_PAYLOAD_OFF, default=DEFAULT_PAYLOAD_OFF): cv.string,
vol.Optional(CONF_PAYLOAD_ON, default=DEFAULT_PAYLOAD_ON): cv.string,
vol.Optional(CONF_RGB_COMMAND_TEMPLATE): cv.template,
vol.Optional(CONF_RGB_COMMAND_TOPIC): mqtt.valid_publish_topic,
vol.Optional(CONF_RGB_STATE_TOPIC): mqtt.valid_subscribe_topic,
vol.Optional(CONF_RGB_COMMAND_TOPIC): valid_publish_topic,
vol.Optional(CONF_RGB_STATE_TOPIC): valid_subscribe_topic,
vol.Optional(CONF_RGB_VALUE_TEMPLATE): cv.template,
vol.Optional(CONF_RGBW_COMMAND_TEMPLATE): cv.template,
vol.Optional(CONF_RGBW_COMMAND_TOPIC): mqtt.valid_publish_topic,
vol.Optional(CONF_RGBW_STATE_TOPIC): mqtt.valid_subscribe_topic,
vol.Optional(CONF_RGBW_COMMAND_TOPIC): valid_publish_topic,
vol.Optional(CONF_RGBW_STATE_TOPIC): valid_subscribe_topic,
vol.Optional(CONF_RGBW_VALUE_TEMPLATE): cv.template,
vol.Optional(CONF_RGBWW_COMMAND_TEMPLATE): cv.template,
vol.Optional(CONF_RGBWW_COMMAND_TOPIC): mqtt.valid_publish_topic,
vol.Optional(CONF_RGBWW_STATE_TOPIC): mqtt.valid_subscribe_topic,
vol.Optional(CONF_RGBWW_COMMAND_TOPIC): valid_publish_topic,
vol.Optional(CONF_RGBWW_STATE_TOPIC): valid_subscribe_topic,
vol.Optional(CONF_RGBWW_VALUE_TEMPLATE): cv.template,
vol.Optional(CONF_STATE_VALUE_TEMPLATE): cv.template,
vol.Optional(CONF_WHITE_COMMAND_TOPIC): mqtt.valid_publish_topic,
vol.Optional(CONF_WHITE_COMMAND_TOPIC): valid_publish_topic,
vol.Optional(CONF_WHITE_SCALE, default=DEFAULT_WHITE_SCALE): vol.All(
vol.Coerce(int), vol.Range(min=1)
),
vol.Optional(CONF_WHITE_VALUE_COMMAND_TOPIC): mqtt.valid_publish_topic,
vol.Optional(CONF_WHITE_VALUE_COMMAND_TOPIC): valid_publish_topic,
vol.Optional(
CONF_WHITE_VALUE_SCALE, default=DEFAULT_WHITE_VALUE_SCALE
): vol.All(vol.Coerce(int), vol.Range(min=1)),
vol.Optional(CONF_WHITE_VALUE_STATE_TOPIC): mqtt.valid_subscribe_topic,
vol.Optional(CONF_WHITE_VALUE_STATE_TOPIC): valid_subscribe_topic,
vol.Optional(CONF_WHITE_VALUE_TEMPLATE): cv.template,
vol.Optional(CONF_XY_COMMAND_TOPIC): mqtt.valid_publish_topic,
vol.Optional(CONF_XY_STATE_TOPIC): mqtt.valid_subscribe_topic,
vol.Optional(CONF_XY_COMMAND_TOPIC): valid_publish_topic,
vol.Optional(CONF_XY_STATE_TOPIC): valid_subscribe_topic,
vol.Optional(CONF_XY_VALUE_TEMPLATE): cv.template,
},
)

View File

@ -51,7 +51,7 @@ from homeassistant.helpers.typing import ConfigType
import homeassistant.util.color as color_util
from .. import subscription
from ... import mqtt
from ..config import DEFAULT_QOS, DEFAULT_RETAIN, MQTT_RW_SCHEMA
from ..const import (
CONF_COMMAND_TOPIC,
CONF_ENCODING,
@ -61,6 +61,7 @@ from ..const import (
)
from ..debug_info import log_messages
from ..mixins import MQTT_ENTITY_COMMON_SCHEMA, MqttEntity
from ..util import valid_subscribe_topic
from .schema import MQTT_LIGHT_SCHEMA_SCHEMA
from .schema_basic import CONF_BRIGHTNESS_SCALE, MQTT_LIGHT_ATTRIBUTES_BLOCKED
@ -103,7 +104,7 @@ def valid_color_configuration(config):
_PLATFORM_SCHEMA_BASE = (
mqtt.MQTT_RW_SCHEMA.extend(
MQTT_RW_SCHEMA.extend(
{
vol.Optional(CONF_BRIGHTNESS, default=DEFAULT_BRIGHTNESS): cv.boolean,
vol.Optional(
@ -126,12 +127,12 @@ _PLATFORM_SCHEMA_BASE = (
vol.Optional(CONF_MIN_MIREDS): cv.positive_int,
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
vol.Optional(CONF_OPTIMISTIC, default=DEFAULT_OPTIMISTIC): cv.boolean,
vol.Optional(CONF_QOS, default=mqtt.DEFAULT_QOS): vol.All(
vol.Optional(CONF_QOS, default=DEFAULT_QOS): vol.All(
vol.Coerce(int), vol.In([0, 1, 2])
),
vol.Optional(CONF_RETAIN, default=mqtt.DEFAULT_RETAIN): cv.boolean,
vol.Optional(CONF_RETAIN, default=DEFAULT_RETAIN): cv.boolean,
vol.Optional(CONF_RGB, default=DEFAULT_RGB): cv.boolean,
vol.Optional(CONF_STATE_TOPIC): mqtt.valid_subscribe_topic,
vol.Optional(CONF_STATE_TOPIC): valid_subscribe_topic,
vol.Inclusive(CONF_SUPPORTED_COLOR_MODES, "color_mode"): vol.All(
cv.ensure_list,
[vol.In(VALID_COLOR_MODES)],

View File

@ -31,8 +31,8 @@ import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.restore_state import RestoreEntity
import homeassistant.util.color as color_util
from .. import MqttValueTemplate, subscription
from ... import mqtt
from .. import subscription
from ..config import MQTT_RW_SCHEMA
from ..const import (
CONF_COMMAND_TOPIC,
CONF_ENCODING,
@ -43,6 +43,7 @@ from ..const import (
)
from ..debug_info import log_messages
from ..mixins import MQTT_ENTITY_COMMON_SCHEMA, MqttEntity
from ..models import MqttValueTemplate
from .schema import MQTT_LIGHT_SCHEMA_SCHEMA
from .schema_basic import MQTT_LIGHT_ATTRIBUTES_BLOCKED
@ -67,7 +68,7 @@ CONF_RED_TEMPLATE = "red_template"
CONF_WHITE_VALUE_TEMPLATE = "white_value_template"
_PLATFORM_SCHEMA_BASE = (
mqtt.MQTT_RW_SCHEMA.extend(
MQTT_RW_SCHEMA.extend(
{
vol.Optional(CONF_BLUE_TEMPLATE): cv.template,
vol.Optional(CONF_BRIGHTNESS_TEMPLATE): cv.template,

View File

@ -1,7 +1,6 @@
"""Support for MQTT locks."""
from __future__ import annotations
import asyncio
import functools
import voluptuous as vol
@ -15,8 +14,8 @@ import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
from . import MqttValueTemplate, subscription
from .. import mqtt
from . import subscription
from .config import MQTT_RW_SCHEMA
from .const import (
CONF_COMMAND_TOPIC,
CONF_ENCODING,
@ -28,11 +27,12 @@ from .debug_info import log_messages
from .mixins import (
MQTT_ENTITY_COMMON_SCHEMA,
MqttEntity,
async_get_platform_config_from_yaml,
async_setup_entry_helper,
async_setup_platform_discovery,
async_setup_platform_helper,
warn_for_legacy_schema,
)
from .models import MqttValueTemplate
CONF_PAYLOAD_LOCK = "payload_lock"
CONF_PAYLOAD_UNLOCK = "payload_unlock"
@ -56,7 +56,7 @@ MQTT_LOCK_ATTRIBUTES_BLOCKED = frozenset(
}
)
PLATFORM_SCHEMA_MODERN = mqtt.MQTT_RW_SCHEMA.extend(
PLATFORM_SCHEMA_MODERN = MQTT_RW_SCHEMA.extend(
{
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
vol.Optional(CONF_OPTIMISTIC, default=DEFAULT_OPTIMISTIC): cv.boolean,
@ -87,7 +87,11 @@ async def async_setup_platform(
"""Set up MQTT locks configured under the lock platform key (deprecated)."""
# Deprecated in HA Core 2022.6
await async_setup_platform_helper(
hass, lock.DOMAIN, config, async_add_entities, _async_setup_entity
hass,
lock.DOMAIN,
discovery_info or config,
async_add_entities,
_async_setup_entity,
)
@ -98,13 +102,8 @@ async def async_setup_entry(
) -> None:
"""Set up MQTT lock 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, lock.DOMAIN, PLATFORM_SCHEMA_MODERN
)
)
config_entry.async_on_unload(
await async_setup_platform_discovery(hass, lock.DOMAIN, PLATFORM_SCHEMA_MODERN)
)
# setup for discovery
setup = functools.partial(

View File

@ -2,6 +2,7 @@
from __future__ import annotations
from abc import abstractmethod
import asyncio
from collections.abc import Callable
import json
import logging
@ -27,10 +28,11 @@ from homeassistant.const import (
CONF_UNIQUE_ID,
CONF_VALUE_TEMPLATE,
)
from homeassistant.core import Event, HomeAssistant, callback
from homeassistant.core import CALLBACK_TYPE, Event, HomeAssistant, callback
from homeassistant.helpers import (
config_validation as cv,
device_registry as dr,
discovery,
entity_registry as er,
)
from homeassistant.helpers.device_registry import EVENT_DEVICE_REGISTRY_UPDATED
@ -46,17 +48,14 @@ from homeassistant.helpers.entity import (
async_generate_entity_id,
)
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.reload import async_setup_reload_service
from homeassistant.helpers.reload import (
async_integration_yaml_config,
async_setup_reload_service,
)
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
from . import (
DATA_MQTT,
PLATFORMS,
MqttValueTemplate,
async_publish,
debug_info,
subscription,
)
from . import debug_info, subscription
from .client import async_publish
from .const import (
ATTR_DISCOVERY_HASH,
ATTR_DISCOVERY_PAYLOAD,
@ -65,6 +64,7 @@ from .const import (
CONF_ENCODING,
CONF_QOS,
CONF_TOPIC,
DATA_MQTT,
DATA_MQTT_CONFIG,
DATA_MQTT_RELOAD_NEEDED,
DEFAULT_ENCODING,
@ -73,6 +73,7 @@ from .const import (
DOMAIN,
MQTT_CONNECTED,
MQTT_DISCONNECTED,
PLATFORMS,
)
from .debug_info import log_message, log_messages
from .discovery import (
@ -82,7 +83,7 @@ from .discovery import (
clear_discovery_hash,
set_discovery_hash,
)
from .models import PublishPayloadType, ReceiveMessage
from .models import MqttValueTemplate, PublishPayloadType, ReceiveMessage
from .subscription import (
async_prepare_subscribe_topics,
async_subscribe_topics,
@ -264,8 +265,44 @@ class SetupEntity(Protocol):
"""Define setup_entities type."""
async def async_setup_platform_discovery(
hass: HomeAssistant, platform_domain: str, schema: vol.Schema
) -> CALLBACK_TYPE:
"""Set up platform discovery for manual config."""
async def _async_discover_entities(event: Event | None) -> None:
"""Discover entities for a platform."""
if event:
# The platform has been reloaded
config_yaml = await async_integration_yaml_config(hass, DOMAIN)
if not config_yaml:
return
config_yaml = config_yaml.get(DOMAIN, {})
else:
config_yaml = hass.data.get(DATA_MQTT_CONFIG, {})
if not config_yaml:
return
if platform_domain not in config_yaml:
return
await asyncio.gather(
*(
discovery.async_load_platform(hass, platform_domain, DOMAIN, config, {})
for config in await async_get_platform_config_from_yaml(
hass, platform_domain, schema, config_yaml
)
)
)
unsub = hass.bus.async_listen("event_mqtt_reloaded", _async_discover_entities)
await _async_discover_entities(None)
return unsub
async def async_get_platform_config_from_yaml(
hass: HomeAssistant, domain: str, schema: vol.Schema
hass: HomeAssistant,
platform_domain: str,
schema: vol.Schema,
config_yaml: ConfigType = None,
) -> list[ConfigType]:
"""Return a list of validated configurations for the domain."""
@ -279,12 +316,15 @@ async def async_get_platform_config_from_yaml(
try:
validated_config.append(schema(config_item))
except vol.MultipleInvalid as err:
async_log_exception(err, domain, config_item, hass)
async_log_exception(err, platform_domain, config_item, hass)
return validated_config
config_yaml: ConfigType = hass.data.get(DATA_MQTT_CONFIG, {})
if not (platform_configs := config_yaml.get(domain)):
if config_yaml is None:
config_yaml = hass.data.get(DATA_MQTT_CONFIG)
if not config_yaml:
return []
if not (platform_configs := config_yaml.get(platform_domain)):
return []
return async_validate_config(hass, platform_configs)
@ -314,7 +354,7 @@ async def async_setup_entry_helper(hass, domain, async_setup, schema):
async def async_setup_platform_helper(
hass: HomeAssistant,
platform_domain: str,
config: ConfigType,
config: ConfigType | DiscoveryInfoType,
async_add_entities: AddEntitiesCallback,
async_setup_entities: SetupEntity,
) -> None:

View File

@ -1,12 +1,21 @@
"""Models used by multiple MQTT modules."""
from __future__ import annotations
from ast import literal_eval
from collections.abc import Awaitable, Callable
import datetime as dt
from typing import Union
from typing import Any, Union
import attr
from homeassistant.const import ATTR_ENTITY_ID, ATTR_NAME
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers import template
from homeassistant.helpers.entity import Entity
from homeassistant.helpers.typing import TemplateVarsType
_SENTINEL = object()
PublishPayloadType = Union[str, bytes, int, float, None]
ReceivePayloadType = Union[str, bytes]
@ -35,3 +44,118 @@ class ReceiveMessage:
AsyncMessageCallbackType = Callable[[ReceiveMessage], Awaitable[None]]
MessageCallbackType = Callable[[ReceiveMessage], None]
class MqttCommandTemplate:
"""Class for rendering MQTT payload with command templates."""
def __init__(
self,
command_template: template.Template | None,
*,
hass: HomeAssistant | None = None,
entity: Entity | None = None,
) -> None:
"""Instantiate a command template."""
self._attr_command_template = command_template
if command_template is None:
return
self._entity = entity
command_template.hass = hass
if entity:
command_template.hass = entity.hass
@callback
def async_render(
self,
value: PublishPayloadType = None,
variables: TemplateVarsType = None,
) -> PublishPayloadType:
"""Render or convert the command template with given value or variables."""
def _convert_outgoing_payload(
payload: PublishPayloadType,
) -> PublishPayloadType:
"""Ensure correct raw MQTT payload is passed as bytes for publishing."""
if isinstance(payload, str):
try:
native_object = literal_eval(payload)
if isinstance(native_object, bytes):
return native_object
except (ValueError, TypeError, SyntaxError, MemoryError):
pass
return payload
if self._attr_command_template is None:
return value
values = {"value": value}
if self._entity:
values[ATTR_ENTITY_ID] = self._entity.entity_id
values[ATTR_NAME] = self._entity.name
if variables is not None:
values.update(variables)
return _convert_outgoing_payload(
self._attr_command_template.async_render(values, parse_result=False)
)
class MqttValueTemplate:
"""Class for rendering MQTT value template with possible json values."""
def __init__(
self,
value_template: template.Template | None,
*,
hass: HomeAssistant | None = None,
entity: Entity | None = None,
config_attributes: TemplateVarsType = None,
) -> None:
"""Instantiate a value template."""
self._value_template = value_template
self._config_attributes = config_attributes
if value_template is None:
return
value_template.hass = hass
self._entity = entity
if entity:
value_template.hass = entity.hass
@callback
def async_render_with_possible_json_value(
self,
payload: ReceivePayloadType,
default: ReceivePayloadType | object = _SENTINEL,
variables: TemplateVarsType = None,
) -> ReceivePayloadType:
"""Render with possible json value or pass-though a received MQTT value."""
if self._value_template is None:
return payload
values: dict[str, Any] = {}
if variables is not None:
values.update(variables)
if self._config_attributes is not None:
values.update(self._config_attributes)
if self._entity:
values[ATTR_ENTITY_ID] = self._entity.entity_id
values[ATTR_NAME] = self._entity.name
if default == _SENTINEL:
return self._value_template.async_render_with_possible_json_value(
payload, variables=values
)
return self._value_template.async_render_with_possible_json_value(
payload, default, variables=values
)

View File

@ -1,7 +1,6 @@
"""Configure number in a device through MQTT topic."""
from __future__ import annotations
import asyncio
import functools
import logging
@ -27,8 +26,8 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.restore_state import RestoreEntity
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
from . import MqttCommandTemplate, MqttValueTemplate, subscription
from .. import mqtt
from . import subscription
from .config import MQTT_RW_SCHEMA
from .const import (
CONF_COMMAND_TEMPLATE,
CONF_COMMAND_TOPIC,
@ -41,11 +40,12 @@ from .debug_info import log_messages
from .mixins import (
MQTT_ENTITY_COMMON_SCHEMA,
MqttEntity,
async_get_platform_config_from_yaml,
async_setup_entry_helper,
async_setup_platform_discovery,
async_setup_platform_helper,
warn_for_legacy_schema,
)
from .models import MqttCommandTemplate, MqttValueTemplate
_LOGGER = logging.getLogger(__name__)
@ -75,7 +75,7 @@ def validate_config(config):
return config
_PLATFORM_SCHEMA_BASE = mqtt.MQTT_RW_SCHEMA.extend(
_PLATFORM_SCHEMA_BASE = MQTT_RW_SCHEMA.extend(
{
vol.Optional(CONF_COMMAND_TEMPLATE): cv.template,
vol.Optional(CONF_MAX, default=DEFAULT_MAX_VALUE): vol.Coerce(float),
@ -118,7 +118,11 @@ async def async_setup_platform(
"""Set up MQTT number configured under the number platform key (deprecated)."""
# Deprecated in HA Core 2022.6
await async_setup_platform_helper(
hass, number.DOMAIN, config, async_add_entities, _async_setup_entity
hass,
number.DOMAIN,
discovery_info or config,
async_add_entities,
_async_setup_entity,
)
@ -129,12 +133,9 @@ async def async_setup_entry(
) -> None:
"""Set up MQTT number 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, number.DOMAIN, PLATFORM_SCHEMA_MODERN
)
config_entry.async_on_unload(
await async_setup_platform_discovery(
hass, number.DOMAIN, PLATFORM_SCHEMA_MODERN
)
)
# setup for discovery

View File

@ -1,7 +1,6 @@
"""Support for MQTT scenes."""
from __future__ import annotations
import asyncio
import functools
import voluptuous as vol
@ -15,25 +14,27 @@ import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
from .. import mqtt
from .client import async_publish
from .config import MQTT_BASE_SCHEMA
from .const import CONF_COMMAND_TOPIC, CONF_ENCODING, CONF_QOS, CONF_RETAIN
from .mixins import (
CONF_ENABLED_BY_DEFAULT,
CONF_OBJECT_ID,
MQTT_AVAILABILITY_SCHEMA,
MqttEntity,
async_get_platform_config_from_yaml,
async_setup_entry_helper,
async_setup_platform_discovery,
async_setup_platform_helper,
warn_for_legacy_schema,
)
from .util import valid_publish_topic
DEFAULT_NAME = "MQTT Scene"
DEFAULT_RETAIN = False
PLATFORM_SCHEMA_MODERN = mqtt.MQTT_BASE_SCHEMA.extend(
PLATFORM_SCHEMA_MODERN = MQTT_BASE_SCHEMA.extend(
{
vol.Required(CONF_COMMAND_TOPIC): mqtt.valid_publish_topic,
vol.Required(CONF_COMMAND_TOPIC): valid_publish_topic,
vol.Optional(CONF_ICON): cv.icon,
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
vol.Optional(CONF_PAYLOAD_ON): cv.string,
@ -63,7 +64,11 @@ async def async_setup_platform(
"""Set up MQTT scene configured under the scene platform key (deprecated)."""
# Deprecated in HA Core 2022.6
await async_setup_platform_helper(
hass, scene.DOMAIN, config, async_add_entities, _async_setup_entity
hass,
scene.DOMAIN,
discovery_info or config,
async_add_entities,
_async_setup_entity,
)
@ -74,13 +79,8 @@ async def async_setup_entry(
) -> None:
"""Set up MQTT scene 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, scene.DOMAIN, PLATFORM_SCHEMA_MODERN
)
)
config_entry.async_on_unload(
await async_setup_platform_discovery(hass, scene.DOMAIN, PLATFORM_SCHEMA_MODERN)
)
# setup for discovery
setup = functools.partial(
@ -128,7 +128,7 @@ class MqttScene(
This method is a coroutine.
"""
await mqtt.async_publish(
await async_publish(
self.hass,
self._config[CONF_COMMAND_TOPIC],
self._config[CONF_PAYLOAD_ON],

View File

@ -1,7 +1,6 @@
"""Configure select in a device through MQTT topic."""
from __future__ import annotations
import asyncio
import functools
import logging
@ -17,8 +16,8 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.restore_state import RestoreEntity
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
from . import MqttCommandTemplate, MqttValueTemplate, subscription
from .. import mqtt
from . import subscription
from .config import MQTT_RW_SCHEMA
from .const import (
CONF_COMMAND_TEMPLATE,
CONF_COMMAND_TOPIC,
@ -31,11 +30,12 @@ from .debug_info import log_messages
from .mixins import (
MQTT_ENTITY_COMMON_SCHEMA,
MqttEntity,
async_get_platform_config_from_yaml,
async_setup_entry_helper,
async_setup_platform_discovery,
async_setup_platform_helper,
warn_for_legacy_schema,
)
from .models import MqttCommandTemplate, MqttValueTemplate
_LOGGER = logging.getLogger(__name__)
@ -51,7 +51,7 @@ MQTT_SELECT_ATTRIBUTES_BLOCKED = frozenset(
)
PLATFORM_SCHEMA_MODERN = mqtt.MQTT_RW_SCHEMA.extend(
PLATFORM_SCHEMA_MODERN = MQTT_RW_SCHEMA.extend(
{
vol.Optional(CONF_COMMAND_TEMPLATE): cv.template,
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
@ -79,7 +79,11 @@ async def async_setup_platform(
"""Set up MQTT select configured under the select platform key (deprecated)."""
# Deprecated in HA Core 2022.6
await async_setup_platform_helper(
hass, select.DOMAIN, config, async_add_entities, _async_setup_entity
hass,
select.DOMAIN,
discovery_info or config,
async_add_entities,
_async_setup_entity,
)
@ -90,12 +94,9 @@ async def async_setup_entry(
) -> None:
"""Set up MQTT select 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, select.DOMAIN, PLATFORM_SCHEMA_MODERN
)
config_entry.async_on_unload(
await async_setup_platform_discovery(
hass, select.DOMAIN, PLATFORM_SCHEMA_MODERN
)
)
# setup for discovery

View File

@ -1,7 +1,6 @@
"""Support for MQTT sensors."""
from __future__ import annotations
import asyncio
from datetime import timedelta
import functools
import logging
@ -34,19 +33,21 @@ from homeassistant.helpers.event import async_track_point_in_utc_time
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
from homeassistant.util import dt as dt_util
from . import MqttValueTemplate, subscription
from .. import mqtt
from . import subscription
from .config import MQTT_RO_SCHEMA
from .const import CONF_ENCODING, CONF_QOS, CONF_STATE_TOPIC
from .debug_info import log_messages
from .mixins import (
MQTT_ENTITY_COMMON_SCHEMA,
MqttAvailability,
MqttEntity,
async_get_platform_config_from_yaml,
async_setup_entry_helper,
async_setup_platform_discovery,
async_setup_platform_helper,
warn_for_legacy_schema,
)
from .models import MqttValueTemplate
from .util import valid_subscribe_topic
_LOGGER = logging.getLogger(__name__)
@ -89,12 +90,12 @@ def validate_options(conf):
return conf
_PLATFORM_SCHEMA_BASE = mqtt.MQTT_RO_SCHEMA.extend(
_PLATFORM_SCHEMA_BASE = MQTT_RO_SCHEMA.extend(
{
vol.Optional(CONF_DEVICE_CLASS): DEVICE_CLASSES_SCHEMA,
vol.Optional(CONF_EXPIRE_AFTER): cv.positive_int,
vol.Optional(CONF_FORCE_UPDATE, default=DEFAULT_FORCE_UPDATE): cv.boolean,
vol.Optional(CONF_LAST_RESET_TOPIC): mqtt.valid_subscribe_topic,
vol.Optional(CONF_LAST_RESET_TOPIC): valid_subscribe_topic,
vol.Optional(CONF_LAST_RESET_VALUE_TEMPLATE): cv.template,
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
vol.Optional(CONF_STATE_CLASS): STATE_CLASSES_SCHEMA,
@ -131,7 +132,11 @@ async def async_setup_platform(
"""Set up MQTT sensors configured under the fan platform key (deprecated)."""
# Deprecated in HA Core 2022.6
await async_setup_platform_helper(
hass, sensor.DOMAIN, config, async_add_entities, _async_setup_entity
hass,
sensor.DOMAIN,
discovery_info or config,
async_add_entities,
_async_setup_entity,
)
@ -142,12 +147,9 @@ async def async_setup_entry(
) -> None:
"""Set up MQTT sensor 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, sensor.DOMAIN, PLATFORM_SCHEMA_MODERN
)
config_entry.async_on_unload(
await async_setup_platform_discovery(
hass, sensor.DOMAIN, PLATFORM_SCHEMA_MODERN
)
)
# setup for discovery

View File

@ -1,7 +1,6 @@
"""Support for MQTT sirens."""
from __future__ import annotations
import asyncio
import copy
import functools
import json
@ -35,8 +34,8 @@ import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
from . import MqttCommandTemplate, MqttValueTemplate, subscription
from .. import mqtt
from . import subscription
from .config import MQTT_RW_SCHEMA
from .const import (
CONF_COMMAND_TEMPLATE,
CONF_COMMAND_TOPIC,
@ -52,11 +51,12 @@ from .debug_info import log_messages
from .mixins import (
MQTT_ENTITY_COMMON_SCHEMA,
MqttEntity,
async_get_platform_config_from_yaml,
async_setup_entry_helper,
async_setup_platform_discovery,
async_setup_platform_helper,
warn_for_legacy_schema,
)
from .models import MqttCommandTemplate, MqttValueTemplate
DEFAULT_NAME = "MQTT Siren"
DEFAULT_PAYLOAD_ON = "ON"
@ -74,7 +74,7 @@ CONF_SUPPORT_VOLUME_SET = "support_volume_set"
STATE = "state"
PLATFORM_SCHEMA_MODERN = mqtt.MQTT_RW_SCHEMA.extend(
PLATFORM_SCHEMA_MODERN = MQTT_RW_SCHEMA.extend(
{
vol.Optional(CONF_AVAILABLE_TONES): cv.ensure_list,
vol.Optional(CONF_COMMAND_TEMPLATE): cv.template,
@ -128,7 +128,11 @@ async def async_setup_platform(
"""Set up MQTT sirens configured under the fan platform key (deprecated)."""
# Deprecated in HA Core 2022.6
await async_setup_platform_helper(
hass, siren.DOMAIN, config, async_add_entities, _async_setup_entity
hass,
siren.DOMAIN,
discovery_info or config,
async_add_entities,
_async_setup_entity,
)
@ -139,13 +143,8 @@ async def async_setup_entry(
) -> None:
"""Set up MQTT siren 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, siren.DOMAIN, PLATFORM_SCHEMA_MODERN
)
)
config_entry.async_on_unload(
await async_setup_platform_discovery(hass, siren.DOMAIN, PLATFORM_SCHEMA_MODERN)
)
# setup for discovery
setup = functools.partial(

View File

@ -1,7 +1,6 @@
"""Support for MQTT switches."""
from __future__ import annotations
import asyncio
import functools
import voluptuous as vol
@ -24,8 +23,8 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.restore_state import RestoreEntity
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
from . import MqttValueTemplate, subscription
from .. import mqtt
from . import subscription
from .config import MQTT_RW_SCHEMA
from .const import (
CONF_COMMAND_TOPIC,
CONF_ENCODING,
@ -38,11 +37,12 @@ from .debug_info import log_messages
from .mixins import (
MQTT_ENTITY_COMMON_SCHEMA,
MqttEntity,
async_get_platform_config_from_yaml,
async_setup_entry_helper,
async_setup_platform_discovery,
async_setup_platform_helper,
warn_for_legacy_schema,
)
from .models import MqttValueTemplate
DEFAULT_NAME = "MQTT Switch"
DEFAULT_PAYLOAD_ON = "ON"
@ -51,7 +51,7 @@ DEFAULT_OPTIMISTIC = False
CONF_STATE_ON = "state_on"
CONF_STATE_OFF = "state_off"
PLATFORM_SCHEMA_MODERN = mqtt.MQTT_RW_SCHEMA.extend(
PLATFORM_SCHEMA_MODERN = MQTT_RW_SCHEMA.extend(
{
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
vol.Optional(CONF_OPTIMISTIC, default=DEFAULT_OPTIMISTIC): cv.boolean,
@ -82,7 +82,11 @@ async def async_setup_platform(
"""Set up MQTT switch configured under the fan platform key (deprecated)."""
# Deprecated in HA Core 2022.6
await async_setup_platform_helper(
hass, switch.DOMAIN, config, async_add_entities, _async_setup_entity
hass,
switch.DOMAIN,
discovery_info or config,
async_add_entities,
_async_setup_entity,
)
@ -93,12 +97,9 @@ async def async_setup_entry(
) -> None:
"""Set up MQTT switch 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, switch.DOMAIN, PLATFORM_SCHEMA_MODERN
)
config_entry.async_on_unload(
await async_setup_platform_discovery(
hass, switch.DOMAIN, PLATFORM_SCHEMA_MODERN
)
)
# setup for discovery

View File

@ -11,8 +11,8 @@ from homeassistant.core import HomeAssistant, callback
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.typing import ConfigType
from . import MqttValueTemplate, subscription
from .. import mqtt
from . import subscription
from .config import MQTT_BASE_SCHEMA
from .const import ATTR_DISCOVERY_HASH, CONF_QOS, CONF_TOPIC
from .mixins import (
MQTT_ENTITY_DEVICE_INFO_SCHEMA,
@ -21,7 +21,7 @@ from .mixins import (
send_discovery_done,
update_device,
)
from .models import ReceiveMessage
from .models import MqttValueTemplate, ReceiveMessage
from .subscription import EntitySubscription
from .util import valid_subscribe_topic
@ -30,7 +30,7 @@ LOG_NAME = "Tag"
TAG = "tag"
TAGS = "mqtt_tags"
PLATFORM_SCHEMA = mqtt.MQTT_BASE_PLATFORM_SCHEMA.extend(
PLATFORM_SCHEMA = MQTT_BASE_SCHEMA.extend(
{
vol.Optional(CONF_DEVICE): MQTT_ENTITY_DEVICE_INFO_SCHEMA,
vol.Optional(CONF_PLATFORM): "mqtt",

View File

@ -1,7 +1,6 @@
"""Support for MQTT vacuums."""
from __future__ import annotations
import asyncio
import functools
import voluptuous as vol
@ -13,8 +12,8 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
from ..mixins import (
async_get_platform_config_from_yaml,
async_setup_entry_helper,
async_setup_platform_discovery,
async_setup_platform_helper,
)
from .schema import CONF_SCHEMA, LEGACY, MQTT_VACUUM_SCHEMA, STATE
@ -77,7 +76,11 @@ async def async_setup_platform(
"""Set up MQTT vacuum through configuration.yaml."""
# Deprecated in HA Core 2022.6
await async_setup_platform_helper(
hass, vacuum.DOMAIN, config, async_add_entities, _async_setup_entity
hass,
vacuum.DOMAIN,
discovery_info or config,
async_add_entities,
_async_setup_entity,
)
@ -88,12 +91,9 @@ async def async_setup_entry(
) -> None:
"""Set up MQTT vacuum 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, vacuum.DOMAIN, PLATFORM_SCHEMA_MODERN
)
config_entry.async_on_unload(
await async_setup_platform_discovery(
hass, vacuum.DOMAIN, PLATFORM_SCHEMA_MODERN
)
)
# setup for discovery

View File

@ -15,11 +15,13 @@ from homeassistant.core import callback
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.icon import icon_for_battery_level
from .. import MqttValueTemplate, subscription
from ... import mqtt
from .. import subscription
from ..config import MQTT_BASE_SCHEMA
from ..const import CONF_COMMAND_TOPIC, CONF_ENCODING, CONF_QOS, CONF_RETAIN
from ..debug_info import log_messages
from ..mixins import MQTT_ENTITY_COMMON_SCHEMA, MqttEntity, warn_for_legacy_schema
from ..models import MqttValueTemplate
from ..util import valid_publish_topic
from .const import MQTT_VACUUM_ATTRIBUTES_BLOCKED
from .schema import MQTT_VACUUM_SCHEMA, services_to_strings, strings_to_services
@ -96,25 +98,23 @@ MQTT_LEGACY_VACUUM_ATTRIBUTES_BLOCKED = MQTT_VACUUM_ATTRIBUTES_BLOCKED | frozens
)
PLATFORM_SCHEMA_LEGACY_MODERN = (
mqtt.MQTT_BASE_SCHEMA.extend(
MQTT_BASE_SCHEMA.extend(
{
vol.Inclusive(CONF_BATTERY_LEVEL_TEMPLATE, "battery"): cv.template,
vol.Inclusive(
CONF_BATTERY_LEVEL_TOPIC, "battery"
): mqtt.valid_publish_topic,
vol.Inclusive(CONF_BATTERY_LEVEL_TOPIC, "battery"): valid_publish_topic,
vol.Inclusive(CONF_CHARGING_TEMPLATE, "charging"): cv.template,
vol.Inclusive(CONF_CHARGING_TOPIC, "charging"): mqtt.valid_publish_topic,
vol.Inclusive(CONF_CHARGING_TOPIC, "charging"): valid_publish_topic,
vol.Inclusive(CONF_CLEANING_TEMPLATE, "cleaning"): cv.template,
vol.Inclusive(CONF_CLEANING_TOPIC, "cleaning"): mqtt.valid_publish_topic,
vol.Inclusive(CONF_CLEANING_TOPIC, "cleaning"): valid_publish_topic,
vol.Inclusive(CONF_DOCKED_TEMPLATE, "docked"): cv.template,
vol.Inclusive(CONF_DOCKED_TOPIC, "docked"): mqtt.valid_publish_topic,
vol.Inclusive(CONF_DOCKED_TOPIC, "docked"): valid_publish_topic,
vol.Inclusive(CONF_ERROR_TEMPLATE, "error"): cv.template,
vol.Inclusive(CONF_ERROR_TOPIC, "error"): mqtt.valid_publish_topic,
vol.Inclusive(CONF_ERROR_TOPIC, "error"): valid_publish_topic,
vol.Optional(CONF_FAN_SPEED_LIST, default=[]): vol.All(
cv.ensure_list, [cv.string]
),
vol.Inclusive(CONF_FAN_SPEED_TEMPLATE, "fan_speed"): cv.template,
vol.Inclusive(CONF_FAN_SPEED_TOPIC, "fan_speed"): mqtt.valid_publish_topic,
vol.Inclusive(CONF_FAN_SPEED_TOPIC, "fan_speed"): valid_publish_topic,
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
vol.Optional(
CONF_PAYLOAD_CLEAN_SPOT, default=DEFAULT_PAYLOAD_CLEAN_SPOT
@ -135,12 +135,12 @@ PLATFORM_SCHEMA_LEGACY_MODERN = (
vol.Optional(
CONF_PAYLOAD_TURN_ON, default=DEFAULT_PAYLOAD_TURN_ON
): cv.string,
vol.Optional(CONF_SEND_COMMAND_TOPIC): mqtt.valid_publish_topic,
vol.Optional(CONF_SET_FAN_SPEED_TOPIC): mqtt.valid_publish_topic,
vol.Optional(CONF_SEND_COMMAND_TOPIC): valid_publish_topic,
vol.Optional(CONF_SET_FAN_SPEED_TOPIC): valid_publish_topic,
vol.Optional(
CONF_SUPPORTED_FEATURES, default=DEFAULT_SERVICE_STRINGS
): vol.All(cv.ensure_list, [vol.In(STRING_TO_SERVICE.keys())]),
vol.Optional(CONF_COMMAND_TOPIC): mqtt.valid_publish_topic,
vol.Optional(CONF_COMMAND_TOPIC): valid_publish_topic,
vol.Optional(CONF_RETAIN, default=DEFAULT_RETAIN): cv.boolean,
}
)

View File

@ -23,7 +23,7 @@ from homeassistant.core import callback
import homeassistant.helpers.config_validation as cv
from .. import subscription
from ... import mqtt
from ..config import MQTT_BASE_SCHEMA
from ..const import (
CONF_COMMAND_TOPIC,
CONF_ENCODING,
@ -33,6 +33,7 @@ from ..const import (
)
from ..debug_info import log_messages
from ..mixins import MQTT_ENTITY_COMMON_SCHEMA, MqttEntity, warn_for_legacy_schema
from ..util import valid_publish_topic
from .const import MQTT_VACUUM_ATTRIBUTES_BLOCKED
from .schema import MQTT_VACUUM_SCHEMA, services_to_strings, strings_to_services
@ -105,7 +106,7 @@ DEFAULT_PAYLOAD_START = "start"
DEFAULT_PAYLOAD_PAUSE = "pause"
PLATFORM_SCHEMA_STATE_MODERN = (
mqtt.MQTT_BASE_SCHEMA.extend(
MQTT_BASE_SCHEMA.extend(
{
vol.Optional(CONF_FAN_SPEED_LIST, default=[]): vol.All(
cv.ensure_list, [cv.string]
@ -123,13 +124,13 @@ PLATFORM_SCHEMA_STATE_MODERN = (
vol.Optional(CONF_PAYLOAD_START, default=DEFAULT_PAYLOAD_START): cv.string,
vol.Optional(CONF_PAYLOAD_PAUSE, default=DEFAULT_PAYLOAD_PAUSE): cv.string,
vol.Optional(CONF_PAYLOAD_STOP, default=DEFAULT_PAYLOAD_STOP): cv.string,
vol.Optional(CONF_SEND_COMMAND_TOPIC): mqtt.valid_publish_topic,
vol.Optional(CONF_SET_FAN_SPEED_TOPIC): mqtt.valid_publish_topic,
vol.Optional(CONF_STATE_TOPIC): mqtt.valid_publish_topic,
vol.Optional(CONF_SEND_COMMAND_TOPIC): valid_publish_topic,
vol.Optional(CONF_SET_FAN_SPEED_TOPIC): valid_publish_topic,
vol.Optional(CONF_STATE_TOPIC): valid_publish_topic,
vol.Optional(
CONF_SUPPORTED_FEATURES, default=DEFAULT_SERVICE_STRINGS
): vol.All(cv.ensure_list, [vol.In(STRING_TO_SERVICE.keys())]),
vol.Optional(CONF_COMMAND_TOPIC): mqtt.valid_publish_topic,
vol.Optional(CONF_COMMAND_TOPIC): valid_publish_topic,
vol.Optional(CONF_RETAIN, default=DEFAULT_RETAIN): cv.boolean,
}
)
@ -178,7 +179,7 @@ class MqttStateVacuum(MqttEntity, StateVacuumEntity):
supported_feature_strings, STRING_TO_SERVICE
)
self._fan_speed_list = config[CONF_FAN_SPEED_LIST]
self._command_topic = config.get(mqtt.CONF_COMMAND_TOPIC)
self._command_topic = config.get(CONF_COMMAND_TOPIC)
self._set_fan_speed_topic = config.get(CONF_SET_FAN_SPEED_TOPIC)
self._send_command_topic = config.get(CONF_SEND_COMMAND_TOPIC)

View File

@ -35,7 +35,7 @@ GPS_JSON_PAYLOAD_SCHEMA = vol.Schema(
extra=vol.ALLOW_EXTRA,
)
PLATFORM_SCHEMA = PARENT_PLATFORM_SCHEMA.extend(mqtt.SCHEMA_BASE).extend(
PLATFORM_SCHEMA = PARENT_PLATFORM_SCHEMA.extend(mqtt.config.SCHEMA_BASE).extend(
{vol.Required(CONF_DEVICES): {cv.string: mqtt.valid_subscribe_topic}}
)

View File

@ -43,7 +43,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(
vol.Optional(CONF_AWAY_TIMEOUT, default=DEFAULT_AWAY_TIMEOUT): cv.positive_int,
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
}
).extend(mqtt.MQTT_RO_PLATFORM_SCHEMA.schema)
).extend(mqtt.config.MQTT_RO_SCHEMA.schema)
MQTT_PAYLOAD = vol.Schema(
vol.All(

View File

@ -3,6 +3,7 @@ from __future__ import annotations
import asyncio
from collections.abc import Callable, Iterable
from concurrent.futures import CancelledError
import contextlib
from datetime import datetime, timedelta
import logging
@ -518,9 +519,16 @@ class Recorder(threading.Thread):
def _wait_startup_or_shutdown(self) -> object | None:
"""Wait for startup or shutdown before starting."""
return asyncio.run_coroutine_threadsafe(
self._async_wait_for_started(), self.hass.loop
).result()
try:
return asyncio.run_coroutine_threadsafe(
self._async_wait_for_started(), self.hass.loop
).result()
except CancelledError as ex:
_LOGGER.warning(
"Recorder startup was externally canceled before it could complete: %s",
ex,
)
return SHUTDOWN_TASK
def run(self) -> None:
"""Start processing events to save."""

View File

@ -36,7 +36,7 @@ def extract_include_exclude_filter_conf(conf: ConfigType) -> dict[str, Any]:
"""
return {
filter_type: {
matcher: set(conf.get(filter_type, {}).get(matcher, []))
matcher: set(conf.get(filter_type, {}).get(matcher) or [])
for matcher in FITLER_MATCHERS
}
for filter_type in FILTER_TYPES
@ -88,14 +88,32 @@ class Filters:
self.included_domains: Iterable[str] = []
self.included_entity_globs: Iterable[str] = []
def __repr__(self) -> str:
"""Return human readable excludes/includes."""
return (
f"<Filters excluded_entities={self.excluded_entities} excluded_domains={self.excluded_domains} "
f"excluded_entity_globs={self.excluded_entity_globs} "
f"included_entities={self.included_entities} included_domains={self.included_domains} "
f"included_entity_globs={self.included_entity_globs}>"
)
@property
def has_config(self) -> bool:
"""Determine if there is any filter configuration."""
return bool(self._have_exclude or self._have_include)
@property
def _have_exclude(self) -> bool:
return bool(
self.excluded_entities
or self.excluded_domains
or self.excluded_entity_globs
or self.included_entities
)
@property
def _have_include(self) -> bool:
return bool(
self.included_entities
or self.included_domains
or self.included_entity_globs
)
@ -103,36 +121,67 @@ class Filters:
def _generate_filter_for_columns(
self, columns: Iterable[Column], encoder: Callable[[Any], Any]
) -> ClauseList:
includes = []
if self.included_domains:
includes.append(_domain_matcher(self.included_domains, columns, encoder))
if self.included_entities:
includes.append(_entity_matcher(self.included_entities, columns, encoder))
if self.included_entity_globs:
includes.append(
_globs_to_like(self.included_entity_globs, columns, encoder)
)
"""Generate a filter from pre-comuted sets and pattern lists.
excludes = []
if self.excluded_domains:
excludes.append(_domain_matcher(self.excluded_domains, columns, encoder))
if self.excluded_entities:
excludes.append(_entity_matcher(self.excluded_entities, columns, encoder))
if self.excluded_entity_globs:
excludes.append(
_globs_to_like(self.excluded_entity_globs, columns, encoder)
)
This must match exactly how homeassistant.helpers.entityfilter works.
"""
i_domains = _domain_matcher(self.included_domains, columns, encoder)
i_entities = _entity_matcher(self.included_entities, columns, encoder)
i_entity_globs = _globs_to_like(self.included_entity_globs, columns, encoder)
includes = [i_domains, i_entities, i_entity_globs]
if not includes and not excludes:
e_domains = _domain_matcher(self.excluded_domains, columns, encoder)
e_entities = _entity_matcher(self.excluded_entities, columns, encoder)
e_entity_globs = _globs_to_like(self.excluded_entity_globs, columns, encoder)
excludes = [e_domains, e_entities, e_entity_globs]
have_exclude = self._have_exclude
have_include = self._have_include
# Case 1 - no includes or excludes - pass all entities
if not have_include and not have_exclude:
return None
if includes and not excludes:
# Case 2 - includes, no excludes - only include specified entities
if have_include and not have_exclude:
return or_(*includes).self_group()
if not includes and excludes:
# Case 3 - excludes, no includes - only exclude specified entities
if not have_include and have_exclude:
return not_(or_(*excludes).self_group())
return or_(*includes).self_group() & not_(or_(*excludes).self_group())
# Case 4 - both includes and excludes specified
# Case 4a - include domain or glob specified
# - if domain is included, pass if entity not excluded
# - if glob is included, pass if entity and domain not excluded
# - if domain and glob are not included, pass if entity is included
# note: if both include domain matches then exclude domains ignored.
# If glob matches then exclude domains and glob checked
if self.included_domains or self.included_entity_globs:
return or_(
(i_domains & ~(e_entities | e_entity_globs)),
(
~i_domains
& or_(
(i_entity_globs & ~(or_(*excludes))),
(~i_entity_globs & i_entities),
)
),
).self_group()
# Case 4b - exclude domain or glob specified, include has no domain or glob
# In this one case the traditional include logic is inverted. Even though an
# include is specified since its only a list of entity IDs its used only to
# expose specific entities excluded by domain or glob. Any entities not
# excluded are then presumed included. Logic is as follows
# - if domain or glob is excluded, pass if entity is included
# - if domain is not excluded, pass if entity not excluded by ID
if self.excluded_domains or self.excluded_entity_globs:
return (not_(or_(*excludes)) | i_entities).self_group()
# Case 4c - neither include or exclude domain specified
# - Only pass if entity is included. Ignore entity excludes.
return i_entities
def states_entity_filter(self) -> ClauseList:
"""Generate the entity filter query."""
@ -158,29 +207,32 @@ def _globs_to_like(
glob_strs: Iterable[str], columns: Iterable[Column], encoder: Callable[[Any], Any]
) -> ClauseList:
"""Translate glob to sql."""
return or_(
matchers = [
cast(column, Text()).like(
encoder(glob_str).translate(GLOB_TO_SQL_CHARS), escape="\\"
)
for glob_str in glob_strs
for column in columns
)
]
return or_(*matchers) if matchers else or_(False)
def _entity_matcher(
entity_ids: Iterable[str], columns: Iterable[Column], encoder: Callable[[Any], Any]
) -> ClauseList:
return or_(
matchers = [
cast(column, Text()).in_([encoder(entity_id) for entity_id in entity_ids])
for column in columns
)
]
return or_(*matchers) if matchers else or_(False)
def _domain_matcher(
domains: Iterable[str], columns: Iterable[Column], encoder: Callable[[Any], Any]
) -> ClauseList:
return or_(
matchers = [
cast(column, Text()).like(encoder(f"{domain}.%"))
for domain in domains
for column in columns
)
]
return or_(*matchers) if matchers else or_(False)

View File

@ -237,7 +237,9 @@ def _significant_states_stmt(
stmt += _ignore_domains_filter
if filters and filters.has_config:
entity_filter = filters.states_entity_filter()
stmt += lambda q: q.filter(entity_filter)
stmt = stmt.add_criteria(
lambda q: q.filter(entity_filter), track_on=[filters]
)
stmt += lambda q: q.filter(States.last_updated > start_time)
if end_time:
@ -529,7 +531,7 @@ def _get_states_for_all_stmt(
stmt += _ignore_domains_filter
if filters and filters.has_config:
entity_filter = filters.states_entity_filter()
stmt += lambda q: q.filter(entity_filter)
stmt = stmt.add_criteria(lambda q: q.filter(entity_filter), track_on=[filters])
if join_attributes:
stmt += lambda q: q.outerjoin(
StateAttributes, (States.attributes_id == StateAttributes.attributes_id)

View File

@ -715,14 +715,13 @@ def _apply_update( # noqa: C901
if engine.dialect.name == SupportedDialect.MYSQL:
# Ensure the row format is dynamic or the index
# unique will be too large
with session_scope(session=session_maker()) as session:
connection = session.connection()
# This is safe to run multiple times and fast since the table is small
connection.execute(
text(
"ALTER TABLE statistics_meta ENGINE=InnoDB, ROW_FORMAT=DYNAMIC"
with contextlib.suppress(SQLAlchemyError):
with session_scope(session=session_maker()) as session:
connection = session.connection()
# This is safe to run multiple times and fast since the table is small
connection.execute(
text("ALTER TABLE statistics_meta ROW_FORMAT=DYNAMIC")
)
)
try:
_create_index(
session_maker, "statistics_meta", "ix_statistics_meta_statistic_id"

View File

@ -93,6 +93,8 @@ TABLES_TO_CHECK = [
LAST_UPDATED_INDEX = "ix_states_last_updated"
ENTITY_ID_LAST_UPDATED_INDEX = "ix_states_entity_id_last_updated"
EVENTS_CONTEXT_ID_INDEX = "ix_events_context_id"
STATES_CONTEXT_ID_INDEX = "ix_states_context_id"
EMPTY_JSON_OBJECT = "{}"

View File

@ -25,7 +25,6 @@ from homeassistant.components.media_player import (
)
from homeassistant.components.media_player.const import (
ATTR_INPUT_SOURCE,
ATTR_MEDIA_ANNOUNCE,
ATTR_MEDIA_ENQUEUE,
MEDIA_TYPE_ALBUM,
MEDIA_TYPE_ARTIST,
@ -544,9 +543,6 @@ class SonosMediaPlayerEntity(SonosEntity, MediaPlayerEntity):
"""
# Use 'replace' as the default enqueue option
enqueue = kwargs.get(ATTR_MEDIA_ENQUEUE, MediaPlayerEnqueue.REPLACE)
if kwargs.get(ATTR_MEDIA_ANNOUNCE):
# Temporary workaround until announce support is added
enqueue = MediaPlayerEnqueue.PLAY
if spotify.is_spotify_media_type(media_type):
media_type = spotify.resolve_spotify_media_type(media_type)

View File

@ -3,7 +3,7 @@
"name": "YoLink",
"config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/yolink",
"requirements": ["yolink-api==0.0.5"],
"requirements": ["yolink-api==0.0.6"],
"dependencies": ["auth", "application_credentials"],
"codeowners": ["@matrixd2"],
"iot_class": "cloud_push"

View File

@ -7,7 +7,7 @@ from .backports.enum import StrEnum
MAJOR_VERSION: Final = 2022
MINOR_VERSION: Final = 6
PATCH_VERSION: Final = "0"
PATCH_VERSION: Final = "1"
__short_version__: Final = f"{MAJOR_VERSION}.{MINOR_VERSION}"
__version__: Final = f"{__short_version__}.{PATCH_VERSION}"
REQUIRED_PYTHON_VER: Final[tuple[int, int, int]] = (3, 9, 0)

View File

@ -15,7 +15,7 @@ ciso8601==2.2.0
cryptography==36.0.2
fnvhash==0.1.0
hass-nabucasa==0.54.0
home-assistant-frontend==20220531.0
home-assistant-frontend==20220601.0
httpx==0.23.0
ifaddr==0.1.7
jinja2==3.1.2

View File

@ -122,7 +122,7 @@ aioasuswrt==1.4.0
aioazuredevops==1.3.5
# homeassistant.components.baf
aiobafi6==0.3.0
aiobafi6==0.5.0
# homeassistant.components.aws
aiobotocore==2.1.0
@ -822,7 +822,7 @@ hole==0.7.0
holidays==0.13
# homeassistant.components.frontend
home-assistant-frontend==20220531.0
home-assistant-frontend==20220601.0
# homeassistant.components.home_connect
homeconnect==0.7.0
@ -1538,7 +1538,7 @@ pyheos==0.7.2
pyhik==0.3.0
# homeassistant.components.hive
pyhiveapi==0.5.4
pyhiveapi==0.5.5
# homeassistant.components.homematic
pyhomematic==0.1.77
@ -2486,7 +2486,7 @@ yeelight==0.7.10
yeelightsunflower==0.0.10
# homeassistant.components.yolink
yolink-api==0.0.5
yolink-api==0.0.6
# homeassistant.components.youless
youless-api==0.16

View File

@ -109,7 +109,7 @@ aioasuswrt==1.4.0
aioazuredevops==1.3.5
# homeassistant.components.baf
aiobafi6==0.3.0
aiobafi6==0.5.0
# homeassistant.components.aws
aiobotocore==2.1.0
@ -589,7 +589,7 @@ hole==0.7.0
holidays==0.13
# homeassistant.components.frontend
home-assistant-frontend==20220531.0
home-assistant-frontend==20220601.0
# homeassistant.components.home_connect
homeconnect==0.7.0
@ -1029,7 +1029,7 @@ pyhaversion==22.4.1
pyheos==0.7.2
# homeassistant.components.hive
pyhiveapi==0.5.4
pyhiveapi==0.5.5
# homeassistant.components.homematic
pyhomematic==0.1.77
@ -1638,7 +1638,7 @@ yalexs==1.1.25
yeelight==0.7.10
# homeassistant.components.yolink
yolink-api==0.0.5
yolink-api==0.0.6
# homeassistant.components.youless
youless-api==0.16

View File

@ -2,24 +2,24 @@
# ==============================================================================
# Take down the S6 supervision tree when Home Assistant fails
# ==============================================================================
declare RESTART_EXIT_CODE 100
declare SIGNAL_EXIT_CODE 256
declare SIGTERM 15
declare RESTART_EXIT_CODE=100
declare SIGNAL_EXIT_CODE=256
declare SIGTERM=15
declare APP_EXIT_CODE=${1}
declare SYS_EXIT_CODE=${2+x}
declare SIGNAL_NO=${2}
declare NEW_EXIT_CODE=
bashio::log.info "Home Assistant Core finish process exit code ${1}"
bashio::log.info "Home Assistant Core finish process exit code ${APP_EXIT_CODE}"
if [[ ${APP_EXIT_CODE} -eq ${RESTART_EXIT_CODE} ]]; then
exit 0
elif [[ ${APP_EXIT_CODE} -eq ${SIGNAL_EXIT_CODE} ]]; then
bashio::log.info "Home Assistant Core finish process received signal ${APP_EXIT_CODE}"
bashio::log.info "Home Assistant Core finish process received signal ${SIGNAL_NO}"
NEW_EXIT_CODE=$((128 + SYS_EXIT_CODE))
NEW_EXIT_CODE=$((128 + SIGNAL_NO))
echo ${NEW_EXIT_CODE} > /run/s6-linux-init-container-results/exitcode
if [[ ${NEW_EXIT_CODE} -eq ${SIGTERM} ]]; then
if [[ ${SIGNAL_NO} -eq ${SIGTERM} ]]; then
/run/s6/basedir/bin/halt
fi
else

View File

@ -1,5 +1,5 @@
[metadata]
version = 2022.6.0
version = 2022.6.1
url = https://www.home-assistant.io/
[options]

View File

@ -246,15 +246,11 @@ def test_get_significant_states_exclude(hass_history):
def test_get_significant_states_exclude_include_entity(hass_history):
"""Test significant states when excluding domains and include entities.
We should not get back every thermostat and media player test changes.
We should not get back every thermostat change unless its specifically included
"""
hass = hass_history
zero, four, states = record_states(hass)
del states["media_player.test2"]
del states["media_player.test3"]
del states["thermostat.test"]
del states["thermostat.test2"]
del states["script.can_cancel_this_one"]
config = history.CONFIG_SCHEMA(
{
@ -340,14 +336,12 @@ def test_get_significant_states_include(hass_history):
def test_get_significant_states_include_exclude_domain(hass_history):
"""Test if significant states when excluding and including domains.
We should not get back any changes since we include only the
media_player domain but also exclude it.
We should get back all the media_player domain changes
only since the include wins over the exclude but will
exclude everything else.
"""
hass = hass_history
zero, four, states = record_states(hass)
del states["media_player.test"]
del states["media_player.test2"]
del states["media_player.test3"]
del states["thermostat.test"]
del states["thermostat.test2"]
del states["script.can_cancel_this_one"]
@ -372,7 +366,6 @@ def test_get_significant_states_include_exclude_entity(hass_history):
"""
hass = hass_history
zero, four, states = record_states(hass)
del states["media_player.test"]
del states["media_player.test2"]
del states["media_player.test3"]
del states["thermostat.test"]
@ -394,12 +387,12 @@ def test_get_significant_states_include_exclude_entity(hass_history):
def test_get_significant_states_include_exclude(hass_history):
"""Test if significant states when in/excluding domains and entities.
We should only get back changes of the media_player.test2 entity.
We should get back changes of the media_player.test2, media_player.test3,
and thermostat.test.
"""
hass = hass_history
zero, four, states = record_states(hass)
del states["media_player.test"]
del states["thermostat.test"]
del states["thermostat.test2"]
del states["script.can_cancel_this_one"]

View File

@ -357,7 +357,7 @@ async def test_measure_multiple(hass, recorder_mock):
await hass.async_block_till_done()
assert hass.states.get("sensor.sensor1").state == "0.5"
assert hass.states.get("sensor.sensor2").state == STATE_UNKNOWN
assert hass.states.get("sensor.sensor2").state == "0.0"
assert hass.states.get("sensor.sensor3").state == "2"
assert hass.states.get("sensor.sensor4").state == "50.0"

View File

@ -33,6 +33,9 @@ async def test_import_flow(hass):
"AccessToken": "mock-access-token",
},
},
), patch(
"homeassistant.components.hive.config_flow.Auth.device_registration",
return_value=True,
), patch(
"homeassistant.components.hive.config_flow.Auth.getDeviceData",
return_value=[
@ -93,6 +96,9 @@ async def test_user_flow(hass):
"AccessToken": "mock-access-token",
},
},
), patch(
"homeassistant.components.hive.config_flow.Auth.device_registration",
return_value=True,
), patch(
"homeassistant.components.hive.config_flow.Auth.getDeviceData",
return_value=[
@ -172,6 +178,9 @@ async def test_user_flow_2fa(hass):
"AccessToken": "mock-access-token",
},
},
), patch(
"homeassistant.components.hive.config_flow.Auth.device_registration",
return_value=True,
), patch(
"homeassistant.components.hive.config_flow.Auth.getDeviceData",
return_value=[
@ -256,6 +265,9 @@ async def test_reauth_flow(hass):
"AccessToken": "mock-access-token",
},
},
), patch(
"homeassistant.components.hive.config_flow.Auth.device_registration",
return_value=True,
):
result2 = await hass.config_entries.flow.async_configure(
result["flow_id"],
@ -361,6 +373,9 @@ async def test_user_flow_2fa_send_new_code(hass):
"AccessToken": "mock-access-token",
},
},
), patch(
"homeassistant.components.hive.config_flow.Auth.device_registration",
return_value=True,
), patch(
"homeassistant.components.hive.config_flow.Auth.getDeviceData",
return_value=[

View File

@ -11,7 +11,7 @@ from unittest.mock import Mock, patch
import pytest
import voluptuous as vol
from homeassistant.components import logbook
from homeassistant.components import logbook, recorder
from homeassistant.components.alexa.smart_home import EVENT_ALEXA_SMART_HOME
from homeassistant.components.automation import EVENT_AUTOMATION_TRIGGERED
from homeassistant.components.logbook.models import LazyEventPartialState
@ -2037,7 +2037,7 @@ async def test_include_events_domain_glob(hass, hass_client, recorder_mock):
_assert_entry(entries[3], name="included", entity_id=entity_id3)
async def test_include_exclude_events(hass, hass_client, recorder_mock):
async def test_include_exclude_events_no_globs(hass, hass_client, recorder_mock):
"""Test if events are filtered if include and exclude is configured."""
entity_id = "switch.bla"
entity_id2 = "sensor.blu"
@ -2082,13 +2082,15 @@ async def test_include_exclude_events(hass, hass_client, recorder_mock):
client = await hass_client()
entries = await _async_fetch_logbook(client)
assert len(entries) == 4
assert len(entries) == 6
_assert_entry(
entries[0], name="Home Assistant", message="started", domain=ha.DOMAIN
)
_assert_entry(entries[1], name="blu", entity_id=entity_id2, state="10")
_assert_entry(entries[2], name="blu", entity_id=entity_id2, state="20")
_assert_entry(entries[3], name="keep", entity_id=entity_id4, state="10")
_assert_entry(entries[1], name="bla", entity_id=entity_id, state="10")
_assert_entry(entries[2], name="blu", entity_id=entity_id2, state="10")
_assert_entry(entries[3], name="bla", entity_id=entity_id, state="20")
_assert_entry(entries[4], name="blu", entity_id=entity_id2, state="20")
_assert_entry(entries[5], name="keep", entity_id=entity_id4, state="10")
async def test_include_exclude_events_with_glob_filters(
@ -2145,13 +2147,15 @@ async def test_include_exclude_events_with_glob_filters(
client = await hass_client()
entries = await _async_fetch_logbook(client)
assert len(entries) == 4
assert len(entries) == 6
_assert_entry(
entries[0], name="Home Assistant", message="started", domain=ha.DOMAIN
)
_assert_entry(entries[1], name="blu", entity_id=entity_id2, state="10")
_assert_entry(entries[2], name="blu", entity_id=entity_id2, state="20")
_assert_entry(entries[3], name="included", entity_id=entity_id4, state="30")
_assert_entry(entries[1], name="bla", entity_id=entity_id, state="10")
_assert_entry(entries[2], name="blu", entity_id=entity_id2, state="10")
_assert_entry(entries[3], name="bla", entity_id=entity_id, state="20")
_assert_entry(entries[4], name="blu", entity_id=entity_id2, state="20")
_assert_entry(entries[5], name="included", entity_id=entity_id4, state="30")
async def test_empty_config(hass, hass_client, recorder_mock):
@ -2796,3 +2800,39 @@ async def test_get_events_with_context_state(hass, hass_ws_client, recorder_mock
assert results[3]["context_state"] == "off"
assert results[3]["context_user_id"] == "b400facee45711eaa9308bfd3d19e474"
assert "context_event_type" not in results[3]
async def test_logbook_with_empty_config(hass, recorder_mock):
"""Test we handle a empty configuration."""
assert await async_setup_component(
hass,
logbook.DOMAIN,
{
logbook.DOMAIN: {},
recorder.DOMAIN: {},
},
)
await hass.async_block_till_done()
async def test_logbook_with_non_iterable_entity_filter(hass, recorder_mock):
"""Test we handle a non-iterable entity filter."""
assert await async_setup_component(
hass,
logbook.DOMAIN,
{
logbook.DOMAIN: {
CONF_EXCLUDE: {
CONF_ENTITIES: ["light.additional_excluded"],
}
},
recorder.DOMAIN: {
CONF_EXCLUDE: {
CONF_ENTITIES: None,
CONF_DOMAINS: None,
CONF_ENTITY_GLOBS: None,
}
},
},
)
await hass.async_block_till_done()

View File

@ -26,9 +26,9 @@ from tests.components.alarm_control_panel import common
CODE = "HELLO_CODE"
async def test_fail_setup_without_state_topic(hass, mqtt_mock):
async def test_fail_setup_without_state_topic(hass, mqtt_mock_entry_with_yaml_config):
"""Test for failing with no state topic."""
with assert_setup_component(0) as config:
with assert_setup_component(0, alarm_control_panel.DOMAIN) as config:
assert await async_setup_component(
hass,
alarm_control_panel.DOMAIN,
@ -42,9 +42,9 @@ async def test_fail_setup_without_state_topic(hass, mqtt_mock):
assert not config[alarm_control_panel.DOMAIN]
async def test_fail_setup_without_command_topic(hass, mqtt_mock):
async def test_fail_setup_without_command_topic(hass, mqtt_mock_entry_with_yaml_config):
"""Test failing with no command topic."""
with assert_setup_component(0):
with assert_setup_component(0, alarm_control_panel.DOMAIN):
assert await async_setup_component(
hass,
alarm_control_panel.DOMAIN,
@ -57,7 +57,7 @@ async def test_fail_setup_without_command_topic(hass, mqtt_mock):
)
async def test_arm_home_no_pending(hass, mqtt_mock):
async def test_arm_home_no_pending(hass, mqtt_mock_entry_with_yaml_config):
"""Test arm home method."""
assert await async_setup_component(
hass,
@ -86,7 +86,9 @@ async def test_arm_home_no_pending(hass, mqtt_mock):
assert hass.states.get(entity_id).state == STATE_ALARM_ARMED_HOME
async def test_arm_home_no_pending_when_code_not_req(hass, mqtt_mock):
async def test_arm_home_no_pending_when_code_not_req(
hass, mqtt_mock_entry_with_yaml_config
):
"""Test arm home method."""
assert await async_setup_component(
hass,
@ -116,7 +118,7 @@ async def test_arm_home_no_pending_when_code_not_req(hass, mqtt_mock):
assert hass.states.get(entity_id).state == STATE_ALARM_ARMED_HOME
async def test_arm_home_with_pending(hass, mqtt_mock):
async def test_arm_home_with_pending(hass, mqtt_mock_entry_with_yaml_config):
"""Test arm home method."""
assert await async_setup_component(
hass,
@ -158,7 +160,7 @@ async def test_arm_home_with_pending(hass, mqtt_mock):
assert hass.states.get(entity_id).state == STATE_ALARM_ARMED_HOME
async def test_arm_home_with_invalid_code(hass, mqtt_mock):
async def test_arm_home_with_invalid_code(hass, mqtt_mock_entry_with_yaml_config):
"""Attempt to arm home without a valid code."""
assert await async_setup_component(
hass,
@ -187,7 +189,7 @@ async def test_arm_home_with_invalid_code(hass, mqtt_mock):
assert hass.states.get(entity_id).state == STATE_ALARM_DISARMED
async def test_arm_away_no_pending(hass, mqtt_mock):
async def test_arm_away_no_pending(hass, mqtt_mock_entry_with_yaml_config):
"""Test arm home method."""
assert await async_setup_component(
hass,
@ -216,7 +218,9 @@ async def test_arm_away_no_pending(hass, mqtt_mock):
assert hass.states.get(entity_id).state == STATE_ALARM_ARMED_AWAY
async def test_arm_away_no_pending_when_code_not_req(hass, mqtt_mock):
async def test_arm_away_no_pending_when_code_not_req(
hass, mqtt_mock_entry_with_yaml_config
):
"""Test arm home method."""
assert await async_setup_component(
hass,
@ -246,7 +250,7 @@ async def test_arm_away_no_pending_when_code_not_req(hass, mqtt_mock):
assert hass.states.get(entity_id).state == STATE_ALARM_ARMED_AWAY
async def test_arm_home_with_template_code(hass, mqtt_mock):
async def test_arm_home_with_template_code(hass, mqtt_mock_entry_with_yaml_config):
"""Attempt to arm with a template-based code."""
assert await async_setup_component(
hass,
@ -276,7 +280,7 @@ async def test_arm_home_with_template_code(hass, mqtt_mock):
assert state.state == STATE_ALARM_ARMED_HOME
async def test_arm_away_with_pending(hass, mqtt_mock):
async def test_arm_away_with_pending(hass, mqtt_mock_entry_with_yaml_config):
"""Test arm home method."""
assert await async_setup_component(
hass,
@ -318,7 +322,7 @@ async def test_arm_away_with_pending(hass, mqtt_mock):
assert hass.states.get(entity_id).state == STATE_ALARM_ARMED_AWAY
async def test_arm_away_with_invalid_code(hass, mqtt_mock):
async def test_arm_away_with_invalid_code(hass, mqtt_mock_entry_with_yaml_config):
"""Attempt to arm away without a valid code."""
assert await async_setup_component(
hass,
@ -347,7 +351,7 @@ async def test_arm_away_with_invalid_code(hass, mqtt_mock):
assert hass.states.get(entity_id).state == STATE_ALARM_DISARMED
async def test_arm_night_no_pending(hass, mqtt_mock):
async def test_arm_night_no_pending(hass, mqtt_mock_entry_with_yaml_config):
"""Test arm night method."""
assert await async_setup_component(
hass,
@ -376,7 +380,9 @@ async def test_arm_night_no_pending(hass, mqtt_mock):
assert hass.states.get(entity_id).state == STATE_ALARM_ARMED_NIGHT
async def test_arm_night_no_pending_when_code_not_req(hass, mqtt_mock):
async def test_arm_night_no_pending_when_code_not_req(
hass, mqtt_mock_entry_with_yaml_config
):
"""Test arm night method."""
assert await async_setup_component(
hass,
@ -406,7 +412,7 @@ async def test_arm_night_no_pending_when_code_not_req(hass, mqtt_mock):
assert hass.states.get(entity_id).state == STATE_ALARM_ARMED_NIGHT
async def test_arm_night_with_pending(hass, mqtt_mock):
async def test_arm_night_with_pending(hass, mqtt_mock_entry_with_yaml_config):
"""Test arm night method."""
assert await async_setup_component(
hass,
@ -454,7 +460,7 @@ async def test_arm_night_with_pending(hass, mqtt_mock):
assert hass.states.get(entity_id).state == STATE_ALARM_ARMED_NIGHT
async def test_arm_night_with_invalid_code(hass, mqtt_mock):
async def test_arm_night_with_invalid_code(hass, mqtt_mock_entry_with_yaml_config):
"""Attempt to arm night without a valid code."""
assert await async_setup_component(
hass,
@ -483,7 +489,7 @@ async def test_arm_night_with_invalid_code(hass, mqtt_mock):
assert hass.states.get(entity_id).state == STATE_ALARM_DISARMED
async def test_trigger_no_pending(hass, mqtt_mock):
async def test_trigger_no_pending(hass, mqtt_mock_entry_with_yaml_config):
"""Test triggering when no pending submitted method."""
assert await async_setup_component(
hass,
@ -521,7 +527,7 @@ async def test_trigger_no_pending(hass, mqtt_mock):
assert hass.states.get(entity_id).state == STATE_ALARM_TRIGGERED
async def test_trigger_with_delay(hass, mqtt_mock):
async def test_trigger_with_delay(hass, mqtt_mock_entry_with_yaml_config):
"""Test trigger method and switch from pending to triggered."""
assert await async_setup_component(
hass,
@ -569,7 +575,7 @@ async def test_trigger_with_delay(hass, mqtt_mock):
assert state.state == STATE_ALARM_TRIGGERED
async def test_trigger_zero_trigger_time(hass, mqtt_mock):
async def test_trigger_zero_trigger_time(hass, mqtt_mock_entry_with_yaml_config):
"""Test disabled trigger."""
assert await async_setup_component(
hass,
@ -598,7 +604,9 @@ async def test_trigger_zero_trigger_time(hass, mqtt_mock):
assert hass.states.get(entity_id).state == STATE_ALARM_DISARMED
async def test_trigger_zero_trigger_time_with_pending(hass, mqtt_mock):
async def test_trigger_zero_trigger_time_with_pending(
hass, mqtt_mock_entry_with_yaml_config
):
"""Test disabled trigger."""
assert await async_setup_component(
hass,
@ -627,7 +635,7 @@ async def test_trigger_zero_trigger_time_with_pending(hass, mqtt_mock):
assert hass.states.get(entity_id).state == STATE_ALARM_DISARMED
async def test_trigger_with_pending(hass, mqtt_mock):
async def test_trigger_with_pending(hass, mqtt_mock_entry_with_yaml_config):
"""Test arm home method."""
assert await async_setup_component(
hass,
@ -679,7 +687,9 @@ async def test_trigger_with_pending(hass, mqtt_mock):
assert hass.states.get(entity_id).state == STATE_ALARM_DISARMED
async def test_trigger_with_disarm_after_trigger(hass, mqtt_mock):
async def test_trigger_with_disarm_after_trigger(
hass, mqtt_mock_entry_with_yaml_config
):
"""Test disarm after trigger."""
assert await async_setup_component(
hass,
@ -718,7 +728,9 @@ async def test_trigger_with_disarm_after_trigger(hass, mqtt_mock):
assert hass.states.get(entity_id).state == STATE_ALARM_DISARMED
async def test_trigger_with_zero_specific_trigger_time(hass, mqtt_mock):
async def test_trigger_with_zero_specific_trigger_time(
hass, mqtt_mock_entry_with_yaml_config
):
"""Test trigger method."""
assert await async_setup_component(
hass,
@ -748,7 +760,9 @@ async def test_trigger_with_zero_specific_trigger_time(hass, mqtt_mock):
assert hass.states.get(entity_id).state == STATE_ALARM_DISARMED
async def test_trigger_with_unused_zero_specific_trigger_time(hass, mqtt_mock):
async def test_trigger_with_unused_zero_specific_trigger_time(
hass, mqtt_mock_entry_with_yaml_config
):
"""Test disarm after trigger."""
assert await async_setup_component(
hass,
@ -788,7 +802,9 @@ async def test_trigger_with_unused_zero_specific_trigger_time(hass, mqtt_mock):
assert hass.states.get(entity_id).state == STATE_ALARM_DISARMED
async def test_trigger_with_specific_trigger_time(hass, mqtt_mock):
async def test_trigger_with_specific_trigger_time(
hass, mqtt_mock_entry_with_yaml_config
):
"""Test disarm after trigger."""
assert await async_setup_component(
hass,
@ -827,7 +843,9 @@ async def test_trigger_with_specific_trigger_time(hass, mqtt_mock):
assert hass.states.get(entity_id).state == STATE_ALARM_DISARMED
async def test_back_to_back_trigger_with_no_disarm_after_trigger(hass, mqtt_mock):
async def test_back_to_back_trigger_with_no_disarm_after_trigger(
hass, mqtt_mock_entry_with_yaml_config
):
"""Test no disarm after back to back trigger."""
assert await async_setup_component(
hass,
@ -886,7 +904,7 @@ async def test_back_to_back_trigger_with_no_disarm_after_trigger(hass, mqtt_mock
assert hass.states.get(entity_id).state == STATE_ALARM_ARMED_AWAY
async def test_disarm_while_pending_trigger(hass, mqtt_mock):
async def test_disarm_while_pending_trigger(hass, mqtt_mock_entry_with_yaml_config):
"""Test disarming while pending state."""
assert await async_setup_component(
hass,
@ -929,7 +947,9 @@ async def test_disarm_while_pending_trigger(hass, mqtt_mock):
assert hass.states.get(entity_id).state == STATE_ALARM_DISARMED
async def test_disarm_during_trigger_with_invalid_code(hass, mqtt_mock):
async def test_disarm_during_trigger_with_invalid_code(
hass, mqtt_mock_entry_with_yaml_config
):
"""Test disarming while code is invalid."""
assert await async_setup_component(
hass,
@ -973,7 +993,9 @@ async def test_disarm_during_trigger_with_invalid_code(hass, mqtt_mock):
assert hass.states.get(entity_id).state == STATE_ALARM_TRIGGERED
async def test_trigger_with_unused_specific_delay(hass, mqtt_mock):
async def test_trigger_with_unused_specific_delay(
hass, mqtt_mock_entry_with_yaml_config
):
"""Test trigger method and switch from pending to triggered."""
assert await async_setup_component(
hass,
@ -1022,7 +1044,7 @@ async def test_trigger_with_unused_specific_delay(hass, mqtt_mock):
assert state.state == STATE_ALARM_TRIGGERED
async def test_trigger_with_specific_delay(hass, mqtt_mock):
async def test_trigger_with_specific_delay(hass, mqtt_mock_entry_with_yaml_config):
"""Test trigger method and switch from pending to triggered."""
assert await async_setup_component(
hass,
@ -1071,7 +1093,7 @@ async def test_trigger_with_specific_delay(hass, mqtt_mock):
assert state.state == STATE_ALARM_TRIGGERED
async def test_trigger_with_pending_and_delay(hass, mqtt_mock):
async def test_trigger_with_pending_and_delay(hass, mqtt_mock_entry_with_yaml_config):
"""Test trigger method and switch from pending to triggered."""
assert await async_setup_component(
hass,
@ -1132,7 +1154,9 @@ async def test_trigger_with_pending_and_delay(hass, mqtt_mock):
assert state.state == STATE_ALARM_TRIGGERED
async def test_trigger_with_pending_and_specific_delay(hass, mqtt_mock):
async def test_trigger_with_pending_and_specific_delay(
hass, mqtt_mock_entry_with_yaml_config
):
"""Test trigger method and switch from pending to triggered."""
assert await async_setup_component(
hass,
@ -1194,7 +1218,7 @@ async def test_trigger_with_pending_and_specific_delay(hass, mqtt_mock):
assert state.state == STATE_ALARM_TRIGGERED
async def test_armed_home_with_specific_pending(hass, mqtt_mock):
async def test_armed_home_with_specific_pending(hass, mqtt_mock_entry_with_yaml_config):
"""Test arm home method."""
assert await async_setup_component(
hass,
@ -1230,7 +1254,7 @@ async def test_armed_home_with_specific_pending(hass, mqtt_mock):
assert hass.states.get(entity_id).state == STATE_ALARM_ARMED_HOME
async def test_armed_away_with_specific_pending(hass, mqtt_mock):
async def test_armed_away_with_specific_pending(hass, mqtt_mock_entry_with_yaml_config):
"""Test arm home method."""
assert await async_setup_component(
hass,
@ -1266,7 +1290,9 @@ async def test_armed_away_with_specific_pending(hass, mqtt_mock):
assert hass.states.get(entity_id).state == STATE_ALARM_ARMED_AWAY
async def test_armed_night_with_specific_pending(hass, mqtt_mock):
async def test_armed_night_with_specific_pending(
hass, mqtt_mock_entry_with_yaml_config
):
"""Test arm home method."""
assert await async_setup_component(
hass,
@ -1302,7 +1328,7 @@ async def test_armed_night_with_specific_pending(hass, mqtt_mock):
assert hass.states.get(entity_id).state == STATE_ALARM_ARMED_NIGHT
async def test_trigger_with_specific_pending(hass, mqtt_mock):
async def test_trigger_with_specific_pending(hass, mqtt_mock_entry_with_yaml_config):
"""Test arm home method."""
assert await async_setup_component(
hass,
@ -1350,7 +1376,7 @@ async def test_trigger_with_specific_pending(hass, mqtt_mock):
assert hass.states.get(entity_id).state == STATE_ALARM_DISARMED
async def test_arm_away_after_disabled_disarmed(hass, mqtt_mock):
async def test_arm_away_after_disabled_disarmed(hass, mqtt_mock_entry_with_yaml_config):
"""Test pending state with and without zero trigger time."""
assert await async_setup_component(
hass,
@ -1417,7 +1443,7 @@ async def test_arm_away_after_disabled_disarmed(hass, mqtt_mock):
assert state.state == STATE_ALARM_TRIGGERED
async def test_disarm_with_template_code(hass, mqtt_mock):
async def test_disarm_with_template_code(hass, mqtt_mock_entry_with_yaml_config):
"""Attempt to disarm with a valid or invalid template-based code."""
assert await async_setup_component(
hass,
@ -1459,7 +1485,7 @@ async def test_disarm_with_template_code(hass, mqtt_mock):
assert state.state == STATE_ALARM_DISARMED
async def test_arm_home_via_command_topic(hass, mqtt_mock):
async def test_arm_home_via_command_topic(hass, mqtt_mock_entry_with_yaml_config):
"""Test arming home via command topic."""
assert await async_setup_component(
hass,
@ -1498,7 +1524,7 @@ async def test_arm_home_via_command_topic(hass, mqtt_mock):
assert hass.states.get(entity_id).state == STATE_ALARM_ARMED_HOME
async def test_arm_away_via_command_topic(hass, mqtt_mock):
async def test_arm_away_via_command_topic(hass, mqtt_mock_entry_with_yaml_config):
"""Test arming away via command topic."""
assert await async_setup_component(
hass,
@ -1537,7 +1563,7 @@ async def test_arm_away_via_command_topic(hass, mqtt_mock):
assert hass.states.get(entity_id).state == STATE_ALARM_ARMED_AWAY
async def test_arm_night_via_command_topic(hass, mqtt_mock):
async def test_arm_night_via_command_topic(hass, mqtt_mock_entry_with_yaml_config):
"""Test arming night via command topic."""
assert await async_setup_component(
hass,
@ -1576,7 +1602,7 @@ async def test_arm_night_via_command_topic(hass, mqtt_mock):
assert hass.states.get(entity_id).state == STATE_ALARM_ARMED_NIGHT
async def test_disarm_pending_via_command_topic(hass, mqtt_mock):
async def test_disarm_pending_via_command_topic(hass, mqtt_mock_entry_with_yaml_config):
"""Test disarming pending alarm via command topic."""
assert await async_setup_component(
hass,
@ -1610,7 +1636,9 @@ async def test_disarm_pending_via_command_topic(hass, mqtt_mock):
assert hass.states.get(entity_id).state == STATE_ALARM_DISARMED
async def test_state_changes_are_published_to_mqtt(hass, mqtt_mock):
async def test_state_changes_are_published_to_mqtt(
hass, mqtt_mock_entry_with_yaml_config
):
"""Test publishing of MQTT messages when state changes."""
assert await async_setup_component(
hass,
@ -1630,6 +1658,7 @@ async def test_state_changes_are_published_to_mqtt(hass, mqtt_mock):
# Component should send disarmed alarm state on startup
await hass.async_block_till_done()
mqtt_mock = await mqtt_mock_entry_with_yaml_config()
mqtt_mock.async_publish.assert_called_once_with(
"alarm/state", STATE_ALARM_DISARMED, 0, True
)

View File

@ -112,9 +112,9 @@ DEFAULT_CONFIG_REMOTE_CODE_TEXT = {
}
async def test_fail_setup_without_state_topic(hass, mqtt_mock):
async def test_fail_setup_without_state_topic(hass, mqtt_mock_entry_no_yaml_config):
"""Test for failing with no state topic."""
with assert_setup_component(0) as config:
with assert_setup_component(0, alarm_control_panel.DOMAIN) as config:
assert await async_setup_component(
hass,
alarm_control_panel.DOMAIN,
@ -125,12 +125,14 @@ async def test_fail_setup_without_state_topic(hass, mqtt_mock):
}
},
)
await hass.async_block_till_done()
await mqtt_mock_entry_no_yaml_config()
assert not config[alarm_control_panel.DOMAIN]
async def test_fail_setup_without_command_topic(hass, mqtt_mock):
async def test_fail_setup_without_command_topic(hass, mqtt_mock_entry_no_yaml_config):
"""Test failing with no command topic."""
with assert_setup_component(0):
with assert_setup_component(0, alarm_control_panel.DOMAIN) as config:
assert await async_setup_component(
hass,
alarm_control_panel.DOMAIN,
@ -141,9 +143,12 @@ async def test_fail_setup_without_command_topic(hass, mqtt_mock):
}
},
)
await hass.async_block_till_done()
await mqtt_mock_entry_no_yaml_config()
assert not config[alarm_control_panel.DOMAIN]
async def test_update_state_via_state_topic(hass, mqtt_mock):
async def test_update_state_via_state_topic(hass, mqtt_mock_entry_with_yaml_config):
"""Test updating with via state topic."""
assert await async_setup_component(
hass,
@ -151,6 +156,7 @@ async def test_update_state_via_state_topic(hass, mqtt_mock):
DEFAULT_CONFIG,
)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
entity_id = "alarm_control_panel.test"
@ -172,7 +178,9 @@ async def test_update_state_via_state_topic(hass, mqtt_mock):
assert hass.states.get(entity_id).state == state
async def test_ignore_update_state_if_unknown_via_state_topic(hass, mqtt_mock):
async def test_ignore_update_state_if_unknown_via_state_topic(
hass, mqtt_mock_entry_with_yaml_config
):
"""Test ignoring updates via state topic."""
assert await async_setup_component(
hass,
@ -180,6 +188,7 @@ async def test_ignore_update_state_if_unknown_via_state_topic(hass, mqtt_mock):
DEFAULT_CONFIG,
)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
entity_id = "alarm_control_panel.test"
@ -201,7 +210,9 @@ async def test_ignore_update_state_if_unknown_via_state_topic(hass, mqtt_mock):
(SERVICE_ALARM_TRIGGER, "TRIGGER"),
],
)
async def test_publish_mqtt_no_code(hass, mqtt_mock, service, payload):
async def test_publish_mqtt_no_code(
hass, mqtt_mock_entry_with_yaml_config, service, payload
):
"""Test publishing of MQTT messages when no code is configured."""
assert await async_setup_component(
hass,
@ -209,6 +220,7 @@ async def test_publish_mqtt_no_code(hass, mqtt_mock, service, payload):
DEFAULT_CONFIG,
)
await hass.async_block_till_done()
mqtt_mock = await mqtt_mock_entry_with_yaml_config()
await hass.services.async_call(
alarm_control_panel.DOMAIN,
@ -232,7 +244,9 @@ async def test_publish_mqtt_no_code(hass, mqtt_mock, service, payload):
(SERVICE_ALARM_TRIGGER, "TRIGGER"),
],
)
async def test_publish_mqtt_with_code(hass, mqtt_mock, service, payload):
async def test_publish_mqtt_with_code(
hass, mqtt_mock_entry_with_yaml_config, service, payload
):
"""Test publishing of MQTT messages when code is configured."""
assert await async_setup_component(
hass,
@ -240,6 +254,7 @@ async def test_publish_mqtt_with_code(hass, mqtt_mock, service, payload):
DEFAULT_CONFIG_CODE,
)
await hass.async_block_till_done()
mqtt_mock = await mqtt_mock_entry_with_yaml_config()
call_count = mqtt_mock.async_publish.call_count
# No code provided, should not publish
@ -282,7 +297,9 @@ async def test_publish_mqtt_with_code(hass, mqtt_mock, service, payload):
(SERVICE_ALARM_TRIGGER, "TRIGGER"),
],
)
async def test_publish_mqtt_with_remote_code(hass, mqtt_mock, service, payload):
async def test_publish_mqtt_with_remote_code(
hass, mqtt_mock_entry_with_yaml_config, service, payload
):
"""Test publishing of MQTT messages when remode code is configured."""
assert await async_setup_component(
hass,
@ -290,6 +307,7 @@ async def test_publish_mqtt_with_remote_code(hass, mqtt_mock, service, payload):
DEFAULT_CONFIG_REMOTE_CODE,
)
await hass.async_block_till_done()
mqtt_mock = await mqtt_mock_entry_with_yaml_config()
call_count = mqtt_mock.async_publish.call_count
# No code provided, should not publish
@ -323,7 +341,9 @@ async def test_publish_mqtt_with_remote_code(hass, mqtt_mock, service, payload):
(SERVICE_ALARM_TRIGGER, "TRIGGER"),
],
)
async def test_publish_mqtt_with_remote_code_text(hass, mqtt_mock, service, payload):
async def test_publish_mqtt_with_remote_code_text(
hass, mqtt_mock_entry_with_yaml_config, service, payload
):
"""Test publishing of MQTT messages when remote text code is configured."""
assert await async_setup_component(
hass,
@ -331,6 +351,7 @@ async def test_publish_mqtt_with_remote_code_text(hass, mqtt_mock, service, payl
DEFAULT_CONFIG_REMOTE_CODE_TEXT,
)
await hass.async_block_till_done()
mqtt_mock = await mqtt_mock_entry_with_yaml_config()
call_count = mqtt_mock.async_publish.call_count
# No code provided, should not publish
@ -365,7 +386,7 @@ async def test_publish_mqtt_with_remote_code_text(hass, mqtt_mock, service, payl
],
)
async def test_publish_mqtt_with_code_required_false(
hass, mqtt_mock, service, payload, disable_code
hass, mqtt_mock_entry_with_yaml_config, service, payload, disable_code
):
"""Test publishing of MQTT messages when code is configured.
@ -380,6 +401,7 @@ async def test_publish_mqtt_with_code_required_false(
config,
)
await hass.async_block_till_done()
mqtt_mock = await mqtt_mock_entry_with_yaml_config()
# No code provided, should publish
await hass.services.async_call(
@ -412,7 +434,9 @@ async def test_publish_mqtt_with_code_required_false(
mqtt_mock.reset_mock()
async def test_disarm_publishes_mqtt_with_template(hass, mqtt_mock):
async def test_disarm_publishes_mqtt_with_template(
hass, mqtt_mock_entry_with_yaml_config
):
"""Test publishing of MQTT messages while disarmed.
When command_template set to output json
@ -428,6 +452,7 @@ async def test_disarm_publishes_mqtt_with_template(hass, mqtt_mock):
config,
)
await hass.async_block_till_done()
mqtt_mock = await mqtt_mock_entry_with_yaml_config()
await common.async_alarm_disarm(hass, "0123")
mqtt_mock.async_publish.assert_called_once_with(
@ -435,7 +460,9 @@ async def test_disarm_publishes_mqtt_with_template(hass, mqtt_mock):
)
async def test_update_state_via_state_topic_template(hass, mqtt_mock):
async def test_update_state_via_state_topic_template(
hass, mqtt_mock_entry_with_yaml_config
):
"""Test updating with template_value via state topic."""
assert await async_setup_component(
hass,
@ -456,6 +483,7 @@ async def test_update_state_via_state_topic_template(hass, mqtt_mock):
},
)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("alarm_control_panel.test")
assert state.state == STATE_UNKNOWN
@ -466,13 +494,14 @@ async def test_update_state_via_state_topic_template(hass, mqtt_mock):
assert state.state == STATE_ALARM_ARMED_AWAY
async def test_attributes_code_number(hass, mqtt_mock):
async def test_attributes_code_number(hass, mqtt_mock_entry_with_yaml_config):
"""Test attributes which are not supported by the vacuum."""
config = copy.deepcopy(DEFAULT_CONFIG)
config[alarm_control_panel.DOMAIN]["code"] = CODE_NUMBER
assert await async_setup_component(hass, alarm_control_panel.DOMAIN, config)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("alarm_control_panel.test")
assert (
@ -481,13 +510,14 @@ async def test_attributes_code_number(hass, mqtt_mock):
)
async def test_attributes_remote_code_number(hass, mqtt_mock):
async def test_attributes_remote_code_number(hass, mqtt_mock_entry_with_yaml_config):
"""Test attributes which are not supported by the vacuum."""
config = copy.deepcopy(DEFAULT_CONFIG_REMOTE_CODE)
config[alarm_control_panel.DOMAIN]["code"] = "REMOTE_CODE"
assert await async_setup_component(hass, alarm_control_panel.DOMAIN, config)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("alarm_control_panel.test")
assert (
@ -496,13 +526,14 @@ async def test_attributes_remote_code_number(hass, mqtt_mock):
)
async def test_attributes_code_text(hass, mqtt_mock):
async def test_attributes_code_text(hass, mqtt_mock_entry_with_yaml_config):
"""Test attributes which are not supported by the vacuum."""
config = copy.deepcopy(DEFAULT_CONFIG)
config[alarm_control_panel.DOMAIN]["code"] = CODE_TEXT
assert await async_setup_component(hass, alarm_control_panel.DOMAIN, config)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("alarm_control_panel.test")
assert (
@ -511,81 +542,121 @@ async def test_attributes_code_text(hass, mqtt_mock):
)
async def test_availability_when_connection_lost(hass, mqtt_mock):
async def test_availability_when_connection_lost(
hass, mqtt_mock_entry_with_yaml_config
):
"""Test availability after MQTT disconnection."""
await help_test_availability_when_connection_lost(
hass, mqtt_mock, alarm_control_panel.DOMAIN, DEFAULT_CONFIG_CODE
hass,
mqtt_mock_entry_with_yaml_config,
alarm_control_panel.DOMAIN,
DEFAULT_CONFIG_CODE,
)
async def test_availability_without_topic(hass, mqtt_mock):
async def test_availability_without_topic(hass, mqtt_mock_entry_with_yaml_config):
"""Test availability without defined availability topic."""
await help_test_availability_without_topic(
hass, mqtt_mock, alarm_control_panel.DOMAIN, DEFAULT_CONFIG_CODE
hass,
mqtt_mock_entry_with_yaml_config,
alarm_control_panel.DOMAIN,
DEFAULT_CONFIG_CODE,
)
async def test_default_availability_payload(hass, mqtt_mock):
async def test_default_availability_payload(hass, mqtt_mock_entry_with_yaml_config):
"""Test availability by default payload with defined topic."""
await help_test_default_availability_payload(
hass, mqtt_mock, alarm_control_panel.DOMAIN, DEFAULT_CONFIG_CODE
hass,
mqtt_mock_entry_with_yaml_config,
alarm_control_panel.DOMAIN,
DEFAULT_CONFIG_CODE,
)
async def test_custom_availability_payload(hass, mqtt_mock):
async def test_custom_availability_payload(hass, mqtt_mock_entry_with_yaml_config):
"""Test availability by custom payload with defined topic."""
await help_test_custom_availability_payload(
hass, mqtt_mock, alarm_control_panel.DOMAIN, DEFAULT_CONFIG_CODE
hass,
mqtt_mock_entry_with_yaml_config,
alarm_control_panel.DOMAIN,
DEFAULT_CONFIG_CODE,
)
async def test_setting_attribute_via_mqtt_json_message(hass, mqtt_mock):
async def test_setting_attribute_via_mqtt_json_message(
hass, mqtt_mock_entry_with_yaml_config
):
"""Test the setting of attribute via MQTT with JSON payload."""
await help_test_setting_attribute_via_mqtt_json_message(
hass, mqtt_mock, alarm_control_panel.DOMAIN, DEFAULT_CONFIG
hass,
mqtt_mock_entry_with_yaml_config,
alarm_control_panel.DOMAIN,
DEFAULT_CONFIG,
)
async def test_setting_blocked_attribute_via_mqtt_json_message(hass, mqtt_mock):
async def test_setting_blocked_attribute_via_mqtt_json_message(
hass, mqtt_mock_entry_no_yaml_config
):
"""Test the setting of attribute via MQTT with JSON payload."""
await help_test_setting_blocked_attribute_via_mqtt_json_message(
hass,
mqtt_mock,
mqtt_mock_entry_no_yaml_config,
alarm_control_panel.DOMAIN,
DEFAULT_CONFIG,
MQTT_ALARM_ATTRIBUTES_BLOCKED,
)
async def test_setting_attribute_with_template(hass, mqtt_mock):
async def test_setting_attribute_with_template(hass, mqtt_mock_entry_with_yaml_config):
"""Test the setting of attribute via MQTT with JSON payload."""
await help_test_setting_attribute_with_template(
hass, mqtt_mock, alarm_control_panel.DOMAIN, DEFAULT_CONFIG
hass,
mqtt_mock_entry_with_yaml_config,
alarm_control_panel.DOMAIN,
DEFAULT_CONFIG,
)
async def test_update_with_json_attrs_not_dict(hass, mqtt_mock, caplog):
async def test_update_with_json_attrs_not_dict(
hass, mqtt_mock_entry_with_yaml_config, caplog
):
"""Test attributes get extracted from a JSON result."""
await help_test_update_with_json_attrs_not_dict(
hass, mqtt_mock, caplog, alarm_control_panel.DOMAIN, DEFAULT_CONFIG
hass,
mqtt_mock_entry_with_yaml_config,
caplog,
alarm_control_panel.DOMAIN,
DEFAULT_CONFIG,
)
async def test_update_with_json_attrs_bad_JSON(hass, mqtt_mock, caplog):
async def test_update_with_json_attrs_bad_JSON(
hass, mqtt_mock_entry_with_yaml_config, caplog
):
"""Test attributes get extracted from a JSON result."""
await help_test_update_with_json_attrs_bad_JSON(
hass, mqtt_mock, caplog, alarm_control_panel.DOMAIN, DEFAULT_CONFIG
hass,
mqtt_mock_entry_with_yaml_config,
caplog,
alarm_control_panel.DOMAIN,
DEFAULT_CONFIG,
)
async def test_discovery_update_attr(hass, mqtt_mock, caplog):
async def test_discovery_update_attr(hass, mqtt_mock_entry_no_yaml_config, caplog):
"""Test update of discovered MQTTAttributes."""
await help_test_discovery_update_attr(
hass, mqtt_mock, caplog, alarm_control_panel.DOMAIN, DEFAULT_CONFIG
hass,
mqtt_mock_entry_no_yaml_config,
caplog,
alarm_control_panel.DOMAIN,
DEFAULT_CONFIG,
)
async def test_unique_id(hass, mqtt_mock):
async def test_unique_id(hass, mqtt_mock_entry_with_yaml_config):
"""Test unique id option only creates one alarm per unique_id."""
config = {
alarm_control_panel.DOMAIN: [
@ -605,18 +676,22 @@ async def test_unique_id(hass, mqtt_mock):
},
]
}
await help_test_unique_id(hass, mqtt_mock, alarm_control_panel.DOMAIN, config)
async def test_discovery_removal_alarm(hass, mqtt_mock, caplog):
"""Test removal of discovered alarm_control_panel."""
data = json.dumps(DEFAULT_CONFIG[alarm_control_panel.DOMAIN])
await help_test_discovery_removal(
hass, mqtt_mock, caplog, alarm_control_panel.DOMAIN, data
await help_test_unique_id(
hass, mqtt_mock_entry_with_yaml_config, alarm_control_panel.DOMAIN, config
)
async def test_discovery_update_alarm_topic_and_template(hass, mqtt_mock, caplog):
async def test_discovery_removal_alarm(hass, mqtt_mock_entry_no_yaml_config, caplog):
"""Test removal of discovered alarm_control_panel."""
data = json.dumps(DEFAULT_CONFIG[alarm_control_panel.DOMAIN])
await help_test_discovery_removal(
hass, mqtt_mock_entry_no_yaml_config, caplog, alarm_control_panel.DOMAIN, data
)
async def test_discovery_update_alarm_topic_and_template(
hass, mqtt_mock_entry_no_yaml_config, caplog
):
"""Test update of discovered alarm_control_panel."""
config1 = copy.deepcopy(DEFAULT_CONFIG[alarm_control_panel.DOMAIN])
config2 = copy.deepcopy(DEFAULT_CONFIG[alarm_control_panel.DOMAIN])
@ -639,7 +714,7 @@ async def test_discovery_update_alarm_topic_and_template(hass, mqtt_mock, caplog
await help_test_discovery_update(
hass,
mqtt_mock,
mqtt_mock_entry_no_yaml_config,
caplog,
alarm_control_panel.DOMAIN,
config1,
@ -649,7 +724,9 @@ async def test_discovery_update_alarm_topic_and_template(hass, mqtt_mock, caplog
)
async def test_discovery_update_alarm_template(hass, mqtt_mock, caplog):
async def test_discovery_update_alarm_template(
hass, mqtt_mock_entry_no_yaml_config, caplog
):
"""Test update of discovered alarm_control_panel."""
config1 = copy.deepcopy(DEFAULT_CONFIG[alarm_control_panel.DOMAIN])
config2 = copy.deepcopy(DEFAULT_CONFIG[alarm_control_panel.DOMAIN])
@ -670,7 +747,7 @@ async def test_discovery_update_alarm_template(hass, mqtt_mock, caplog):
await help_test_discovery_update(
hass,
mqtt_mock,
mqtt_mock_entry_no_yaml_config,
caplog,
alarm_control_panel.DOMAIN,
config1,
@ -680,7 +757,9 @@ async def test_discovery_update_alarm_template(hass, mqtt_mock, caplog):
)
async def test_discovery_update_unchanged_alarm(hass, mqtt_mock, caplog):
async def test_discovery_update_unchanged_alarm(
hass, mqtt_mock_entry_no_yaml_config, caplog
):
"""Test update of discovered alarm_control_panel."""
config1 = copy.deepcopy(DEFAULT_CONFIG[alarm_control_panel.DOMAIN])
config1["name"] = "Beer"
@ -690,12 +769,17 @@ async def test_discovery_update_unchanged_alarm(hass, mqtt_mock, caplog):
"homeassistant.components.mqtt.alarm_control_panel.MqttAlarm.discovery_update"
) as discovery_update:
await help_test_discovery_update_unchanged(
hass, mqtt_mock, caplog, alarm_control_panel.DOMAIN, data1, discovery_update
hass,
mqtt_mock_entry_no_yaml_config,
caplog,
alarm_control_panel.DOMAIN,
data1,
discovery_update,
)
@pytest.mark.no_fail_on_log_exception
async def test_discovery_broken(hass, mqtt_mock, caplog):
async def test_discovery_broken(hass, mqtt_mock_entry_no_yaml_config, caplog):
"""Test handling of bad discovery message."""
data1 = '{ "name": "Beer" }'
data2 = (
@ -704,7 +788,12 @@ async def test_discovery_broken(hass, mqtt_mock, caplog):
' "command_topic": "test_topic" }'
)
await help_test_discovery_broken(
hass, mqtt_mock, caplog, alarm_control_panel.DOMAIN, data1, data2
hass,
mqtt_mock_entry_no_yaml_config,
caplog,
alarm_control_panel.DOMAIN,
data1,
data2,
)
@ -715,11 +804,13 @@ async def test_discovery_broken(hass, mqtt_mock, caplog):
("state_topic", "disarmed"),
],
)
async def test_encoding_subscribable_topics(hass, mqtt_mock, caplog, topic, value):
async def test_encoding_subscribable_topics(
hass, mqtt_mock_entry_with_yaml_config, caplog, topic, value
):
"""Test handling of incoming encoded payload."""
await help_test_encoding_subscribable_topics(
hass,
mqtt_mock,
mqtt_mock_entry_with_yaml_config,
caplog,
alarm_control_panel.DOMAIN,
DEFAULT_CONFIG[alarm_control_panel.DOMAIN],
@ -728,53 +819,62 @@ async def test_encoding_subscribable_topics(hass, mqtt_mock, caplog, topic, valu
)
async def test_entity_device_info_with_connection(hass, mqtt_mock):
async def test_entity_device_info_with_connection(hass, mqtt_mock_entry_no_yaml_config):
"""Test MQTT alarm control panel device registry integration."""
await help_test_entity_device_info_with_connection(
hass, mqtt_mock, alarm_control_panel.DOMAIN, DEFAULT_CONFIG
hass,
mqtt_mock_entry_no_yaml_config,
alarm_control_panel.DOMAIN,
DEFAULT_CONFIG,
)
async def test_entity_device_info_with_identifier(hass, mqtt_mock):
async def test_entity_device_info_with_identifier(hass, mqtt_mock_entry_no_yaml_config):
"""Test MQTT alarm control panel device registry integration."""
await help_test_entity_device_info_with_identifier(
hass, mqtt_mock, alarm_control_panel.DOMAIN, DEFAULT_CONFIG
hass,
mqtt_mock_entry_no_yaml_config,
alarm_control_panel.DOMAIN,
DEFAULT_CONFIG,
)
async def test_entity_device_info_update(hass, mqtt_mock):
async def test_entity_device_info_update(hass, mqtt_mock_entry_no_yaml_config):
"""Test device registry update."""
await help_test_entity_device_info_update(
hass, mqtt_mock, alarm_control_panel.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_no_yaml_config, alarm_control_panel.DOMAIN, DEFAULT_CONFIG
)
async def test_entity_device_info_remove(hass, mqtt_mock):
async def test_entity_device_info_remove(hass, mqtt_mock_entry_no_yaml_config):
"""Test device registry remove."""
await help_test_entity_device_info_remove(
hass, mqtt_mock, alarm_control_panel.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_no_yaml_config, alarm_control_panel.DOMAIN, DEFAULT_CONFIG
)
async def test_entity_id_update_subscriptions(hass, mqtt_mock):
async def test_entity_id_update_subscriptions(hass, mqtt_mock_entry_with_yaml_config):
"""Test MQTT subscriptions are managed when entity_id is updated."""
await help_test_entity_id_update_subscriptions(
hass, mqtt_mock, alarm_control_panel.DOMAIN, DEFAULT_CONFIG
hass,
mqtt_mock_entry_with_yaml_config,
alarm_control_panel.DOMAIN,
DEFAULT_CONFIG,
)
async def test_entity_id_update_discovery_update(hass, mqtt_mock):
async def test_entity_id_update_discovery_update(hass, mqtt_mock_entry_no_yaml_config):
"""Test MQTT discovery update when entity_id is updated."""
await help_test_entity_id_update_discovery_update(
hass, mqtt_mock, alarm_control_panel.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_no_yaml_config, alarm_control_panel.DOMAIN, DEFAULT_CONFIG
)
async def test_entity_debug_info_message(hass, mqtt_mock):
async def test_entity_debug_info_message(hass, mqtt_mock_entry_no_yaml_config):
"""Test MQTT debug info."""
await help_test_entity_debug_info_message(
hass,
mqtt_mock,
mqtt_mock_entry_no_yaml_config,
alarm_control_panel.DOMAIN,
DEFAULT_CONFIG,
alarm_control_panel.SERVICE_ALARM_DISARM,
@ -807,7 +907,7 @@ async def test_entity_debug_info_message(hass, mqtt_mock):
)
async def test_publishing_with_custom_encoding(
hass,
mqtt_mock,
mqtt_mock_entry_with_yaml_config,
caplog,
service,
topic,
@ -823,7 +923,7 @@ async def test_publishing_with_custom_encoding(
await help_test_publishing_with_custom_encoding(
hass,
mqtt_mock,
mqtt_mock_entry_with_yaml_config,
caplog,
domain,
config,
@ -837,11 +937,13 @@ async def test_publishing_with_custom_encoding(
)
async def test_reloadable(hass, mqtt_mock, caplog, tmp_path):
async def test_reloadable(hass, mqtt_mock_entry_with_yaml_config, caplog, tmp_path):
"""Test reloading the MQTT platform."""
domain = alarm_control_panel.DOMAIN
config = DEFAULT_CONFIG[domain]
await help_test_reloadable(hass, mqtt_mock, caplog, tmp_path, domain, config)
await help_test_reloadable(
hass, mqtt_mock_entry_with_yaml_config, caplog, tmp_path, domain, config
)
async def test_reloadable_late(hass, mqtt_client_mock, caplog, tmp_path):

View File

@ -62,7 +62,9 @@ DEFAULT_CONFIG = {
}
async def test_setting_sensor_value_expires_availability_topic(hass, mqtt_mock, caplog):
async def test_setting_sensor_value_expires_availability_topic(
hass, mqtt_mock_entry_with_yaml_config, caplog
):
"""Test the expiration of the value."""
assert await async_setup_component(
hass,
@ -79,6 +81,7 @@ async def test_setting_sensor_value_expires_availability_topic(hass, mqtt_mock,
},
)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("binary_sensor.test")
assert state.state == STATE_UNAVAILABLE
@ -89,10 +92,12 @@ async def test_setting_sensor_value_expires_availability_topic(hass, mqtt_mock,
state = hass.states.get("binary_sensor.test")
assert state.state == STATE_UNAVAILABLE
await expires_helper(hass, mqtt_mock, caplog)
await expires_helper(hass)
async def test_setting_sensor_value_expires(hass, mqtt_mock, caplog):
async def test_setting_sensor_value_expires(
hass, mqtt_mock_entry_with_yaml_config, caplog
):
"""Test the expiration of the value."""
assert await async_setup_component(
hass,
@ -108,15 +113,16 @@ async def test_setting_sensor_value_expires(hass, mqtt_mock, caplog):
},
)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
# State should be unavailable since expire_after is defined and > 0
state = hass.states.get("binary_sensor.test")
assert state.state == STATE_UNAVAILABLE
await expires_helper(hass, mqtt_mock, caplog)
await expires_helper(hass)
async def expires_helper(hass, mqtt_mock, caplog):
async def expires_helper(hass):
"""Run the basic expiry code."""
realnow = dt_util.utcnow()
now = datetime(realnow.year + 1, 1, 1, 1, tzinfo=dt_util.UTC)
@ -168,9 +174,10 @@ async def expires_helper(hass, mqtt_mock, caplog):
async def test_expiration_on_discovery_and_discovery_update_of_binary_sensor(
hass, mqtt_mock, caplog
hass, mqtt_mock_entry_no_yaml_config, caplog
):
"""Test that binary_sensor with expire_after set behaves correctly on discovery and discovery update."""
await mqtt_mock_entry_no_yaml_config()
config = {
"name": "Test",
"state_topic": "test-topic",
@ -247,7 +254,9 @@ async def test_expiration_on_discovery_and_discovery_update_of_binary_sensor(
assert state.state == STATE_UNAVAILABLE
async def test_setting_sensor_value_via_mqtt_message(hass, mqtt_mock):
async def test_setting_sensor_value_via_mqtt_message(
hass, mqtt_mock_entry_with_yaml_config
):
"""Test the setting of the value via MQTT."""
assert await async_setup_component(
hass,
@ -263,6 +272,7 @@ async def test_setting_sensor_value_via_mqtt_message(hass, mqtt_mock):
},
)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("binary_sensor.test")
@ -281,7 +291,9 @@ async def test_setting_sensor_value_via_mqtt_message(hass, mqtt_mock):
assert state.state == STATE_UNKNOWN
async def test_invalid_sensor_value_via_mqtt_message(hass, mqtt_mock, caplog):
async def test_invalid_sensor_value_via_mqtt_message(
hass, mqtt_mock_entry_with_yaml_config, caplog
):
"""Test the setting of the value via MQTT."""
assert await async_setup_component(
hass,
@ -297,6 +309,7 @@ async def test_invalid_sensor_value_via_mqtt_message(hass, mqtt_mock, caplog):
},
)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("binary_sensor.test")
@ -319,7 +332,9 @@ async def test_invalid_sensor_value_via_mqtt_message(hass, mqtt_mock, caplog):
assert "No matching payload found for entity" in caplog.text
async def test_setting_sensor_value_via_mqtt_message_and_template(hass, mqtt_mock):
async def test_setting_sensor_value_via_mqtt_message_and_template(
hass, mqtt_mock_entry_with_yaml_config
):
"""Test the setting of the value via MQTT."""
assert await async_setup_component(
hass,
@ -337,6 +352,7 @@ async def test_setting_sensor_value_via_mqtt_message_and_template(hass, mqtt_moc
},
)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("binary_sensor.test")
assert state.state == STATE_UNKNOWN
@ -351,7 +367,7 @@ async def test_setting_sensor_value_via_mqtt_message_and_template(hass, mqtt_moc
async def test_setting_sensor_value_via_mqtt_message_and_template2(
hass, mqtt_mock, caplog
hass, mqtt_mock_entry_with_yaml_config, caplog
):
"""Test the setting of the value via MQTT."""
assert await async_setup_component(
@ -369,6 +385,7 @@ async def test_setting_sensor_value_via_mqtt_message_and_template2(
},
)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("binary_sensor.test")
assert state.state == STATE_UNKNOWN
@ -388,7 +405,7 @@ async def test_setting_sensor_value_via_mqtt_message_and_template2(
async def test_setting_sensor_value_via_mqtt_message_and_template_and_raw_state_encoding(
hass, mqtt_mock, caplog
hass, mqtt_mock_entry_with_yaml_config, caplog
):
"""Test processing a raw value via MQTT."""
assert await async_setup_component(
@ -407,6 +424,7 @@ async def test_setting_sensor_value_via_mqtt_message_and_template_and_raw_state_
},
)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("binary_sensor.test")
assert state.state == STATE_UNKNOWN
@ -421,7 +439,7 @@ async def test_setting_sensor_value_via_mqtt_message_and_template_and_raw_state_
async def test_setting_sensor_value_via_mqtt_message_empty_template(
hass, mqtt_mock, caplog
hass, mqtt_mock_entry_with_yaml_config, caplog
):
"""Test the setting of the value via MQTT."""
assert await async_setup_component(
@ -439,6 +457,7 @@ async def test_setting_sensor_value_via_mqtt_message_empty_template(
},
)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("binary_sensor.test")
assert state.state == STATE_UNKNOWN
@ -453,7 +472,7 @@ async def test_setting_sensor_value_via_mqtt_message_empty_template(
assert state.state == STATE_ON
async def test_valid_device_class(hass, mqtt_mock):
async def test_valid_device_class(hass, mqtt_mock_entry_with_yaml_config):
"""Test the setting of a valid sensor class."""
assert await async_setup_component(
hass,
@ -468,12 +487,13 @@ async def test_valid_device_class(hass, mqtt_mock):
},
)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("binary_sensor.test")
assert state.attributes.get("device_class") == "motion"
async def test_invalid_device_class(hass, mqtt_mock):
async def test_invalid_device_class(hass, mqtt_mock_entry_no_yaml_config):
"""Test the setting of an invalid sensor class."""
assert await async_setup_component(
hass,
@ -488,40 +508,43 @@ async def test_invalid_device_class(hass, mqtt_mock):
},
)
await hass.async_block_till_done()
await mqtt_mock_entry_no_yaml_config()
state = hass.states.get("binary_sensor.test")
assert state is None
async def test_availability_when_connection_lost(hass, mqtt_mock):
async def test_availability_when_connection_lost(
hass, mqtt_mock_entry_with_yaml_config
):
"""Test availability after MQTT disconnection."""
await help_test_availability_when_connection_lost(
hass, mqtt_mock, binary_sensor.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_with_yaml_config, binary_sensor.DOMAIN, DEFAULT_CONFIG
)
async def test_availability_without_topic(hass, mqtt_mock):
async def test_availability_without_topic(hass, mqtt_mock_entry_with_yaml_config):
"""Test availability without defined availability topic."""
await help_test_availability_without_topic(
hass, mqtt_mock, binary_sensor.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_with_yaml_config, binary_sensor.DOMAIN, DEFAULT_CONFIG
)
async def test_default_availability_payload(hass, mqtt_mock):
async def test_default_availability_payload(hass, mqtt_mock_entry_with_yaml_config):
"""Test availability by default payload with defined topic."""
await help_test_default_availability_payload(
hass, mqtt_mock, binary_sensor.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_with_yaml_config, binary_sensor.DOMAIN, DEFAULT_CONFIG
)
async def test_custom_availability_payload(hass, mqtt_mock):
async def test_custom_availability_payload(hass, mqtt_mock_entry_with_yaml_config):
"""Test availability by custom payload with defined topic."""
await help_test_custom_availability_payload(
hass, mqtt_mock, binary_sensor.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_with_yaml_config, binary_sensor.DOMAIN, DEFAULT_CONFIG
)
async def test_force_update_disabled(hass, mqtt_mock):
async def test_force_update_disabled(hass, mqtt_mock_entry_with_yaml_config):
"""Test force update option."""
assert await async_setup_component(
hass,
@ -537,6 +560,7 @@ async def test_force_update_disabled(hass, mqtt_mock):
},
)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
events = []
@ -556,7 +580,7 @@ async def test_force_update_disabled(hass, mqtt_mock):
assert len(events) == 1
async def test_force_update_enabled(hass, mqtt_mock):
async def test_force_update_enabled(hass, mqtt_mock_entry_with_yaml_config):
"""Test force update option."""
assert await async_setup_component(
hass,
@ -573,6 +597,7 @@ async def test_force_update_enabled(hass, mqtt_mock):
},
)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
events = []
@ -592,7 +617,7 @@ async def test_force_update_enabled(hass, mqtt_mock):
assert len(events) == 2
async def test_off_delay(hass, mqtt_mock):
async def test_off_delay(hass, mqtt_mock_entry_with_yaml_config):
"""Test off_delay option."""
assert await async_setup_component(
hass,
@ -610,6 +635,7 @@ async def test_off_delay(hass, mqtt_mock):
},
)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
events = []
@ -639,42 +665,60 @@ async def test_off_delay(hass, mqtt_mock):
assert len(events) == 3
async def test_setting_attribute_via_mqtt_json_message(hass, mqtt_mock):
async def test_setting_attribute_via_mqtt_json_message(
hass, mqtt_mock_entry_with_yaml_config
):
"""Test the setting of attribute via MQTT with JSON payload."""
await help_test_setting_attribute_via_mqtt_json_message(
hass, mqtt_mock, binary_sensor.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_with_yaml_config, binary_sensor.DOMAIN, DEFAULT_CONFIG
)
async def test_setting_attribute_with_template(hass, mqtt_mock):
async def test_setting_attribute_with_template(hass, mqtt_mock_entry_with_yaml_config):
"""Test the setting of attribute via MQTT with JSON payload."""
await help_test_setting_attribute_with_template(
hass, mqtt_mock, binary_sensor.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_with_yaml_config, binary_sensor.DOMAIN, DEFAULT_CONFIG
)
async def test_update_with_json_attrs_not_dict(hass, mqtt_mock, caplog):
async def test_update_with_json_attrs_not_dict(
hass, mqtt_mock_entry_with_yaml_config, caplog
):
"""Test attributes get extracted from a JSON result."""
await help_test_update_with_json_attrs_not_dict(
hass, mqtt_mock, caplog, binary_sensor.DOMAIN, DEFAULT_CONFIG
hass,
mqtt_mock_entry_with_yaml_config,
caplog,
binary_sensor.DOMAIN,
DEFAULT_CONFIG,
)
async def test_update_with_json_attrs_bad_JSON(hass, mqtt_mock, caplog):
async def test_update_with_json_attrs_bad_JSON(
hass, mqtt_mock_entry_with_yaml_config, caplog
):
"""Test attributes get extracted from a JSON result."""
await help_test_update_with_json_attrs_bad_JSON(
hass, mqtt_mock, caplog, binary_sensor.DOMAIN, DEFAULT_CONFIG
hass,
mqtt_mock_entry_with_yaml_config,
caplog,
binary_sensor.DOMAIN,
DEFAULT_CONFIG,
)
async def test_discovery_update_attr(hass, mqtt_mock, caplog):
async def test_discovery_update_attr(hass, mqtt_mock_entry_no_yaml_config, caplog):
"""Test update of discovered MQTTAttributes."""
await help_test_discovery_update_attr(
hass, mqtt_mock, caplog, binary_sensor.DOMAIN, DEFAULT_CONFIG
hass,
mqtt_mock_entry_no_yaml_config,
caplog,
binary_sensor.DOMAIN,
DEFAULT_CONFIG,
)
async def test_unique_id(hass, mqtt_mock):
async def test_unique_id(hass, mqtt_mock_entry_with_yaml_config):
"""Test unique id option only creates one sensor per unique_id."""
config = {
binary_sensor.DOMAIN: [
@ -692,18 +736,24 @@ async def test_unique_id(hass, mqtt_mock):
},
]
}
await help_test_unique_id(hass, mqtt_mock, binary_sensor.DOMAIN, config)
async def test_discovery_removal_binary_sensor(hass, mqtt_mock, caplog):
"""Test removal of discovered binary_sensor."""
data = json.dumps(DEFAULT_CONFIG[binary_sensor.DOMAIN])
await help_test_discovery_removal(
hass, mqtt_mock, caplog, binary_sensor.DOMAIN, data
await help_test_unique_id(
hass, mqtt_mock_entry_with_yaml_config, binary_sensor.DOMAIN, config
)
async def test_discovery_update_binary_sensor_topic_template(hass, mqtt_mock, caplog):
async def test_discovery_removal_binary_sensor(
hass, mqtt_mock_entry_no_yaml_config, caplog
):
"""Test removal of discovered binary_sensor."""
data = json.dumps(DEFAULT_CONFIG[binary_sensor.DOMAIN])
await help_test_discovery_removal(
hass, mqtt_mock_entry_no_yaml_config, caplog, binary_sensor.DOMAIN, data
)
async def test_discovery_update_binary_sensor_topic_template(
hass, mqtt_mock_entry_no_yaml_config, caplog
):
"""Test update of discovered binary_sensor."""
config1 = copy.deepcopy(DEFAULT_CONFIG[binary_sensor.DOMAIN])
config2 = copy.deepcopy(DEFAULT_CONFIG[binary_sensor.DOMAIN])
@ -728,7 +778,7 @@ async def test_discovery_update_binary_sensor_topic_template(hass, mqtt_mock, ca
await help_test_discovery_update(
hass,
mqtt_mock,
mqtt_mock_entry_no_yaml_config,
caplog,
binary_sensor.DOMAIN,
config1,
@ -738,7 +788,9 @@ async def test_discovery_update_binary_sensor_topic_template(hass, mqtt_mock, ca
)
async def test_discovery_update_binary_sensor_template(hass, mqtt_mock, caplog):
async def test_discovery_update_binary_sensor_template(
hass, mqtt_mock_entry_no_yaml_config, caplog
):
"""Test update of discovered binary_sensor."""
config1 = copy.deepcopy(DEFAULT_CONFIG[binary_sensor.DOMAIN])
config2 = copy.deepcopy(DEFAULT_CONFIG[binary_sensor.DOMAIN])
@ -761,7 +813,7 @@ async def test_discovery_update_binary_sensor_template(hass, mqtt_mock, caplog):
await help_test_discovery_update(
hass,
mqtt_mock,
mqtt_mock_entry_no_yaml_config,
caplog,
binary_sensor.DOMAIN,
config1,
@ -785,12 +837,18 @@ async def test_discovery_update_binary_sensor_template(hass, mqtt_mock, caplog):
],
)
async def test_encoding_subscribable_topics(
hass, mqtt_mock, caplog, topic, value, attribute, attribute_value
hass,
mqtt_mock_entry_with_yaml_config,
caplog,
topic,
value,
attribute,
attribute_value,
):
"""Test handling of incoming encoded payload."""
await help_test_encoding_subscribable_topics(
hass,
mqtt_mock,
mqtt_mock_entry_with_yaml_config,
caplog,
binary_sensor.DOMAIN,
DEFAULT_CONFIG[binary_sensor.DOMAIN],
@ -801,7 +859,9 @@ async def test_encoding_subscribable_topics(
)
async def test_discovery_update_unchanged_binary_sensor(hass, mqtt_mock, caplog):
async def test_discovery_update_unchanged_binary_sensor(
hass, mqtt_mock_entry_no_yaml_config, caplog
):
"""Test update of discovered binary_sensor."""
config1 = copy.deepcopy(DEFAULT_CONFIG[binary_sensor.DOMAIN])
config1["name"] = "Beer"
@ -811,74 +871,90 @@ async def test_discovery_update_unchanged_binary_sensor(hass, mqtt_mock, caplog)
"homeassistant.components.mqtt.binary_sensor.MqttBinarySensor.discovery_update"
) as discovery_update:
await help_test_discovery_update_unchanged(
hass, mqtt_mock, caplog, binary_sensor.DOMAIN, data1, discovery_update
hass,
mqtt_mock_entry_no_yaml_config,
caplog,
binary_sensor.DOMAIN,
data1,
discovery_update,
)
@pytest.mark.no_fail_on_log_exception
async def test_discovery_broken(hass, mqtt_mock, caplog):
async def test_discovery_broken(hass, mqtt_mock_entry_no_yaml_config, caplog):
"""Test handling of bad discovery message."""
data1 = '{ "name": "Beer",' ' "off_delay": -1 }'
data2 = '{ "name": "Milk",' ' "state_topic": "test_topic" }'
await help_test_discovery_broken(
hass, mqtt_mock, caplog, binary_sensor.DOMAIN, data1, data2
hass,
mqtt_mock_entry_no_yaml_config,
caplog,
binary_sensor.DOMAIN,
data1,
data2,
)
async def test_entity_device_info_with_connection(hass, mqtt_mock):
async def test_entity_device_info_with_connection(hass, mqtt_mock_entry_no_yaml_config):
"""Test MQTT binary sensor device registry integration."""
await help_test_entity_device_info_with_connection(
hass, mqtt_mock, binary_sensor.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_no_yaml_config, binary_sensor.DOMAIN, DEFAULT_CONFIG
)
async def test_entity_device_info_with_identifier(hass, mqtt_mock):
async def test_entity_device_info_with_identifier(hass, mqtt_mock_entry_no_yaml_config):
"""Test MQTT binary sensor device registry integration."""
await help_test_entity_device_info_with_identifier(
hass, mqtt_mock, binary_sensor.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_no_yaml_config, binary_sensor.DOMAIN, DEFAULT_CONFIG
)
async def test_entity_device_info_update(hass, mqtt_mock):
async def test_entity_device_info_update(hass, mqtt_mock_entry_no_yaml_config):
"""Test device registry update."""
await help_test_entity_device_info_update(
hass, mqtt_mock, binary_sensor.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_no_yaml_config, binary_sensor.DOMAIN, DEFAULT_CONFIG
)
async def test_entity_device_info_remove(hass, mqtt_mock):
async def test_entity_device_info_remove(hass, mqtt_mock_entry_no_yaml_config):
"""Test device registry remove."""
await help_test_entity_device_info_remove(
hass, mqtt_mock, binary_sensor.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_no_yaml_config, binary_sensor.DOMAIN, DEFAULT_CONFIG
)
async def test_entity_id_update_subscriptions(hass, mqtt_mock):
async def test_entity_id_update_subscriptions(hass, mqtt_mock_entry_with_yaml_config):
"""Test MQTT subscriptions are managed when entity_id is updated."""
await help_test_entity_id_update_subscriptions(
hass, mqtt_mock, binary_sensor.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_with_yaml_config, binary_sensor.DOMAIN, DEFAULT_CONFIG
)
async def test_entity_id_update_discovery_update(hass, mqtt_mock):
async def test_entity_id_update_discovery_update(hass, mqtt_mock_entry_no_yaml_config):
"""Test MQTT discovery update when entity_id is updated."""
await help_test_entity_id_update_discovery_update(
hass, mqtt_mock, binary_sensor.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_no_yaml_config, binary_sensor.DOMAIN, DEFAULT_CONFIG
)
async def test_entity_debug_info_message(hass, mqtt_mock):
async def test_entity_debug_info_message(hass, mqtt_mock_entry_no_yaml_config):
"""Test MQTT debug info."""
await help_test_entity_debug_info_message(
hass, mqtt_mock, binary_sensor.DOMAIN, DEFAULT_CONFIG, None
hass,
mqtt_mock_entry_no_yaml_config,
binary_sensor.DOMAIN,
DEFAULT_CONFIG,
None,
)
async def test_reloadable(hass, mqtt_mock, caplog, tmp_path):
async def test_reloadable(hass, mqtt_mock_entry_with_yaml_config, caplog, tmp_path):
"""Test reloading the MQTT platform."""
domain = binary_sensor.DOMAIN
config = DEFAULT_CONFIG[domain]
await help_test_reloadable(hass, mqtt_mock, caplog, tmp_path, domain, config)
await help_test_reloadable(
hass, mqtt_mock_entry_with_yaml_config, caplog, tmp_path, domain, config
)
async def test_reloadable_late(hass, mqtt_client_mock, caplog, tmp_path):
@ -893,7 +969,15 @@ async def test_reloadable_late(hass, mqtt_client_mock, caplog, tmp_path):
[("ON", "on", "OFF", "off"), ("OFF", "off", "ON", "on")],
)
async def test_cleanup_triggers_and_restoring_state(
hass, mqtt_mock, caplog, tmp_path, freezer, payload1, state1, payload2, state2
hass,
mqtt_mock_entry_with_yaml_config,
caplog,
tmp_path,
freezer,
payload1,
state1,
payload2,
state2,
):
"""Test cleanup old triggers at reloading and restoring the state."""
domain = binary_sensor.DOMAIN
@ -914,6 +998,8 @@ async def test_cleanup_triggers_and_restoring_state(
{binary_sensor.DOMAIN: [config1, config2]},
)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
async_fire_mqtt_message(hass, "test-topic1", payload1)
state = hass.states.get("binary_sensor.test1")
assert state.state == state1
@ -925,7 +1011,7 @@ async def test_cleanup_triggers_and_restoring_state(
freezer.move_to("2022-02-02 12:01:10+01:00")
await help_test_reload_with_config(
hass, caplog, tmp_path, domain, [config1, config2]
hass, caplog, tmp_path, {domain: [config1, config2]}
)
assert "Clean up expire after trigger for binary_sensor.test1" in caplog.text
assert "Clean up expire after trigger for binary_sensor.test2" not in caplog.text
@ -951,7 +1037,7 @@ async def test_cleanup_triggers_and_restoring_state(
async def test_skip_restoring_state_with_over_due_expire_trigger(
hass, mqtt_mock, caplog, freezer
hass, mqtt_mock_entry_with_yaml_config, caplog, freezer
):
"""Test restoring a state with over due expire timer."""
@ -973,6 +1059,7 @@ async def test_skip_restoring_state_with_over_due_expire_trigger(
), assert_setup_component(1, domain):
assert await async_setup_component(hass, domain, {domain: config3})
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
assert "Skip state recovery after reload for binary_sensor.test3" in caplog.text

View File

@ -42,7 +42,7 @@ DEFAULT_CONFIG = {
@pytest.mark.freeze_time("2021-11-08 13:31:44+00:00")
async def test_sending_mqtt_commands(hass, mqtt_mock):
async def test_sending_mqtt_commands(hass, mqtt_mock_entry_with_yaml_config):
"""Test the sending MQTT commands."""
assert await async_setup_component(
hass,
@ -59,6 +59,7 @@ async def test_sending_mqtt_commands(hass, mqtt_mock):
},
)
await hass.async_block_till_done()
mqtt_mock = await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("button.test_button")
assert state.state == STATE_UNKNOWN
@ -79,7 +80,7 @@ async def test_sending_mqtt_commands(hass, mqtt_mock):
assert state.state == "2021-11-08T13:31:44+00:00"
async def test_command_template(hass, mqtt_mock):
async def test_command_template(hass, mqtt_mock_entry_with_yaml_config):
"""Test the sending of MQTT commands through a command template."""
assert await async_setup_component(
hass,
@ -95,6 +96,7 @@ async def test_command_template(hass, mqtt_mock):
},
)
await hass.async_block_till_done()
mqtt_mock = await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("button.test")
assert state.state == STATE_UNKNOWN
@ -113,21 +115,23 @@ async def test_command_template(hass, mqtt_mock):
mqtt_mock.async_publish.reset_mock()
async def test_availability_when_connection_lost(hass, mqtt_mock):
async def test_availability_when_connection_lost(
hass, mqtt_mock_entry_with_yaml_config
):
"""Test availability after MQTT disconnection."""
await help_test_availability_when_connection_lost(
hass, mqtt_mock, button.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_with_yaml_config, button.DOMAIN, DEFAULT_CONFIG
)
async def test_availability_without_topic(hass, mqtt_mock):
async def test_availability_without_topic(hass, mqtt_mock_entry_with_yaml_config):
"""Test availability without defined availability topic."""
await help_test_availability_without_topic(
hass, mqtt_mock, button.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_with_yaml_config, button.DOMAIN, DEFAULT_CONFIG
)
async def test_default_availability_payload(hass, mqtt_mock):
async def test_default_availability_payload(hass, mqtt_mock_entry_with_yaml_config):
"""Test availability by default payload with defined topic."""
config = {
button.DOMAIN: {
@ -139,11 +143,17 @@ async def test_default_availability_payload(hass, mqtt_mock):
}
await help_test_default_availability_payload(
hass, mqtt_mock, button.DOMAIN, config, True, "state-topic", "1"
hass,
mqtt_mock_entry_with_yaml_config,
button.DOMAIN,
config,
True,
"state-topic",
"1",
)
async def test_custom_availability_payload(hass, mqtt_mock):
async def test_custom_availability_payload(hass, mqtt_mock_entry_with_yaml_config):
"""Test availability by custom payload with defined topic."""
config = {
button.DOMAIN: {
@ -155,53 +165,67 @@ async def test_custom_availability_payload(hass, mqtt_mock):
}
await help_test_custom_availability_payload(
hass, mqtt_mock, button.DOMAIN, config, True, "state-topic", "1"
hass,
mqtt_mock_entry_with_yaml_config,
button.DOMAIN,
config,
True,
"state-topic",
"1",
)
async def test_setting_attribute_via_mqtt_json_message(hass, mqtt_mock):
async def test_setting_attribute_via_mqtt_json_message(
hass, mqtt_mock_entry_with_yaml_config
):
"""Test the setting of attribute via MQTT with JSON payload."""
await help_test_setting_attribute_via_mqtt_json_message(
hass, mqtt_mock, button.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_with_yaml_config, button.DOMAIN, DEFAULT_CONFIG
)
async def test_setting_blocked_attribute_via_mqtt_json_message(hass, mqtt_mock):
async def test_setting_blocked_attribute_via_mqtt_json_message(
hass, mqtt_mock_entry_no_yaml_config
):
"""Test the setting of attribute via MQTT with JSON payload."""
await help_test_setting_blocked_attribute_via_mqtt_json_message(
hass, mqtt_mock, button.DOMAIN, DEFAULT_CONFIG, None
hass, mqtt_mock_entry_no_yaml_config, button.DOMAIN, DEFAULT_CONFIG, None
)
async def test_setting_attribute_with_template(hass, mqtt_mock):
async def test_setting_attribute_with_template(hass, mqtt_mock_entry_with_yaml_config):
"""Test the setting of attribute via MQTT with JSON payload."""
await help_test_setting_attribute_with_template(
hass, mqtt_mock, button.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_with_yaml_config, button.DOMAIN, DEFAULT_CONFIG
)
async def test_update_with_json_attrs_not_dict(hass, mqtt_mock, caplog):
async def test_update_with_json_attrs_not_dict(
hass, mqtt_mock_entry_with_yaml_config, caplog
):
"""Test attributes get extracted from a JSON result."""
await help_test_update_with_json_attrs_not_dict(
hass, mqtt_mock, caplog, button.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_with_yaml_config, caplog, button.DOMAIN, DEFAULT_CONFIG
)
async def test_update_with_json_attrs_bad_JSON(hass, mqtt_mock, caplog):
async def test_update_with_json_attrs_bad_JSON(
hass, mqtt_mock_entry_with_yaml_config, caplog
):
"""Test attributes get extracted from a JSON result."""
await help_test_update_with_json_attrs_bad_JSON(
hass, mqtt_mock, caplog, button.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_with_yaml_config, caplog, button.DOMAIN, DEFAULT_CONFIG
)
async def test_discovery_update_attr(hass, mqtt_mock, caplog):
async def test_discovery_update_attr(hass, mqtt_mock_entry_no_yaml_config, caplog):
"""Test update of discovered MQTTAttributes."""
await help_test_discovery_update_attr(
hass, mqtt_mock, caplog, button.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_no_yaml_config, caplog, button.DOMAIN, DEFAULT_CONFIG
)
async def test_unique_id(hass, mqtt_mock):
async def test_unique_id(hass, mqtt_mock_entry_with_yaml_config):
"""Test unique id option only creates one button per unique_id."""
config = {
button.DOMAIN: [
@ -219,16 +243,20 @@ async def test_unique_id(hass, mqtt_mock):
},
]
}
await help_test_unique_id(hass, mqtt_mock, button.DOMAIN, config)
await help_test_unique_id(
hass, mqtt_mock_entry_with_yaml_config, button.DOMAIN, config
)
async def test_discovery_removal_button(hass, mqtt_mock, caplog):
async def test_discovery_removal_button(hass, mqtt_mock_entry_no_yaml_config, caplog):
"""Test removal of discovered button."""
data = '{ "name": "test", "command_topic": "test_topic" }'
await help_test_discovery_removal(hass, mqtt_mock, caplog, button.DOMAIN, data)
await help_test_discovery_removal(
hass, mqtt_mock_entry_no_yaml_config, caplog, button.DOMAIN, data
)
async def test_discovery_update_button(hass, mqtt_mock, caplog):
async def test_discovery_update_button(hass, mqtt_mock_entry_no_yaml_config, caplog):
"""Test update of discovered button."""
config1 = copy.deepcopy(DEFAULT_CONFIG[button.DOMAIN])
config2 = copy.deepcopy(DEFAULT_CONFIG[button.DOMAIN])
@ -237,7 +265,7 @@ async def test_discovery_update_button(hass, mqtt_mock, caplog):
await help_test_discovery_update(
hass,
mqtt_mock,
mqtt_mock_entry_no_yaml_config,
caplog,
button.DOMAIN,
config1,
@ -245,7 +273,9 @@ async def test_discovery_update_button(hass, mqtt_mock, caplog):
)
async def test_discovery_update_unchanged_button(hass, mqtt_mock, caplog):
async def test_discovery_update_unchanged_button(
hass, mqtt_mock_entry_no_yaml_config, caplog
):
"""Test update of discovered button."""
data1 = (
'{ "name": "Beer",'
@ -256,60 +286,65 @@ async def test_discovery_update_unchanged_button(hass, mqtt_mock, caplog):
"homeassistant.components.mqtt.button.MqttButton.discovery_update"
) as discovery_update:
await help_test_discovery_update_unchanged(
hass, mqtt_mock, caplog, button.DOMAIN, data1, discovery_update
hass,
mqtt_mock_entry_no_yaml_config,
caplog,
button.DOMAIN,
data1,
discovery_update,
)
@pytest.mark.no_fail_on_log_exception
async def test_discovery_broken(hass, mqtt_mock, caplog):
async def test_discovery_broken(hass, mqtt_mock_entry_no_yaml_config, caplog):
"""Test handling of bad discovery message."""
data1 = '{ "name": "Beer" }'
data2 = '{ "name": "Milk", "command_topic": "test_topic" }'
await help_test_discovery_broken(
hass, mqtt_mock, caplog, button.DOMAIN, data1, data2
hass, mqtt_mock_entry_no_yaml_config, caplog, button.DOMAIN, data1, data2
)
async def test_entity_device_info_with_connection(hass, mqtt_mock):
async def test_entity_device_info_with_connection(hass, mqtt_mock_entry_no_yaml_config):
"""Test MQTT button device registry integration."""
await help_test_entity_device_info_with_connection(
hass, mqtt_mock, button.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_no_yaml_config, button.DOMAIN, DEFAULT_CONFIG
)
async def test_entity_device_info_with_identifier(hass, mqtt_mock):
async def test_entity_device_info_with_identifier(hass, mqtt_mock_entry_no_yaml_config):
"""Test MQTT button device registry integration."""
await help_test_entity_device_info_with_identifier(
hass, mqtt_mock, button.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_no_yaml_config, button.DOMAIN, DEFAULT_CONFIG
)
async def test_entity_device_info_update(hass, mqtt_mock):
async def test_entity_device_info_update(hass, mqtt_mock_entry_no_yaml_config):
"""Test device registry update."""
await help_test_entity_device_info_update(
hass, mqtt_mock, button.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_no_yaml_config, button.DOMAIN, DEFAULT_CONFIG
)
async def test_entity_device_info_remove(hass, mqtt_mock):
async def test_entity_device_info_remove(hass, mqtt_mock_entry_no_yaml_config):
"""Test device registry remove."""
await help_test_entity_device_info_remove(
hass, mqtt_mock, button.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_no_yaml_config, button.DOMAIN, DEFAULT_CONFIG
)
async def test_entity_id_update_discovery_update(hass, mqtt_mock):
async def test_entity_id_update_discovery_update(hass, mqtt_mock_entry_no_yaml_config):
"""Test MQTT discovery update when entity_id is updated."""
await help_test_entity_id_update_discovery_update(
hass, mqtt_mock, button.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_no_yaml_config, button.DOMAIN, DEFAULT_CONFIG
)
async def test_entity_debug_info_message(hass, mqtt_mock):
async def test_entity_debug_info_message(hass, mqtt_mock_entry_no_yaml_config):
"""Test MQTT debug info."""
await help_test_entity_debug_info_message(
hass,
mqtt_mock,
mqtt_mock_entry_no_yaml_config,
button.DOMAIN,
DEFAULT_CONFIG,
button.SERVICE_PRESS,
@ -318,7 +353,7 @@ async def test_entity_debug_info_message(hass, mqtt_mock):
)
async def test_invalid_device_class(hass, mqtt_mock):
async def test_invalid_device_class(hass, mqtt_mock_entry_no_yaml_config):
"""Test device_class option with invalid value."""
assert await async_setup_component(
hass,
@ -333,12 +368,13 @@ async def test_invalid_device_class(hass, mqtt_mock):
},
)
await hass.async_block_till_done()
await mqtt_mock_entry_no_yaml_config()
state = hass.states.get("button.test")
assert state is None
async def test_valid_device_class(hass, mqtt_mock):
async def test_valid_device_class(hass, mqtt_mock_entry_with_yaml_config):
"""Test device_class option with valid values."""
assert await async_setup_component(
hass,
@ -366,6 +402,7 @@ async def test_valid_device_class(hass, mqtt_mock):
},
)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("button.test_1")
assert state.attributes["device_class"] == button.ButtonDeviceClass.UPDATE
@ -382,7 +419,14 @@ async def test_valid_device_class(hass, mqtt_mock):
],
)
async def test_publishing_with_custom_encoding(
hass, mqtt_mock, caplog, service, topic, parameters, payload, template
hass,
mqtt_mock_entry_with_yaml_config,
caplog,
service,
topic,
parameters,
payload,
template,
):
"""Test publishing MQTT payload with different encoding."""
domain = button.DOMAIN
@ -390,7 +434,7 @@ async def test_publishing_with_custom_encoding(
await help_test_publishing_with_custom_encoding(
hass,
mqtt_mock,
mqtt_mock_entry_with_yaml_config,
caplog,
domain,
config,
@ -402,11 +446,13 @@ async def test_publishing_with_custom_encoding(
)
async def test_reloadable(hass, mqtt_mock, caplog, tmp_path):
async def test_reloadable(hass, mqtt_mock_entry_with_yaml_config, caplog, tmp_path):
"""Test reloading the MQTT platform."""
domain = button.DOMAIN
config = DEFAULT_CONFIG[domain]
await help_test_reloadable(hass, mqtt_mock, caplog, tmp_path, domain, config)
await help_test_reloadable(
hass, mqtt_mock_entry_with_yaml_config, caplog, tmp_path, domain, config
)
async def test_reloadable_late(hass, mqtt_client_mock, caplog, tmp_path):

View File

@ -46,7 +46,9 @@ DEFAULT_CONFIG = {
}
async def test_run_camera_setup(hass, hass_client_no_auth, mqtt_mock):
async def test_run_camera_setup(
hass, hass_client_no_auth, mqtt_mock_entry_with_yaml_config
):
"""Test that it fetches the given payload."""
topic = "test/camera"
await async_setup_component(
@ -55,6 +57,7 @@ async def test_run_camera_setup(hass, hass_client_no_auth, mqtt_mock):
{"camera": {"platform": "mqtt", "topic": topic, "name": "Test Camera"}},
)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
url = hass.states.get("camera.test_camera").attributes["entity_picture"]
@ -67,7 +70,9 @@ async def test_run_camera_setup(hass, hass_client_no_auth, mqtt_mock):
assert body == "beer"
async def test_run_camera_b64_encoded(hass, hass_client_no_auth, mqtt_mock):
async def test_run_camera_b64_encoded(
hass, hass_client_no_auth, mqtt_mock_entry_with_yaml_config
):
"""Test that it fetches the given encoded payload."""
topic = "test/camera"
await async_setup_component(
@ -83,6 +88,7 @@ async def test_run_camera_b64_encoded(hass, hass_client_no_auth, mqtt_mock):
},
)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
url = hass.states.get("camera.test_camera").attributes["entity_picture"]
@ -95,77 +101,91 @@ async def test_run_camera_b64_encoded(hass, hass_client_no_auth, mqtt_mock):
assert body == "grass"
async def test_availability_when_connection_lost(hass, mqtt_mock):
async def test_availability_when_connection_lost(
hass, mqtt_mock_entry_with_yaml_config
):
"""Test availability after MQTT disconnection."""
await help_test_availability_when_connection_lost(
hass, mqtt_mock, camera.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_with_yaml_config, camera.DOMAIN, DEFAULT_CONFIG
)
async def test_availability_without_topic(hass, mqtt_mock):
async def test_availability_without_topic(hass, mqtt_mock_entry_with_yaml_config):
"""Test availability without defined availability topic."""
await help_test_availability_without_topic(
hass, mqtt_mock, camera.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_with_yaml_config, camera.DOMAIN, DEFAULT_CONFIG
)
async def test_default_availability_payload(hass, mqtt_mock):
async def test_default_availability_payload(hass, mqtt_mock_entry_with_yaml_config):
"""Test availability by default payload with defined topic."""
await help_test_default_availability_payload(
hass, mqtt_mock, camera.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_with_yaml_config, camera.DOMAIN, DEFAULT_CONFIG
)
async def test_custom_availability_payload(hass, mqtt_mock):
async def test_custom_availability_payload(hass, mqtt_mock_entry_with_yaml_config):
"""Test availability by custom payload with defined topic."""
await help_test_custom_availability_payload(
hass, mqtt_mock, camera.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_with_yaml_config, camera.DOMAIN, DEFAULT_CONFIG
)
async def test_setting_attribute_via_mqtt_json_message(hass, mqtt_mock):
async def test_setting_attribute_via_mqtt_json_message(
hass, mqtt_mock_entry_with_yaml_config
):
"""Test the setting of attribute via MQTT with JSON payload."""
await help_test_setting_attribute_via_mqtt_json_message(
hass, mqtt_mock, camera.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_with_yaml_config, camera.DOMAIN, DEFAULT_CONFIG
)
async def test_setting_blocked_attribute_via_mqtt_json_message(hass, mqtt_mock):
async def test_setting_blocked_attribute_via_mqtt_json_message(
hass, mqtt_mock_entry_no_yaml_config
):
"""Test the setting of attribute via MQTT with JSON payload."""
await help_test_setting_blocked_attribute_via_mqtt_json_message(
hass, mqtt_mock, camera.DOMAIN, DEFAULT_CONFIG, MQTT_CAMERA_ATTRIBUTES_BLOCKED
hass,
mqtt_mock_entry_no_yaml_config,
camera.DOMAIN,
DEFAULT_CONFIG,
MQTT_CAMERA_ATTRIBUTES_BLOCKED,
)
async def test_setting_attribute_with_template(hass, mqtt_mock):
async def test_setting_attribute_with_template(hass, mqtt_mock_entry_with_yaml_config):
"""Test the setting of attribute via MQTT with JSON payload."""
await help_test_setting_attribute_with_template(
hass, mqtt_mock, camera.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_with_yaml_config, camera.DOMAIN, DEFAULT_CONFIG
)
async def test_update_with_json_attrs_not_dict(hass, mqtt_mock, caplog):
async def test_update_with_json_attrs_not_dict(
hass, mqtt_mock_entry_with_yaml_config, caplog
):
"""Test attributes get extracted from a JSON result."""
await help_test_update_with_json_attrs_not_dict(
hass, mqtt_mock, caplog, camera.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_with_yaml_config, caplog, camera.DOMAIN, DEFAULT_CONFIG
)
async def test_update_with_json_attrs_bad_JSON(hass, mqtt_mock, caplog):
async def test_update_with_json_attrs_bad_JSON(
hass, mqtt_mock_entry_with_yaml_config, caplog
):
"""Test attributes get extracted from a JSON result."""
await help_test_update_with_json_attrs_bad_JSON(
hass, mqtt_mock, caplog, camera.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_with_yaml_config, caplog, camera.DOMAIN, DEFAULT_CONFIG
)
async def test_discovery_update_attr(hass, mqtt_mock, caplog):
async def test_discovery_update_attr(hass, mqtt_mock_entry_no_yaml_config, caplog):
"""Test update of discovered MQTTAttributes."""
await help_test_discovery_update_attr(
hass, mqtt_mock, caplog, camera.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_no_yaml_config, caplog, camera.DOMAIN, DEFAULT_CONFIG
)
async def test_unique_id(hass, mqtt_mock):
async def test_unique_id(hass, mqtt_mock_entry_with_yaml_config):
"""Test unique id option only creates one camera per unique_id."""
config = {
camera.DOMAIN: [
@ -183,94 +203,109 @@ async def test_unique_id(hass, mqtt_mock):
},
]
}
await help_test_unique_id(hass, mqtt_mock, camera.DOMAIN, config)
await help_test_unique_id(
hass, mqtt_mock_entry_with_yaml_config, camera.DOMAIN, config
)
async def test_discovery_removal_camera(hass, mqtt_mock, caplog):
async def test_discovery_removal_camera(hass, mqtt_mock_entry_no_yaml_config, caplog):
"""Test removal of discovered camera."""
data = json.dumps(DEFAULT_CONFIG[camera.DOMAIN])
await help_test_discovery_removal(hass, mqtt_mock, caplog, camera.DOMAIN, data)
await help_test_discovery_removal(
hass, mqtt_mock_entry_no_yaml_config, caplog, camera.DOMAIN, data
)
async def test_discovery_update_camera(hass, mqtt_mock, caplog):
async def test_discovery_update_camera(hass, mqtt_mock_entry_no_yaml_config, caplog):
"""Test update of discovered camera."""
config1 = {"name": "Beer", "topic": "test_topic"}
config2 = {"name": "Milk", "topic": "test_topic"}
await help_test_discovery_update(
hass, mqtt_mock, caplog, camera.DOMAIN, config1, config2
hass, mqtt_mock_entry_no_yaml_config, caplog, camera.DOMAIN, config1, config2
)
async def test_discovery_update_unchanged_camera(hass, mqtt_mock, caplog):
async def test_discovery_update_unchanged_camera(
hass, mqtt_mock_entry_no_yaml_config, caplog
):
"""Test update of discovered camera."""
data1 = '{ "name": "Beer", "topic": "test_topic"}'
with patch(
"homeassistant.components.mqtt.camera.MqttCamera.discovery_update"
) as discovery_update:
await help_test_discovery_update_unchanged(
hass, mqtt_mock, caplog, camera.DOMAIN, data1, discovery_update
hass,
mqtt_mock_entry_no_yaml_config,
caplog,
camera.DOMAIN,
data1,
discovery_update,
)
@pytest.mark.no_fail_on_log_exception
async def test_discovery_broken(hass, mqtt_mock, caplog):
async def test_discovery_broken(hass, mqtt_mock_entry_no_yaml_config, caplog):
"""Test handling of bad discovery message."""
data1 = '{ "name": "Beer" }'
data2 = '{ "name": "Milk", "topic": "test_topic"}'
await help_test_discovery_broken(
hass, mqtt_mock, caplog, camera.DOMAIN, data1, data2
hass, mqtt_mock_entry_no_yaml_config, caplog, camera.DOMAIN, data1, data2
)
async def test_entity_device_info_with_connection(hass, mqtt_mock):
async def test_entity_device_info_with_connection(hass, mqtt_mock_entry_no_yaml_config):
"""Test MQTT camera device registry integration."""
await help_test_entity_device_info_with_connection(
hass, mqtt_mock, camera.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_no_yaml_config, camera.DOMAIN, DEFAULT_CONFIG
)
async def test_entity_device_info_with_identifier(hass, mqtt_mock):
async def test_entity_device_info_with_identifier(hass, mqtt_mock_entry_no_yaml_config):
"""Test MQTT camera device registry integration."""
await help_test_entity_device_info_with_identifier(
hass, mqtt_mock, camera.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_no_yaml_config, camera.DOMAIN, DEFAULT_CONFIG
)
async def test_entity_device_info_update(hass, mqtt_mock):
async def test_entity_device_info_update(hass, mqtt_mock_entry_no_yaml_config):
"""Test device registry update."""
await help_test_entity_device_info_update(
hass, mqtt_mock, camera.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_no_yaml_config, camera.DOMAIN, DEFAULT_CONFIG
)
async def test_entity_device_info_remove(hass, mqtt_mock):
async def test_entity_device_info_remove(hass, mqtt_mock_entry_no_yaml_config):
"""Test device registry remove."""
await help_test_entity_device_info_remove(
hass, mqtt_mock, camera.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_no_yaml_config, camera.DOMAIN, DEFAULT_CONFIG
)
async def test_entity_id_update_subscriptions(hass, mqtt_mock):
async def test_entity_id_update_subscriptions(hass, mqtt_mock_entry_with_yaml_config):
"""Test MQTT subscriptions are managed when entity_id is updated."""
await help_test_entity_id_update_subscriptions(
hass, mqtt_mock, camera.DOMAIN, DEFAULT_CONFIG, ["test_topic"]
hass,
mqtt_mock_entry_with_yaml_config,
camera.DOMAIN,
DEFAULT_CONFIG,
["test_topic"],
)
async def test_entity_id_update_discovery_update(hass, mqtt_mock):
async def test_entity_id_update_discovery_update(hass, mqtt_mock_entry_no_yaml_config):
"""Test MQTT discovery update when entity_id is updated."""
await help_test_entity_id_update_discovery_update(
hass, mqtt_mock, camera.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_no_yaml_config, camera.DOMAIN, DEFAULT_CONFIG
)
async def test_entity_debug_info_message(hass, mqtt_mock):
async def test_entity_debug_info_message(hass, mqtt_mock_entry_no_yaml_config):
"""Test MQTT debug info."""
await help_test_entity_debug_info_message(
hass,
mqtt_mock,
mqtt_mock_entry_no_yaml_config,
camera.DOMAIN,
DEFAULT_CONFIG,
None,
@ -279,11 +314,13 @@ async def test_entity_debug_info_message(hass, mqtt_mock):
)
async def test_reloadable(hass, mqtt_mock, caplog, tmp_path):
async def test_reloadable(hass, mqtt_mock_entry_with_yaml_config, caplog, tmp_path):
"""Test reloading the MQTT platform."""
domain = camera.DOMAIN
config = DEFAULT_CONFIG[domain]
await help_test_reloadable(hass, mqtt_mock, caplog, tmp_path, domain, config)
await help_test_reloadable(
hass, mqtt_mock_entry_with_yaml_config, caplog, tmp_path, domain, config
)
async def test_reloadable_late(hass, mqtt_client_mock, caplog, tmp_path):

View File

@ -106,10 +106,11 @@ DEFAULT_LEGACY_CONFIG = {
}
async def test_setup_params(hass, mqtt_mock):
async def test_setup_params(hass, mqtt_mock_entry_with_yaml_config):
"""Test the initial parameters."""
assert await async_setup_component(hass, CLIMATE_DOMAIN, DEFAULT_CONFIG)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
state = hass.states.get(ENTITY_CLIMATE)
assert state.attributes.get("temperature") == 21
@ -120,12 +121,15 @@ async def test_setup_params(hass, mqtt_mock):
assert state.attributes.get("max_temp") == DEFAULT_MAX_TEMP
async def test_preset_none_in_preset_modes(hass, mqtt_mock, caplog):
async def test_preset_none_in_preset_modes(
hass, mqtt_mock_entry_no_yaml_config, caplog
):
"""Test the preset mode payload reset configuration."""
config = copy.deepcopy(DEFAULT_CONFIG[CLIMATE_DOMAIN])
config["preset_modes"].append("none")
assert await async_setup_component(hass, CLIMATE_DOMAIN, {CLIMATE_DOMAIN: config})
await hass.async_block_till_done()
await mqtt_mock_entry_no_yaml_config()
assert "Invalid config for [climate.mqtt]: not a valid value" in caplog.text
state = hass.states.get(ENTITY_CLIMATE)
assert state is None
@ -145,21 +149,23 @@ async def test_preset_none_in_preset_modes(hass, mqtt_mock, caplog):
],
)
async def test_preset_modes_deprecation_guard(
hass, mqtt_mock, caplog, parameter, config_value
hass, mqtt_mock_entry_no_yaml_config, caplog, parameter, config_value
):
"""Test the configuration for invalid legacy parameters."""
config = copy.deepcopy(DEFAULT_CONFIG[CLIMATE_DOMAIN])
config[parameter] = config_value
assert await async_setup_component(hass, CLIMATE_DOMAIN, {CLIMATE_DOMAIN: config})
await hass.async_block_till_done()
await mqtt_mock_entry_no_yaml_config()
state = hass.states.get(ENTITY_CLIMATE)
assert state is None
async def test_supported_features(hass, mqtt_mock):
async def test_supported_features(hass, mqtt_mock_entry_with_yaml_config):
"""Test the supported_features."""
assert await async_setup_component(hass, CLIMATE_DOMAIN, DEFAULT_CONFIG)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
state = hass.states.get(ENTITY_CLIMATE)
support = (
@ -174,10 +180,11 @@ async def test_supported_features(hass, mqtt_mock):
assert state.attributes.get("supported_features") == support
async def test_get_hvac_modes(hass, mqtt_mock):
async def test_get_hvac_modes(hass, mqtt_mock_entry_with_yaml_config):
"""Test that the operation list returns the correct modes."""
assert await async_setup_component(hass, CLIMATE_DOMAIN, DEFAULT_CONFIG)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
state = hass.states.get(ENTITY_CLIMATE)
modes = state.attributes.get("hvac_modes")
@ -191,13 +198,16 @@ async def test_get_hvac_modes(hass, mqtt_mock):
] == modes
async def test_set_operation_bad_attr_and_state(hass, mqtt_mock, caplog):
async def test_set_operation_bad_attr_and_state(
hass, mqtt_mock_entry_with_yaml_config, caplog
):
"""Test setting operation mode without required attribute.
Also check the state.
"""
assert await async_setup_component(hass, CLIMATE_DOMAIN, DEFAULT_CONFIG)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
state = hass.states.get(ENTITY_CLIMATE)
assert state.state == "off"
@ -210,10 +220,11 @@ async def test_set_operation_bad_attr_and_state(hass, mqtt_mock, caplog):
assert state.state == "off"
async def test_set_operation(hass, mqtt_mock):
async def test_set_operation(hass, mqtt_mock_entry_with_yaml_config):
"""Test setting of new operation mode."""
assert await async_setup_component(hass, CLIMATE_DOMAIN, DEFAULT_CONFIG)
await hass.async_block_till_done()
mqtt_mock = await mqtt_mock_entry_with_yaml_config()
state = hass.states.get(ENTITY_CLIMATE)
assert state.state == "off"
@ -224,12 +235,13 @@ async def test_set_operation(hass, mqtt_mock):
mqtt_mock.async_publish.assert_called_once_with("mode-topic", "cool", 0, False)
async def test_set_operation_pessimistic(hass, mqtt_mock):
async def test_set_operation_pessimistic(hass, mqtt_mock_entry_with_yaml_config):
"""Test setting operation mode in pessimistic mode."""
config = copy.deepcopy(DEFAULT_CONFIG)
config["climate"]["mode_state_topic"] = "mode-state"
assert await async_setup_component(hass, CLIMATE_DOMAIN, config)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
state = hass.states.get(ENTITY_CLIMATE)
assert state.state == "unknown"
@ -247,12 +259,13 @@ async def test_set_operation_pessimistic(hass, mqtt_mock):
assert state.state == "cool"
async def test_set_operation_with_power_command(hass, mqtt_mock):
async def test_set_operation_with_power_command(hass, mqtt_mock_entry_with_yaml_config):
"""Test setting of new operation mode with power command enabled."""
config = copy.deepcopy(DEFAULT_CONFIG)
config["climate"]["power_command_topic"] = "power-command"
assert await async_setup_component(hass, CLIMATE_DOMAIN, config)
await hass.async_block_till_done()
mqtt_mock = await mqtt_mock_entry_with_yaml_config()
state = hass.states.get(ENTITY_CLIMATE)
assert state.state == "off"
@ -273,10 +286,11 @@ async def test_set_operation_with_power_command(hass, mqtt_mock):
mqtt_mock.async_publish.reset_mock()
async def test_set_fan_mode_bad_attr(hass, mqtt_mock, caplog):
async def test_set_fan_mode_bad_attr(hass, mqtt_mock_entry_with_yaml_config, caplog):
"""Test setting fan mode without required attribute."""
assert await async_setup_component(hass, CLIMATE_DOMAIN, DEFAULT_CONFIG)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
state = hass.states.get(ENTITY_CLIMATE)
assert state.attributes.get("fan_mode") == "low"
@ -289,12 +303,13 @@ async def test_set_fan_mode_bad_attr(hass, mqtt_mock, caplog):
assert state.attributes.get("fan_mode") == "low"
async def test_set_fan_mode_pessimistic(hass, mqtt_mock):
async def test_set_fan_mode_pessimistic(hass, mqtt_mock_entry_with_yaml_config):
"""Test setting of new fan mode in pessimistic mode."""
config = copy.deepcopy(DEFAULT_CONFIG)
config["climate"]["fan_mode_state_topic"] = "fan-state"
assert await async_setup_component(hass, CLIMATE_DOMAIN, config)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
state = hass.states.get(ENTITY_CLIMATE)
assert state.attributes.get("fan_mode") is None
@ -312,10 +327,11 @@ async def test_set_fan_mode_pessimistic(hass, mqtt_mock):
assert state.attributes.get("fan_mode") == "high"
async def test_set_fan_mode(hass, mqtt_mock):
async def test_set_fan_mode(hass, mqtt_mock_entry_with_yaml_config):
"""Test setting of new fan mode."""
assert await async_setup_component(hass, CLIMATE_DOMAIN, DEFAULT_CONFIG)
await hass.async_block_till_done()
mqtt_mock = await mqtt_mock_entry_with_yaml_config()
state = hass.states.get(ENTITY_CLIMATE)
assert state.attributes.get("fan_mode") == "low"
@ -335,13 +351,14 @@ async def test_set_fan_mode(hass, mqtt_mock):
],
)
async def test_set_fan_mode_send_if_off(
hass, mqtt_mock, send_if_off, assert_async_publish
hass, mqtt_mock_entry_with_yaml_config, send_if_off, assert_async_publish
):
"""Test setting of fan mode if the hvac is off."""
config = copy.deepcopy(DEFAULT_CONFIG)
config[CLIMATE_DOMAIN].update(send_if_off)
assert await async_setup_component(hass, CLIMATE_DOMAIN, config)
await hass.async_block_till_done()
mqtt_mock = await mqtt_mock_entry_with_yaml_config()
assert hass.states.get(ENTITY_CLIMATE) is not None
# Turn on HVAC
@ -362,10 +379,11 @@ async def test_set_fan_mode_send_if_off(
mqtt_mock.async_publish.assert_has_calls(assert_async_publish)
async def test_set_swing_mode_bad_attr(hass, mqtt_mock, caplog):
async def test_set_swing_mode_bad_attr(hass, mqtt_mock_entry_with_yaml_config, caplog):
"""Test setting swing mode without required attribute."""
assert await async_setup_component(hass, CLIMATE_DOMAIN, DEFAULT_CONFIG)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
state = hass.states.get(ENTITY_CLIMATE)
assert state.attributes.get("swing_mode") == "off"
@ -378,12 +396,13 @@ async def test_set_swing_mode_bad_attr(hass, mqtt_mock, caplog):
assert state.attributes.get("swing_mode") == "off"
async def test_set_swing_pessimistic(hass, mqtt_mock):
async def test_set_swing_pessimistic(hass, mqtt_mock_entry_with_yaml_config):
"""Test setting swing mode in pessimistic mode."""
config = copy.deepcopy(DEFAULT_CONFIG)
config["climate"]["swing_mode_state_topic"] = "swing-state"
assert await async_setup_component(hass, CLIMATE_DOMAIN, config)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
state = hass.states.get(ENTITY_CLIMATE)
assert state.attributes.get("swing_mode") is None
@ -401,10 +420,11 @@ async def test_set_swing_pessimistic(hass, mqtt_mock):
assert state.attributes.get("swing_mode") == "on"
async def test_set_swing(hass, mqtt_mock):
async def test_set_swing(hass, mqtt_mock_entry_with_yaml_config):
"""Test setting of new swing mode."""
assert await async_setup_component(hass, CLIMATE_DOMAIN, DEFAULT_CONFIG)
await hass.async_block_till_done()
mqtt_mock = await mqtt_mock_entry_with_yaml_config()
state = hass.states.get(ENTITY_CLIMATE)
assert state.attributes.get("swing_mode") == "off"
@ -424,13 +444,14 @@ async def test_set_swing(hass, mqtt_mock):
],
)
async def test_set_swing_mode_send_if_off(
hass, mqtt_mock, send_if_off, assert_async_publish
hass, mqtt_mock_entry_with_yaml_config, send_if_off, assert_async_publish
):
"""Test setting of swing mode if the hvac is off."""
config = copy.deepcopy(DEFAULT_CONFIG)
config[CLIMATE_DOMAIN].update(send_if_off)
assert await async_setup_component(hass, CLIMATE_DOMAIN, config)
await hass.async_block_till_done()
mqtt_mock = await mqtt_mock_entry_with_yaml_config()
assert hass.states.get(ENTITY_CLIMATE) is not None
# Turn on HVAC
@ -451,10 +472,11 @@ async def test_set_swing_mode_send_if_off(
mqtt_mock.async_publish.assert_has_calls(assert_async_publish)
async def test_set_target_temperature(hass, mqtt_mock):
async def test_set_target_temperature(hass, mqtt_mock_entry_with_yaml_config):
"""Test setting the target temperature."""
assert await async_setup_component(hass, CLIMATE_DOMAIN, DEFAULT_CONFIG)
await hass.async_block_till_done()
mqtt_mock = await mqtt_mock_entry_with_yaml_config()
state = hass.states.get(ENTITY_CLIMATE)
assert state.attributes.get("temperature") == 21
@ -497,13 +519,14 @@ async def test_set_target_temperature(hass, mqtt_mock):
],
)
async def test_set_target_temperature_send_if_off(
hass, mqtt_mock, send_if_off, assert_async_publish
hass, mqtt_mock_entry_with_yaml_config, send_if_off, assert_async_publish
):
"""Test setting of target temperature if the hvac is off."""
config = copy.deepcopy(DEFAULT_CONFIG)
config[CLIMATE_DOMAIN].update(send_if_off)
assert await async_setup_component(hass, CLIMATE_DOMAIN, config)
await hass.async_block_till_done()
mqtt_mock = await mqtt_mock_entry_with_yaml_config()
assert hass.states.get(ENTITY_CLIMATE) is not None
# Turn on HVAC
@ -526,12 +549,15 @@ async def test_set_target_temperature_send_if_off(
mqtt_mock.async_publish.assert_has_calls(assert_async_publish)
async def test_set_target_temperature_pessimistic(hass, mqtt_mock):
async def test_set_target_temperature_pessimistic(
hass, mqtt_mock_entry_with_yaml_config
):
"""Test setting the target temperature."""
config = copy.deepcopy(DEFAULT_CONFIG)
config["climate"]["temperature_state_topic"] = "temperature-state"
assert await async_setup_component(hass, CLIMATE_DOMAIN, config)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
state = hass.states.get(ENTITY_CLIMATE)
assert state.attributes.get("temperature") is None
@ -549,10 +575,11 @@ async def test_set_target_temperature_pessimistic(hass, mqtt_mock):
assert state.attributes.get("temperature") == 1701
async def test_set_target_temperature_low_high(hass, mqtt_mock):
async def test_set_target_temperature_low_high(hass, mqtt_mock_entry_with_yaml_config):
"""Test setting the low/high target temperature."""
assert await async_setup_component(hass, CLIMATE_DOMAIN, DEFAULT_CONFIG)
await hass.async_block_till_done()
mqtt_mock = await mqtt_mock_entry_with_yaml_config()
await common.async_set_temperature(
hass, target_temp_low=20, target_temp_high=23, entity_id=ENTITY_CLIMATE
@ -564,13 +591,16 @@ async def test_set_target_temperature_low_high(hass, mqtt_mock):
mqtt_mock.async_publish.assert_any_call("temperature-high-topic", "23.0", 0, False)
async def test_set_target_temperature_low_highpessimistic(hass, mqtt_mock):
async def test_set_target_temperature_low_highpessimistic(
hass, mqtt_mock_entry_with_yaml_config
):
"""Test setting the low/high target temperature."""
config = copy.deepcopy(DEFAULT_CONFIG)
config["climate"]["temperature_low_state_topic"] = "temperature-low-state"
config["climate"]["temperature_high_state_topic"] = "temperature-high-state"
assert await async_setup_component(hass, CLIMATE_DOMAIN, config)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
state = hass.states.get(ENTITY_CLIMATE)
assert state.attributes.get("target_temp_low") is None
@ -601,24 +631,26 @@ async def test_set_target_temperature_low_highpessimistic(hass, mqtt_mock):
assert state.attributes.get("target_temp_high") == 1703
async def test_receive_mqtt_temperature(hass, mqtt_mock):
async def test_receive_mqtt_temperature(hass, mqtt_mock_entry_with_yaml_config):
"""Test getting the current temperature via MQTT."""
config = copy.deepcopy(DEFAULT_CONFIG)
config["climate"]["current_temperature_topic"] = "current_temperature"
assert await async_setup_component(hass, CLIMATE_DOMAIN, config)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
async_fire_mqtt_message(hass, "current_temperature", "47")
state = hass.states.get(ENTITY_CLIMATE)
assert state.attributes.get("current_temperature") == 47
async def test_handle_action_received(hass, mqtt_mock):
async def test_handle_action_received(hass, mqtt_mock_entry_with_yaml_config):
"""Test getting the action received via MQTT."""
config = copy.deepcopy(DEFAULT_CONFIG)
config["climate"]["action_topic"] = "action"
assert await async_setup_component(hass, CLIMATE_DOMAIN, config)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
# Cycle through valid modes and also check for wrong input such as "None" (str(None))
async_fire_mqtt_message(hass, "action", "None")
@ -635,11 +667,14 @@ async def test_handle_action_received(hass, mqtt_mock):
assert hvac_action == action
async def test_set_preset_mode_optimistic(hass, mqtt_mock, caplog):
async def test_set_preset_mode_optimistic(
hass, mqtt_mock_entry_with_yaml_config, caplog
):
"""Test setting of the preset mode."""
config = copy.deepcopy(DEFAULT_CONFIG)
assert await async_setup_component(hass, CLIMATE_DOMAIN, config)
await hass.async_block_till_done()
mqtt_mock = await mqtt_mock_entry_with_yaml_config()
state = hass.states.get(ENTITY_CLIMATE)
assert state.attributes.get("preset_mode") == "none"
@ -680,12 +715,15 @@ async def test_set_preset_mode_optimistic(hass, mqtt_mock, caplog):
assert "'invalid' is not a valid preset mode" in caplog.text
async def test_set_preset_mode_pessimistic(hass, mqtt_mock, caplog):
async def test_set_preset_mode_pessimistic(
hass, mqtt_mock_entry_with_yaml_config, caplog
):
"""Test setting of the preset mode."""
config = copy.deepcopy(DEFAULT_CONFIG)
config["climate"]["preset_mode_state_topic"] = "preset-mode-state"
assert await async_setup_component(hass, CLIMATE_DOMAIN, config)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
state = hass.states.get(ENTITY_CLIMATE)
assert state.attributes.get("preset_mode") == "none"
@ -725,12 +763,13 @@ async def test_set_preset_mode_pessimistic(hass, mqtt_mock, caplog):
# AWAY and HOLD mode topics and templates are deprecated, support will be removed with release 2022.9
async def test_set_away_mode_pessimistic(hass, mqtt_mock):
async def test_set_away_mode_pessimistic(hass, mqtt_mock_entry_with_yaml_config):
"""Test setting of the away mode."""
config = copy.deepcopy(DEFAULT_LEGACY_CONFIG)
config["climate"]["away_mode_state_topic"] = "away-state"
assert await async_setup_component(hass, CLIMATE_DOMAIN, config)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
state = hass.states.get(ENTITY_CLIMATE)
assert state.attributes.get("preset_mode") == "none"
@ -753,7 +792,7 @@ async def test_set_away_mode_pessimistic(hass, mqtt_mock):
# AWAY and HOLD mode topics and templates are deprecated, support will be removed with release 2022.9
async def test_set_away_mode(hass, mqtt_mock):
async def test_set_away_mode(hass, mqtt_mock_entry_with_yaml_config):
"""Test setting of the away mode."""
config = copy.deepcopy(DEFAULT_LEGACY_CONFIG)
config["climate"]["payload_on"] = "AN"
@ -761,6 +800,7 @@ async def test_set_away_mode(hass, mqtt_mock):
assert await async_setup_component(hass, CLIMATE_DOMAIN, config)
await hass.async_block_till_done()
mqtt_mock = await mqtt_mock_entry_with_yaml_config()
state = hass.states.get(ENTITY_CLIMATE)
assert state.attributes.get("preset_mode") == "none"
@ -795,12 +835,13 @@ async def test_set_away_mode(hass, mqtt_mock):
# AWAY and HOLD mode topics and templates are deprecated, support will be removed with release 2022.9
async def test_set_hold_pessimistic(hass, mqtt_mock):
async def test_set_hold_pessimistic(hass, mqtt_mock_entry_with_yaml_config):
"""Test setting the hold mode in pessimistic mode."""
config = copy.deepcopy(DEFAULT_LEGACY_CONFIG)
config["climate"]["hold_state_topic"] = "hold-state"
assert await async_setup_component(hass, CLIMATE_DOMAIN, config)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
state = hass.states.get(ENTITY_CLIMATE)
assert state.attributes.get("hold_mode") is None
@ -819,10 +860,11 @@ async def test_set_hold_pessimistic(hass, mqtt_mock):
# AWAY and HOLD mode topics and templates are deprecated, support will be removed with release 2022.9
async def test_set_hold(hass, mqtt_mock):
async def test_set_hold(hass, mqtt_mock_entry_with_yaml_config):
"""Test setting the hold mode."""
assert await async_setup_component(hass, CLIMATE_DOMAIN, DEFAULT_LEGACY_CONFIG)
await hass.async_block_till_done()
mqtt_mock = await mqtt_mock_entry_with_yaml_config()
state = hass.states.get(ENTITY_CLIMATE)
assert state.attributes.get("preset_mode") == "none"
@ -851,10 +893,11 @@ async def test_set_hold(hass, mqtt_mock):
# AWAY and HOLD mode topics and templates are deprecated, support will be removed with release 2022.9
async def test_set_preset_away(hass, mqtt_mock):
async def test_set_preset_away(hass, mqtt_mock_entry_with_yaml_config):
"""Test setting the hold mode and away mode."""
assert await async_setup_component(hass, CLIMATE_DOMAIN, DEFAULT_LEGACY_CONFIG)
await hass.async_block_till_done()
mqtt_mock = await mqtt_mock_entry_with_yaml_config()
state = hass.states.get(ENTITY_CLIMATE)
assert state.attributes.get("preset_mode") == PRESET_NONE
@ -885,13 +928,14 @@ async def test_set_preset_away(hass, mqtt_mock):
# AWAY and HOLD mode topics and templates are deprecated, support will be removed with release 2022.9
async def test_set_preset_away_pessimistic(hass, mqtt_mock):
async def test_set_preset_away_pessimistic(hass, mqtt_mock_entry_with_yaml_config):
"""Test setting the hold mode and away mode in pessimistic mode."""
config = copy.deepcopy(DEFAULT_LEGACY_CONFIG)
config["climate"]["hold_state_topic"] = "hold-state"
config["climate"]["away_mode_state_topic"] = "away-state"
assert await async_setup_component(hass, CLIMATE_DOMAIN, config)
await hass.async_block_till_done()
mqtt_mock = await mqtt_mock_entry_with_yaml_config()
state = hass.states.get(ENTITY_CLIMATE)
assert state.attributes.get("preset_mode") == PRESET_NONE
@ -936,10 +980,11 @@ async def test_set_preset_away_pessimistic(hass, mqtt_mock):
# AWAY and HOLD mode topics and templates are deprecated, support will be removed with release 2022.9
async def test_set_preset_mode_twice(hass, mqtt_mock):
async def test_set_preset_mode_twice(hass, mqtt_mock_entry_with_yaml_config):
"""Test setting of the same mode twice only publishes once."""
assert await async_setup_component(hass, CLIMATE_DOMAIN, DEFAULT_LEGACY_CONFIG)
await hass.async_block_till_done()
mqtt_mock = await mqtt_mock_entry_with_yaml_config()
state = hass.states.get(ENTITY_CLIMATE)
assert state.attributes.get("preset_mode") == "none"
@ -952,12 +997,13 @@ async def test_set_preset_mode_twice(hass, mqtt_mock):
assert state.attributes.get("preset_mode") == "hold-on"
async def test_set_aux_pessimistic(hass, mqtt_mock):
async def test_set_aux_pessimistic(hass, mqtt_mock_entry_with_yaml_config):
"""Test setting of the aux heating in pessimistic mode."""
config = copy.deepcopy(DEFAULT_CONFIG)
config["climate"]["aux_state_topic"] = "aux-state"
assert await async_setup_component(hass, CLIMATE_DOMAIN, config)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
state = hass.states.get(ENTITY_CLIMATE)
assert state.attributes.get("aux_heat") == "off"
@ -979,10 +1025,11 @@ async def test_set_aux_pessimistic(hass, mqtt_mock):
assert state.attributes.get("aux_heat") == "off"
async def test_set_aux(hass, mqtt_mock):
async def test_set_aux(hass, mqtt_mock_entry_with_yaml_config):
"""Test setting of the aux heating."""
assert await async_setup_component(hass, CLIMATE_DOMAIN, DEFAULT_CONFIG)
await hass.async_block_till_done()
mqtt_mock = await mqtt_mock_entry_with_yaml_config()
state = hass.states.get(ENTITY_CLIMATE)
assert state.attributes.get("aux_heat") == "off"
@ -998,35 +1045,39 @@ async def test_set_aux(hass, mqtt_mock):
assert state.attributes.get("aux_heat") == "off"
async def test_availability_when_connection_lost(hass, mqtt_mock):
async def test_availability_when_connection_lost(
hass, mqtt_mock_entry_with_yaml_config
):
"""Test availability after MQTT disconnection."""
await help_test_availability_when_connection_lost(
hass, mqtt_mock, CLIMATE_DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_with_yaml_config, CLIMATE_DOMAIN, DEFAULT_CONFIG
)
async def test_availability_without_topic(hass, mqtt_mock):
async def test_availability_without_topic(hass, mqtt_mock_entry_with_yaml_config):
"""Test availability without defined availability topic."""
await help_test_availability_without_topic(
hass, mqtt_mock, CLIMATE_DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_with_yaml_config, CLIMATE_DOMAIN, DEFAULT_CONFIG
)
async def test_default_availability_payload(hass, mqtt_mock):
async def test_default_availability_payload(hass, mqtt_mock_entry_with_yaml_config):
"""Test availability by default payload with defined topic."""
await help_test_default_availability_payload(
hass, mqtt_mock, CLIMATE_DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_with_yaml_config, CLIMATE_DOMAIN, DEFAULT_CONFIG
)
async def test_custom_availability_payload(hass, mqtt_mock):
async def test_custom_availability_payload(hass, mqtt_mock_entry_with_yaml_config):
"""Test availability by custom payload with defined topic."""
await help_test_custom_availability_payload(
hass, mqtt_mock, CLIMATE_DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_with_yaml_config, CLIMATE_DOMAIN, DEFAULT_CONFIG
)
async def test_get_target_temperature_low_high_with_templates(hass, mqtt_mock, caplog):
async def test_get_target_temperature_low_high_with_templates(
hass, mqtt_mock_entry_with_yaml_config, caplog
):
"""Test getting temperature high/low with templates."""
config = copy.deepcopy(DEFAULT_CONFIG)
config["climate"]["temperature_low_state_topic"] = "temperature-state"
@ -1036,6 +1087,7 @@ async def test_get_target_temperature_low_high_with_templates(hass, mqtt_mock, c
assert await async_setup_component(hass, CLIMATE_DOMAIN, config)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
state = hass.states.get(ENTITY_CLIMATE)
@ -1060,7 +1112,7 @@ async def test_get_target_temperature_low_high_with_templates(hass, mqtt_mock, c
assert state.attributes.get("target_temp_high") == 1032
async def test_get_with_templates(hass, mqtt_mock, caplog):
async def test_get_with_templates(hass, mqtt_mock_entry_with_yaml_config, caplog):
"""Test getting various attributes with templates."""
config = copy.deepcopy(DEFAULT_CONFIG)
# By default, just unquote the JSON-strings
@ -1081,6 +1133,7 @@ async def test_get_with_templates(hass, mqtt_mock, caplog):
config["climate"]["preset_mode_state_topic"] = "current-preset-mode"
assert await async_setup_component(hass, CLIMATE_DOMAIN, config)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
# Operation Mode
state = hass.states.get(ENTITY_CLIMATE)
@ -1159,7 +1212,9 @@ async def test_get_with_templates(hass, mqtt_mock, caplog):
# AWAY and HOLD mode topics and templates are deprecated, support will be removed with release 2022.9
async def test_get_with_hold_and_away_mode_and_templates(hass, mqtt_mock, caplog):
async def test_get_with_hold_and_away_mode_and_templates(
hass, mqtt_mock_entry_with_yaml_config, caplog
):
"""Test getting various for hold and away mode attributes with templates."""
config = copy.deepcopy(DEFAULT_LEGACY_CONFIG)
config["climate"]["mode_state_topic"] = "mode-state"
@ -1172,6 +1227,7 @@ async def test_get_with_hold_and_away_mode_and_templates(hass, mqtt_mock, caplog
assert await async_setup_component(hass, CLIMATE_DOMAIN, config)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
# Operation Mode
state = hass.states.get(ENTITY_CLIMATE)
@ -1206,7 +1262,7 @@ async def test_get_with_hold_and_away_mode_and_templates(hass, mqtt_mock, caplog
assert state.attributes.get("preset_mode") == "somemode"
async def test_set_and_templates(hass, mqtt_mock, caplog):
async def test_set_and_templates(hass, mqtt_mock_entry_with_yaml_config, caplog):
"""Test setting various attributes with templates."""
config = copy.deepcopy(DEFAULT_CONFIG)
# Create simple templates
@ -1220,6 +1276,7 @@ async def test_set_and_templates(hass, mqtt_mock, caplog):
assert await async_setup_component(hass, CLIMATE_DOMAIN, config)
await hass.async_block_till_done()
mqtt_mock = await mqtt_mock_entry_with_yaml_config()
# Fan Mode
await common.async_set_fan_mode(hass, "high", ENTITY_CLIMATE)
@ -1284,7 +1341,9 @@ async def test_set_and_templates(hass, mqtt_mock, caplog):
# AWAY and HOLD mode topics and templates are deprecated, support will be removed with release 2022.9
async def test_set_with_away_and_hold_modes_and_templates(hass, mqtt_mock, caplog):
async def test_set_with_away_and_hold_modes_and_templates(
hass, mqtt_mock_entry_with_yaml_config, caplog
):
"""Test setting various attributes on hold and away mode with templates."""
config = copy.deepcopy(DEFAULT_LEGACY_CONFIG)
# Create simple templates
@ -1292,6 +1351,7 @@ async def test_set_with_away_and_hold_modes_and_templates(hass, mqtt_mock, caplo
assert await async_setup_component(hass, CLIMATE_DOMAIN, config)
await hass.async_block_till_done()
mqtt_mock = await mqtt_mock_entry_with_yaml_config()
# Hold Mode
await common.async_set_preset_mode(hass, PRESET_ECO, ENTITY_CLIMATE)
@ -1303,13 +1363,14 @@ async def test_set_with_away_and_hold_modes_and_templates(hass, mqtt_mock, caplo
assert state.attributes.get("preset_mode") == PRESET_ECO
async def test_min_temp_custom(hass, mqtt_mock):
async def test_min_temp_custom(hass, mqtt_mock_entry_with_yaml_config):
"""Test a custom min temp."""
config = copy.deepcopy(DEFAULT_CONFIG)
config["climate"]["min_temp"] = 26
assert await async_setup_component(hass, CLIMATE_DOMAIN, config)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
state = hass.states.get(ENTITY_CLIMATE)
min_temp = state.attributes.get("min_temp")
@ -1318,13 +1379,14 @@ async def test_min_temp_custom(hass, mqtt_mock):
assert state.attributes.get("min_temp") == 26
async def test_max_temp_custom(hass, mqtt_mock):
async def test_max_temp_custom(hass, mqtt_mock_entry_with_yaml_config):
"""Test a custom max temp."""
config = copy.deepcopy(DEFAULT_CONFIG)
config["climate"]["max_temp"] = 60
assert await async_setup_component(hass, CLIMATE_DOMAIN, config)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
state = hass.states.get(ENTITY_CLIMATE)
max_temp = state.attributes.get("max_temp")
@ -1333,13 +1395,14 @@ async def test_max_temp_custom(hass, mqtt_mock):
assert max_temp == 60
async def test_temp_step_custom(hass, mqtt_mock):
async def test_temp_step_custom(hass, mqtt_mock_entry_with_yaml_config):
"""Test a custom temp step."""
config = copy.deepcopy(DEFAULT_CONFIG)
config["climate"]["temp_step"] = 0.01
assert await async_setup_component(hass, CLIMATE_DOMAIN, config)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
state = hass.states.get(ENTITY_CLIMATE)
temp_step = state.attributes.get("target_temp_step")
@ -1348,7 +1411,7 @@ async def test_temp_step_custom(hass, mqtt_mock):
assert temp_step == 0.01
async def test_temperature_unit(hass, mqtt_mock):
async def test_temperature_unit(hass, mqtt_mock_entry_with_yaml_config):
"""Test that setting temperature unit converts temperature values."""
config = copy.deepcopy(DEFAULT_CONFIG)
config["climate"]["temperature_unit"] = "F"
@ -1356,6 +1419,7 @@ async def test_temperature_unit(hass, mqtt_mock):
assert await async_setup_component(hass, CLIMATE_DOMAIN, config)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
async_fire_mqtt_message(hass, "current_temperature", "77")
@ -1363,49 +1427,61 @@ async def test_temperature_unit(hass, mqtt_mock):
assert state.attributes.get("current_temperature") == 25
async def test_setting_attribute_via_mqtt_json_message(hass, mqtt_mock):
async def test_setting_attribute_via_mqtt_json_message(
hass, mqtt_mock_entry_with_yaml_config
):
"""Test the setting of attribute via MQTT with JSON payload."""
await help_test_setting_attribute_via_mqtt_json_message(
hass, mqtt_mock, CLIMATE_DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_with_yaml_config, CLIMATE_DOMAIN, DEFAULT_CONFIG
)
async def test_setting_blocked_attribute_via_mqtt_json_message(hass, mqtt_mock):
async def test_setting_blocked_attribute_via_mqtt_json_message(
hass, mqtt_mock_entry_no_yaml_config
):
"""Test the setting of attribute via MQTT with JSON payload."""
await help_test_setting_blocked_attribute_via_mqtt_json_message(
hass, mqtt_mock, CLIMATE_DOMAIN, DEFAULT_CONFIG, MQTT_CLIMATE_ATTRIBUTES_BLOCKED
hass,
mqtt_mock_entry_no_yaml_config,
CLIMATE_DOMAIN,
DEFAULT_CONFIG,
MQTT_CLIMATE_ATTRIBUTES_BLOCKED,
)
async def test_setting_attribute_with_template(hass, mqtt_mock):
async def test_setting_attribute_with_template(hass, mqtt_mock_entry_with_yaml_config):
"""Test the setting of attribute via MQTT with JSON payload."""
await help_test_setting_attribute_with_template(
hass, mqtt_mock, CLIMATE_DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_with_yaml_config, CLIMATE_DOMAIN, DEFAULT_CONFIG
)
async def test_update_with_json_attrs_not_dict(hass, mqtt_mock, caplog):
async def test_update_with_json_attrs_not_dict(
hass, mqtt_mock_entry_with_yaml_config, caplog
):
"""Test attributes get extracted from a JSON result."""
await help_test_update_with_json_attrs_not_dict(
hass, mqtt_mock, caplog, CLIMATE_DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_with_yaml_config, caplog, CLIMATE_DOMAIN, DEFAULT_CONFIG
)
async def test_update_with_json_attrs_bad_JSON(hass, mqtt_mock, caplog):
async def test_update_with_json_attrs_bad_JSON(
hass, mqtt_mock_entry_with_yaml_config, caplog
):
"""Test attributes get extracted from a JSON result."""
await help_test_update_with_json_attrs_bad_JSON(
hass, mqtt_mock, caplog, CLIMATE_DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_with_yaml_config, caplog, CLIMATE_DOMAIN, DEFAULT_CONFIG
)
async def test_discovery_update_attr(hass, mqtt_mock, caplog):
async def test_discovery_update_attr(hass, mqtt_mock_entry_no_yaml_config, caplog):
"""Test update of discovered MQTTAttributes."""
await help_test_discovery_update_attr(
hass, mqtt_mock, caplog, CLIMATE_DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_no_yaml_config, caplog, CLIMATE_DOMAIN, DEFAULT_CONFIG
)
async def test_unique_id(hass, mqtt_mock):
async def test_unique_id(hass, mqtt_mock_entry_with_yaml_config):
"""Test unique id option only creates one climate per unique_id."""
config = {
CLIMATE_DOMAIN: [
@ -1425,7 +1501,9 @@ async def test_unique_id(hass, mqtt_mock):
},
]
}
await help_test_unique_id(hass, mqtt_mock, CLIMATE_DOMAIN, config)
await help_test_unique_id(
hass, mqtt_mock_entry_with_yaml_config, CLIMATE_DOMAIN, config
)
@pytest.mark.parametrize(
@ -1449,7 +1527,13 @@ async def test_unique_id(hass, mqtt_mock):
],
)
async def test_encoding_subscribable_topics(
hass, mqtt_mock, caplog, topic, value, attribute, attribute_value
hass,
mqtt_mock_entry_with_yaml_config,
caplog,
topic,
value,
attribute,
attribute_value,
):
"""Test handling of incoming encoded payload."""
config = copy.deepcopy(DEFAULT_CONFIG[CLIMATE_DOMAIN])
@ -1460,7 +1544,7 @@ async def test_encoding_subscribable_topics(
del config["preset_mode_command_topic"]
await help_test_encoding_subscribable_topics(
hass,
mqtt_mock,
mqtt_mock_entry_with_yaml_config,
caplog,
CLIMATE_DOMAIN,
config,
@ -1471,71 +1555,80 @@ async def test_encoding_subscribable_topics(
)
async def test_discovery_removal_climate(hass, mqtt_mock, caplog):
async def test_discovery_removal_climate(hass, mqtt_mock_entry_no_yaml_config, caplog):
"""Test removal of discovered climate."""
data = json.dumps(DEFAULT_CONFIG[CLIMATE_DOMAIN])
await help_test_discovery_removal(hass, mqtt_mock, caplog, CLIMATE_DOMAIN, data)
await help_test_discovery_removal(
hass, mqtt_mock_entry_no_yaml_config, caplog, CLIMATE_DOMAIN, data
)
async def test_discovery_update_climate(hass, mqtt_mock, caplog):
async def test_discovery_update_climate(hass, mqtt_mock_entry_no_yaml_config, caplog):
"""Test update of discovered climate."""
config1 = {"name": "Beer"}
config2 = {"name": "Milk"}
await help_test_discovery_update(
hass, mqtt_mock, caplog, CLIMATE_DOMAIN, config1, config2
hass, mqtt_mock_entry_no_yaml_config, caplog, CLIMATE_DOMAIN, config1, config2
)
async def test_discovery_update_unchanged_climate(hass, mqtt_mock, caplog):
async def test_discovery_update_unchanged_climate(
hass, mqtt_mock_entry_no_yaml_config, caplog
):
"""Test update of discovered climate."""
data1 = '{ "name": "Beer" }'
with patch(
"homeassistant.components.mqtt.climate.MqttClimate.discovery_update"
) as discovery_update:
await help_test_discovery_update_unchanged(
hass, mqtt_mock, caplog, CLIMATE_DOMAIN, data1, discovery_update
hass,
mqtt_mock_entry_no_yaml_config,
caplog,
CLIMATE_DOMAIN,
data1,
discovery_update,
)
@pytest.mark.no_fail_on_log_exception
async def test_discovery_broken(hass, mqtt_mock, caplog):
async def test_discovery_broken(hass, mqtt_mock_entry_no_yaml_config, caplog):
"""Test handling of bad discovery message."""
data1 = '{ "name": "Beer", "power_command_topic": "test_topic#" }'
data2 = '{ "name": "Milk", "power_command_topic": "test_topic" }'
await help_test_discovery_broken(
hass, mqtt_mock, caplog, CLIMATE_DOMAIN, data1, data2
hass, mqtt_mock_entry_no_yaml_config, caplog, CLIMATE_DOMAIN, data1, data2
)
async def test_entity_device_info_with_connection(hass, mqtt_mock):
async def test_entity_device_info_with_connection(hass, mqtt_mock_entry_no_yaml_config):
"""Test MQTT climate device registry integration."""
await help_test_entity_device_info_with_connection(
hass, mqtt_mock, CLIMATE_DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_no_yaml_config, CLIMATE_DOMAIN, DEFAULT_CONFIG
)
async def test_entity_device_info_with_identifier(hass, mqtt_mock):
async def test_entity_device_info_with_identifier(hass, mqtt_mock_entry_no_yaml_config):
"""Test MQTT climate device registry integration."""
await help_test_entity_device_info_with_identifier(
hass, mqtt_mock, CLIMATE_DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_no_yaml_config, CLIMATE_DOMAIN, DEFAULT_CONFIG
)
async def test_entity_device_info_update(hass, mqtt_mock):
async def test_entity_device_info_update(hass, mqtt_mock_entry_no_yaml_config):
"""Test device registry update."""
await help_test_entity_device_info_update(
hass, mqtt_mock, CLIMATE_DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_no_yaml_config, CLIMATE_DOMAIN, DEFAULT_CONFIG
)
async def test_entity_device_info_remove(hass, mqtt_mock):
async def test_entity_device_info_remove(hass, mqtt_mock_entry_no_yaml_config):
"""Test device registry remove."""
await help_test_entity_device_info_remove(
hass, mqtt_mock, CLIMATE_DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_no_yaml_config, CLIMATE_DOMAIN, DEFAULT_CONFIG
)
async def test_entity_id_update_subscriptions(hass, mqtt_mock):
async def test_entity_id_update_subscriptions(hass, mqtt_mock_entry_with_yaml_config):
"""Test MQTT subscriptions are managed when entity_id is updated."""
config = {
CLIMATE_DOMAIN: {
@ -1546,18 +1639,22 @@ async def test_entity_id_update_subscriptions(hass, mqtt_mock):
}
}
await help_test_entity_id_update_subscriptions(
hass, mqtt_mock, CLIMATE_DOMAIN, config, ["test-topic", "avty-topic"]
hass,
mqtt_mock_entry_with_yaml_config,
CLIMATE_DOMAIN,
config,
["test-topic", "avty-topic"],
)
async def test_entity_id_update_discovery_update(hass, mqtt_mock):
async def test_entity_id_update_discovery_update(hass, mqtt_mock_entry_no_yaml_config):
"""Test MQTT discovery update when entity_id is updated."""
await help_test_entity_id_update_discovery_update(
hass, mqtt_mock, CLIMATE_DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_no_yaml_config, CLIMATE_DOMAIN, DEFAULT_CONFIG
)
async def test_entity_debug_info_message(hass, mqtt_mock):
async def test_entity_debug_info_message(hass, mqtt_mock_entry_no_yaml_config):
"""Test MQTT debug info."""
config = {
CLIMATE_DOMAIN: {
@ -1569,7 +1666,7 @@ async def test_entity_debug_info_message(hass, mqtt_mock):
}
await help_test_entity_debug_info_message(
hass,
mqtt_mock,
mqtt_mock_entry_no_yaml_config,
CLIMATE_DOMAIN,
config,
climate.SERVICE_TURN_ON,
@ -1579,10 +1676,11 @@ async def test_entity_debug_info_message(hass, mqtt_mock):
)
async def test_precision_default(hass, mqtt_mock):
async def test_precision_default(hass, mqtt_mock_entry_with_yaml_config):
"""Test that setting precision to tenths works as intended."""
assert await async_setup_component(hass, CLIMATE_DOMAIN, DEFAULT_CONFIG)
await hass.async_block_till_done()
mqtt_mock = await mqtt_mock_entry_with_yaml_config()
await common.async_set_temperature(
hass, temperature=23.67, entity_id=ENTITY_CLIMATE
@ -1592,12 +1690,13 @@ async def test_precision_default(hass, mqtt_mock):
mqtt_mock.async_publish.reset_mock()
async def test_precision_halves(hass, mqtt_mock):
async def test_precision_halves(hass, mqtt_mock_entry_with_yaml_config):
"""Test that setting precision to halves works as intended."""
config = copy.deepcopy(DEFAULT_CONFIG)
config["climate"]["precision"] = 0.5
assert await async_setup_component(hass, CLIMATE_DOMAIN, config)
await hass.async_block_till_done()
mqtt_mock = await mqtt_mock_entry_with_yaml_config()
await common.async_set_temperature(
hass, temperature=23.67, entity_id=ENTITY_CLIMATE
@ -1607,12 +1706,13 @@ async def test_precision_halves(hass, mqtt_mock):
mqtt_mock.async_publish.reset_mock()
async def test_precision_whole(hass, mqtt_mock):
async def test_precision_whole(hass, mqtt_mock_entry_with_yaml_config):
"""Test that setting precision to whole works as intended."""
config = copy.deepcopy(DEFAULT_CONFIG)
config["climate"]["precision"] = 1.0
assert await async_setup_component(hass, CLIMATE_DOMAIN, config)
await hass.async_block_till_done()
mqtt_mock = await mqtt_mock_entry_with_yaml_config()
await common.async_set_temperature(
hass, temperature=23.67, entity_id=ENTITY_CLIMATE
@ -1721,7 +1821,7 @@ async def test_precision_whole(hass, mqtt_mock):
)
async def test_publishing_with_custom_encoding(
hass,
mqtt_mock,
mqtt_mock_entry_with_yaml_config,
caplog,
service,
topic,
@ -1738,7 +1838,7 @@ async def test_publishing_with_custom_encoding(
await help_test_publishing_with_custom_encoding(
hass,
mqtt_mock,
mqtt_mock_entry_with_yaml_config,
caplog,
domain,
config,
@ -1750,11 +1850,13 @@ async def test_publishing_with_custom_encoding(
)
async def test_reloadable(hass, mqtt_mock, caplog, tmp_path):
async def test_reloadable(hass, mqtt_mock_entry_with_yaml_config, caplog, tmp_path):
"""Test reloading the MQTT platform."""
domain = CLIMATE_DOMAIN
config = DEFAULT_CONFIG[domain]
await help_test_reloadable(hass, mqtt_mock, caplog, tmp_path, domain, config)
await help_test_reloadable(
hass, mqtt_mock_entry_with_yaml_config, caplog, tmp_path, domain, config
)
async def test_reloadable_late(hass, mqtt_client_mock, caplog, tmp_path):

View File

@ -46,10 +46,13 @@ DEFAULT_CONFIG_DEVICE_INFO_MAC = {
_SENTINEL = object()
async def help_test_availability_when_connection_lost(hass, mqtt_mock, domain, config):
async def help_test_availability_when_connection_lost(
hass, mqtt_mock_entry_with_yaml_config, domain, config
):
"""Test availability after MQTT disconnection."""
assert await async_setup_component(hass, domain, config)
await hass.async_block_till_done()
mqtt_mock = await mqtt_mock_entry_with_yaml_config()
state = hass.states.get(f"{domain}.test")
assert state.state != STATE_UNAVAILABLE
@ -62,11 +65,14 @@ async def help_test_availability_when_connection_lost(hass, mqtt_mock, domain, c
assert state.state == STATE_UNAVAILABLE
async def help_test_availability_without_topic(hass, mqtt_mock, domain, config):
async def help_test_availability_without_topic(
hass, mqtt_mock_entry_with_yaml_config, domain, config
):
"""Test availability without defined availability topic."""
assert "availability_topic" not in config[domain]
assert await async_setup_component(hass, domain, config)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
state = hass.states.get(f"{domain}.test")
assert state.state != STATE_UNAVAILABLE
@ -74,7 +80,7 @@ async def help_test_availability_without_topic(hass, mqtt_mock, domain, config):
async def help_test_default_availability_payload(
hass,
mqtt_mock,
mqtt_mock_entry_with_yaml_config,
domain,
config,
no_assumed_state=False,
@ -94,6 +100,7 @@ async def help_test_default_availability_payload(
config,
)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
state = hass.states.get(f"{domain}.test")
assert state.state == STATE_UNAVAILABLE
@ -124,7 +131,7 @@ async def help_test_default_availability_payload(
async def help_test_default_availability_list_payload(
hass,
mqtt_mock,
mqtt_mock_entry_with_yaml_config,
domain,
config,
no_assumed_state=False,
@ -147,6 +154,7 @@ async def help_test_default_availability_list_payload(
config,
)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
state = hass.states.get(f"{domain}.test")
assert state.state == STATE_UNAVAILABLE
@ -189,7 +197,7 @@ async def help_test_default_availability_list_payload(
async def help_test_default_availability_list_payload_all(
hass,
mqtt_mock,
mqtt_mock_entry_with_yaml_config,
domain,
config,
no_assumed_state=False,
@ -213,6 +221,7 @@ async def help_test_default_availability_list_payload_all(
config,
)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
state = hass.states.get(f"{domain}.test")
assert state.state == STATE_UNAVAILABLE
@ -256,7 +265,7 @@ async def help_test_default_availability_list_payload_all(
async def help_test_default_availability_list_payload_any(
hass,
mqtt_mock,
mqtt_mock_entry_with_yaml_config,
domain,
config,
no_assumed_state=False,
@ -280,6 +289,7 @@ async def help_test_default_availability_list_payload_any(
config,
)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
state = hass.states.get(f"{domain}.test")
assert state.state == STATE_UNAVAILABLE
@ -318,7 +328,7 @@ async def help_test_default_availability_list_payload_any(
async def help_test_default_availability_list_single(
hass,
mqtt_mock,
mqtt_mock_entry_with_yaml_config,
caplog,
domain,
config,
@ -342,6 +352,7 @@ async def help_test_default_availability_list_single(
config,
)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
state = hass.states.get(f"{domain}.test")
assert state is None
@ -353,7 +364,7 @@ async def help_test_default_availability_list_single(
async def help_test_custom_availability_payload(
hass,
mqtt_mock,
mqtt_mock_entry_with_yaml_config,
domain,
config,
no_assumed_state=False,
@ -375,6 +386,7 @@ async def help_test_custom_availability_payload(
config,
)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
state = hass.states.get(f"{domain}.test")
assert state.state == STATE_UNAVAILABLE
@ -405,7 +417,7 @@ async def help_test_custom_availability_payload(
async def help_test_discovery_update_availability(
hass,
mqtt_mock,
mqtt_mock_entry_no_yaml_config,
domain,
config,
no_assumed_state=False,
@ -416,6 +428,7 @@ async def help_test_discovery_update_availability(
This is a test helper for the MQTTAvailability mixin.
"""
await mqtt_mock_entry_no_yaml_config()
# Add availability settings to config
config1 = copy.deepcopy(config)
config1[domain]["availability_topic"] = "availability-topic1"
@ -484,7 +497,7 @@ async def help_test_discovery_update_availability(
async def help_test_setting_attribute_via_mqtt_json_message(
hass, mqtt_mock, domain, config
hass, mqtt_mock_entry_with_yaml_config, domain, config
):
"""Test the setting of attribute via MQTT with JSON payload.
@ -499,6 +512,7 @@ async def help_test_setting_attribute_via_mqtt_json_message(
config,
)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
async_fire_mqtt_message(hass, "attr-topic", '{ "val": "100" }')
state = hass.states.get(f"{domain}.test")
@ -507,12 +521,13 @@ async def help_test_setting_attribute_via_mqtt_json_message(
async def help_test_setting_blocked_attribute_via_mqtt_json_message(
hass, mqtt_mock, domain, config, extra_blocked_attributes
hass, mqtt_mock_entry_no_yaml_config, domain, config, extra_blocked_attributes
):
"""Test the setting of blocked attribute via MQTT with JSON payload.
This is a test helper for the MqttAttributes mixin.
"""
await mqtt_mock_entry_no_yaml_config()
extra_blocked_attributes = extra_blocked_attributes or []
# Add JSON attributes settings to config
@ -534,7 +549,9 @@ async def help_test_setting_blocked_attribute_via_mqtt_json_message(
assert state.attributes.get(attr) != val
async def help_test_setting_attribute_with_template(hass, mqtt_mock, domain, config):
async def help_test_setting_attribute_with_template(
hass, mqtt_mock_entry_with_yaml_config, domain, config
):
"""Test the setting of attribute via MQTT with JSON payload.
This is a test helper for the MqttAttributes mixin.
@ -549,6 +566,7 @@ async def help_test_setting_attribute_with_template(hass, mqtt_mock, domain, con
config,
)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
async_fire_mqtt_message(
hass, "attr-topic", json.dumps({"Timer1": {"Arm": 0, "Time": "22:18"}})
@ -560,7 +578,7 @@ async def help_test_setting_attribute_with_template(hass, mqtt_mock, domain, con
async def help_test_update_with_json_attrs_not_dict(
hass, mqtt_mock, caplog, domain, config
hass, mqtt_mock_entry_with_yaml_config, caplog, domain, config
):
"""Test attributes get extracted from a JSON result.
@ -575,6 +593,7 @@ async def help_test_update_with_json_attrs_not_dict(
config,
)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
async_fire_mqtt_message(hass, "attr-topic", '[ "list", "of", "things"]')
state = hass.states.get(f"{domain}.test")
@ -584,7 +603,7 @@ async def help_test_update_with_json_attrs_not_dict(
async def help_test_update_with_json_attrs_bad_JSON(
hass, mqtt_mock, caplog, domain, config
hass, mqtt_mock_entry_with_yaml_config, caplog, domain, config
):
"""Test JSON validation of attributes.
@ -599,6 +618,7 @@ async def help_test_update_with_json_attrs_bad_JSON(
config,
)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
async_fire_mqtt_message(hass, "attr-topic", "This is not JSON")
@ -607,11 +627,14 @@ async def help_test_update_with_json_attrs_bad_JSON(
assert "Erroneous JSON: This is not JSON" in caplog.text
async def help_test_discovery_update_attr(hass, mqtt_mock, caplog, domain, config):
async def help_test_discovery_update_attr(
hass, mqtt_mock_entry_no_yaml_config, caplog, domain, config
):
"""Test update of discovered MQTTAttributes.
This is a test helper for the MqttAttributes mixin.
"""
await mqtt_mock_entry_no_yaml_config()
# Add JSON attributes settings to config
config1 = copy.deepcopy(config)
config1[domain]["json_attributes_topic"] = "attr-topic1"
@ -641,18 +664,22 @@ async def help_test_discovery_update_attr(hass, mqtt_mock, caplog, domain, confi
assert state.attributes.get("val") == "75"
async def help_test_unique_id(hass, mqtt_mock, domain, config):
async def help_test_unique_id(hass, mqtt_mock_entry_with_yaml_config, domain, config):
"""Test unique id option only creates one entity per unique_id."""
assert await async_setup_component(hass, domain, config)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
assert len(hass.states.async_entity_ids(domain)) == 1
async def help_test_discovery_removal(hass, mqtt_mock, caplog, domain, data):
async def help_test_discovery_removal(
hass, mqtt_mock_entry_no_yaml_config, caplog, domain, data
):
"""Test removal of discovered component.
This is a test helper for the MqttDiscoveryUpdate mixin.
"""
await mqtt_mock_entry_no_yaml_config()
async_fire_mqtt_message(hass, f"homeassistant/{domain}/bla/config", data)
await hass.async_block_till_done()
@ -669,7 +696,7 @@ async def help_test_discovery_removal(hass, mqtt_mock, caplog, domain, data):
async def help_test_discovery_update(
hass,
mqtt_mock,
mqtt_mock_entry_no_yaml_config,
caplog,
domain,
discovery_config1,
@ -681,6 +708,7 @@ async def help_test_discovery_update(
This is a test helper for the MqttDiscoveryUpdate mixin.
"""
await mqtt_mock_entry_no_yaml_config()
# Add some future configuration to the configurations
config1 = copy.deepcopy(discovery_config1)
config1["some_future_option_1"] = "future_option_1"
@ -730,12 +758,13 @@ async def help_test_discovery_update(
async def help_test_discovery_update_unchanged(
hass, mqtt_mock, caplog, domain, data1, discovery_update
hass, mqtt_mock_entry_no_yaml_config, caplog, domain, data1, discovery_update
):
"""Test update of discovered component without changes.
This is a test helper for the MqttDiscoveryUpdate mixin.
"""
await mqtt_mock_entry_no_yaml_config()
async_fire_mqtt_message(hass, f"homeassistant/{domain}/bla/config", data1)
await hass.async_block_till_done()
@ -749,8 +778,11 @@ async def help_test_discovery_update_unchanged(
assert not discovery_update.called
async def help_test_discovery_broken(hass, mqtt_mock, caplog, domain, data1, data2):
async def help_test_discovery_broken(
hass, mqtt_mock_entry_no_yaml_config, caplog, domain, data1, data2
):
"""Test handling of bad discovery message."""
await mqtt_mock_entry_no_yaml_config()
async_fire_mqtt_message(hass, f"homeassistant/{domain}/bla/config", data1)
await hass.async_block_till_done()
@ -769,7 +801,7 @@ async def help_test_discovery_broken(hass, mqtt_mock, caplog, domain, data1, dat
async def help_test_encoding_subscribable_topics(
hass,
mqtt_mock,
mqtt_mock_entry_with_yaml_config,
caplog,
domain,
config,
@ -849,6 +881,7 @@ async def help_test_encoding_subscribable_topics(
hass, domain, {domain: [config1, config2, config3]}
)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
expected_result = attribute_value or value
@ -899,11 +932,14 @@ async def help_test_encoding_subscribable_topics(
pass
async def help_test_entity_device_info_with_identifier(hass, mqtt_mock, domain, config):
async def help_test_entity_device_info_with_identifier(
hass, mqtt_mock_entry_no_yaml_config, domain, config
):
"""Test device registry integration.
This is a test helper for the MqttDiscoveryUpdate mixin.
"""
await mqtt_mock_entry_no_yaml_config()
# Add device settings to config
config = copy.deepcopy(config[domain])
config["device"] = copy.deepcopy(DEFAULT_CONFIG_DEVICE_INFO_ID)
@ -926,11 +962,14 @@ async def help_test_entity_device_info_with_identifier(hass, mqtt_mock, domain,
assert device.configuration_url == "http://example.com"
async def help_test_entity_device_info_with_connection(hass, mqtt_mock, domain, config):
async def help_test_entity_device_info_with_connection(
hass, mqtt_mock_entry_no_yaml_config, domain, config
):
"""Test device registry integration.
This is a test helper for the MqttDiscoveryUpdate mixin.
"""
await mqtt_mock_entry_no_yaml_config()
# Add device settings to config
config = copy.deepcopy(config[domain])
config["device"] = copy.deepcopy(DEFAULT_CONFIG_DEVICE_INFO_MAC)
@ -955,8 +994,11 @@ async def help_test_entity_device_info_with_connection(hass, mqtt_mock, domain,
assert device.configuration_url == "http://example.com"
async def help_test_entity_device_info_remove(hass, mqtt_mock, domain, config):
async def help_test_entity_device_info_remove(
hass, mqtt_mock_entry_no_yaml_config, domain, config
):
"""Test device registry remove."""
await mqtt_mock_entry_no_yaml_config()
# Add device settings to config
config = copy.deepcopy(config[domain])
config["device"] = copy.deepcopy(DEFAULT_CONFIG_DEVICE_INFO_ID)
@ -981,11 +1023,14 @@ async def help_test_entity_device_info_remove(hass, mqtt_mock, domain, config):
assert not ent_registry.async_get_entity_id(domain, mqtt.DOMAIN, "veryunique")
async def help_test_entity_device_info_update(hass, mqtt_mock, domain, config):
async def help_test_entity_device_info_update(
hass, mqtt_mock_entry_no_yaml_config, domain, config
):
"""Test device registry update.
This is a test helper for the MqttDiscoveryUpdate mixin.
"""
await mqtt_mock_entry_no_yaml_config()
# Add device settings to config
config = copy.deepcopy(config[domain])
config["device"] = copy.deepcopy(DEFAULT_CONFIG_DEVICE_INFO_ID)
@ -1012,7 +1057,7 @@ async def help_test_entity_device_info_update(hass, mqtt_mock, domain, config):
async def help_test_entity_id_update_subscriptions(
hass, mqtt_mock, domain, config, topics=None
hass, mqtt_mock_entry_with_yaml_config, domain, config, topics=None
):
"""Test MQTT subscriptions are managed when entity_id is updated."""
# Add unique_id to config
@ -1026,16 +1071,18 @@ async def help_test_entity_id_update_subscriptions(
topics = ["avty-topic", "test-topic"]
assert len(topics) > 0
registry = mock_registry(hass, {})
assert await async_setup_component(
hass,
domain,
config,
)
await hass.async_block_till_done()
mqtt_mock = await mqtt_mock_entry_with_yaml_config()
state = hass.states.get(f"{domain}.test")
assert state is not None
assert mqtt_mock.async_subscribe.call_count == len(topics)
assert mqtt_mock.async_subscribe.call_count == len(topics) + 3
for topic in topics:
mqtt_mock.async_subscribe.assert_any_call(topic, ANY, ANY, ANY)
mqtt_mock.async_subscribe.reset_mock()
@ -1053,10 +1100,11 @@ async def help_test_entity_id_update_subscriptions(
async def help_test_entity_id_update_discovery_update(
hass, mqtt_mock, domain, config, topic=None
hass, mqtt_mock_entry_no_yaml_config, domain, config, topic=None
):
"""Test MQTT discovery update after entity_id is updated."""
# Add unique_id to config
await mqtt_mock_entry_no_yaml_config()
config = copy.deepcopy(config)
config[domain]["unique_id"] = "TOTALLY_UNIQUE"
@ -1093,11 +1141,14 @@ async def help_test_entity_id_update_discovery_update(
assert state.state != STATE_UNAVAILABLE
async def help_test_entity_debug_info(hass, mqtt_mock, domain, config):
async def help_test_entity_debug_info(
hass, mqtt_mock_entry_no_yaml_config, domain, config
):
"""Test debug_info.
This is a test helper for MQTT debug_info.
"""
await mqtt_mock_entry_no_yaml_config()
# Add device settings to config
config = copy.deepcopy(config[domain])
config["device"] = copy.deepcopy(DEFAULT_CONFIG_DEVICE_INFO_ID)
@ -1127,11 +1178,14 @@ async def help_test_entity_debug_info(hass, mqtt_mock, domain, config):
assert len(debug_info_data["triggers"]) == 0
async def help_test_entity_debug_info_max_messages(hass, mqtt_mock, domain, config):
async def help_test_entity_debug_info_max_messages(
hass, mqtt_mock_entry_no_yaml_config, domain, config
):
"""Test debug_info message overflow.
This is a test helper for MQTT debug_info.
"""
await mqtt_mock_entry_no_yaml_config()
# Add device settings to config
config = copy.deepcopy(config[domain])
config["device"] = copy.deepcopy(DEFAULT_CONFIG_DEVICE_INFO_ID)
@ -1181,7 +1235,7 @@ async def help_test_entity_debug_info_max_messages(hass, mqtt_mock, domain, conf
async def help_test_entity_debug_info_message(
hass,
mqtt_mock,
mqtt_mock_entry_no_yaml_config,
domain,
config,
service,
@ -1196,6 +1250,7 @@ async def help_test_entity_debug_info_message(
This is a test helper for MQTT debug_info.
"""
# Add device settings to config
await mqtt_mock_entry_no_yaml_config()
config = copy.deepcopy(config[domain])
config["device"] = copy.deepcopy(DEFAULT_CONFIG_DEVICE_INFO_ID)
config["unique_id"] = "veryunique"
@ -1290,11 +1345,14 @@ async def help_test_entity_debug_info_message(
assert debug_info_data["entities"][0]["transmitted"] == expected_transmissions
async def help_test_entity_debug_info_remove(hass, mqtt_mock, domain, config):
async def help_test_entity_debug_info_remove(
hass, mqtt_mock_entry_no_yaml_config, domain, config
):
"""Test debug_info.
This is a test helper for MQTT debug_info.
"""
await mqtt_mock_entry_no_yaml_config()
# Add device settings to config
config = copy.deepcopy(config[domain])
config["device"] = copy.deepcopy(DEFAULT_CONFIG_DEVICE_INFO_ID)
@ -1333,11 +1391,14 @@ async def help_test_entity_debug_info_remove(hass, mqtt_mock, domain, config):
assert entity_id not in hass.data[debug_info.DATA_MQTT_DEBUG_INFO]["entities"]
async def help_test_entity_debug_info_update_entity_id(hass, mqtt_mock, domain, config):
async def help_test_entity_debug_info_update_entity_id(
hass, mqtt_mock_entry_no_yaml_config, domain, config
):
"""Test debug_info.
This is a test helper for MQTT debug_info.
"""
await mqtt_mock_entry_no_yaml_config()
# Add device settings to config
config = copy.deepcopy(config[domain])
config["device"] = copy.deepcopy(DEFAULT_CONFIG_DEVICE_INFO_ID)
@ -1389,8 +1450,11 @@ async def help_test_entity_debug_info_update_entity_id(hass, mqtt_mock, domain,
)
async def help_test_entity_disabled_by_default(hass, mqtt_mock, domain, config):
async def help_test_entity_disabled_by_default(
hass, mqtt_mock_entry_no_yaml_config, domain, config
):
"""Test device registry remove."""
await mqtt_mock_entry_no_yaml_config()
# Add device settings to config
config = copy.deepcopy(config[domain])
config["device"] = copy.deepcopy(DEFAULT_CONFIG_DEVICE_INFO_ID)
@ -1425,8 +1489,11 @@ async def help_test_entity_disabled_by_default(hass, mqtt_mock, domain, config):
assert not dev_registry.async_get_device({("mqtt", "helloworld")})
async def help_test_entity_category(hass, mqtt_mock, domain, config):
async def help_test_entity_category(
hass, mqtt_mock_entry_no_yaml_config, domain, config
):
"""Test device registry remove."""
await mqtt_mock_entry_no_yaml_config()
# Add device settings to config
config = copy.deepcopy(config[domain])
config["device"] = copy.deepcopy(DEFAULT_CONFIG_DEVICE_INFO_ID)
@ -1468,7 +1535,7 @@ async def help_test_entity_category(hass, mqtt_mock, domain, config):
async def help_test_publishing_with_custom_encoding(
hass,
mqtt_mock,
mqtt_mock_entry_with_yaml_config,
caplog,
domain,
config,
@ -1519,6 +1586,7 @@ async def help_test_publishing_with_custom_encoding(
{domain: setup_config},
)
await hass.async_block_till_done()
mqtt_mock = await mqtt_mock_entry_with_yaml_config()
# 1) test with default encoding
await hass.services.async_call(
@ -1583,10 +1651,10 @@ async def help_test_publishing_with_custom_encoding(
mqtt_mock.async_publish.reset_mock()
async def help_test_reload_with_config(hass, caplog, tmp_path, domain, config):
async def help_test_reload_with_config(hass, caplog, tmp_path, config):
"""Test reloading with supplied config."""
new_yaml_config_file = tmp_path / "configuration.yaml"
new_yaml_config = yaml.dump({domain: config})
new_yaml_config = yaml.dump(config)
new_yaml_config_file.write_text(new_yaml_config)
assert new_yaml_config_file.read_text() == new_yaml_config
@ -1602,22 +1670,36 @@ async def help_test_reload_with_config(hass, caplog, tmp_path, domain, config):
assert "<Event event_mqtt_reloaded[L]>" in caplog.text
async def help_test_reloadable(hass, mqtt_mock, caplog, tmp_path, domain, config):
async def help_test_reloadable(
hass, mqtt_mock_entry_with_yaml_config, caplog, tmp_path, domain, config
):
"""Test reloading an MQTT platform."""
# 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_config_3 = copy.deepcopy(config)
old_config_3["name"] = "test_old_3"
old_config_3.pop("platform")
old_config_4 = copy.deepcopy(config)
old_config_4["name"] = "test_old_4"
old_config_4.pop("platform")
assert await async_setup_component(
hass, domain, {domain: [old_config_1, old_config_2]}
)
old_config = {
domain: [old_config_1, old_config_2],
"mqtt": {domain: [old_config_3, old_config_4]},
}
assert await async_setup_component(hass, domain, old_config)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
assert hass.states.get(f"{domain}.test_old_1")
assert hass.states.get(f"{domain}.test_old_2")
assert len(hass.states.async_all(domain)) == 2
assert hass.states.get(f"{domain}.test_old_3")
assert hass.states.get(f"{domain}.test_old_4")
assert len(hass.states.async_all(domain)) == 4
# Create temporary fixture for configuration.yaml based on the supplied config and
# test a reload with this new config
@ -1627,16 +1709,31 @@ async def help_test_reloadable(hass, mqtt_mock, caplog, tmp_path, domain, config
new_config_2["name"] = "test_new_2"
new_config_3 = copy.deepcopy(config)
new_config_3["name"] = "test_new_3"
new_config_3.pop("platform")
new_config_4 = copy.deepcopy(config)
new_config_4["name"] = "test_new_4"
new_config_4.pop("platform")
new_config_5 = copy.deepcopy(config)
new_config_5["name"] = "test_new_5"
new_config_6 = copy.deepcopy(config)
new_config_6["name"] = "test_new_6"
new_config_6.pop("platform")
await help_test_reload_with_config(
hass, caplog, tmp_path, domain, [new_config_1, new_config_2, new_config_3]
)
new_config = {
domain: [new_config_1, new_config_2, new_config_5],
"mqtt": {domain: [new_config_3, new_config_4, new_config_6]},
}
assert len(hass.states.async_all(domain)) == 3
await help_test_reload_with_config(hass, caplog, tmp_path, new_config)
assert len(hass.states.async_all(domain)) == 6
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")
assert hass.states.get(f"{domain}.test_new_4")
assert hass.states.get(f"{domain}.test_new_5")
assert hass.states.get(f"{domain}.test_new_6")
async def help_test_reloadable_late(hass, caplog, tmp_path, domain, config):
@ -1681,9 +1778,10 @@ async def help_test_reloadable_late(hass, caplog, tmp_path, domain, config):
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]
)
new_config = {
domain: [new_config_1, new_config_2, new_config_3],
}
await help_test_reload_with_config(hass, caplog, tmp_path, new_config)
assert len(hass.states.async_all(domain)) == 3

View File

@ -264,8 +264,9 @@ async def test_hassio_confirm(hass, mock_try_connection_success, mock_finish_set
assert len(mock_finish_setup.mock_calls) == 1
async def test_option_flow(hass, mqtt_mock, mock_try_connection):
async def test_option_flow(hass, mqtt_mock_entry_no_yaml_config, mock_try_connection):
"""Test config flow options."""
mqtt_mock = await mqtt_mock_entry_no_yaml_config()
mock_try_connection.return_value = True
config_entry = hass.config_entries.async_entries(mqtt.DOMAIN)[0]
config_entry.data = {
@ -336,8 +337,11 @@ async def test_option_flow(hass, mqtt_mock, mock_try_connection):
assert mqtt_mock.async_connect.call_count == 1
async def test_disable_birth_will(hass, mqtt_mock, mock_try_connection):
async def test_disable_birth_will(
hass, mqtt_mock_entry_no_yaml_config, mock_try_connection
):
"""Test disabling birth and will."""
mqtt_mock = await mqtt_mock_entry_no_yaml_config()
mock_try_connection.return_value = True
config_entry = hass.config_entries.async_entries(mqtt.DOMAIN)[0]
config_entry.data = {
@ -417,9 +421,10 @@ def get_suggested(schema, key):
async def test_option_flow_default_suggested_values(
hass, mqtt_mock, mock_try_connection_success
hass, mqtt_mock_entry_no_yaml_config, mock_try_connection_success
):
"""Test config flow options has default/suggested values."""
await mqtt_mock_entry_no_yaml_config()
config_entry = hass.config_entries.async_entries(mqtt.DOMAIN)[0]
config_entry.data = {
mqtt.CONF_BROKER: "test-broker",

File diff suppressed because it is too large Load Diff

View File

@ -11,7 +11,9 @@ from tests.common import async_fire_mqtt_message
# Deprecated in HA Core 2022.6
async def test_legacy_ensure_device_tracker_platform_validation(hass, mqtt_mock):
async def test_legacy_ensure_device_tracker_platform_validation(
hass, mqtt_mock_entry_with_yaml_config
):
"""Test if platform validation was done."""
async def mock_setup_scanner(hass, config, see, discovery_info=None):
@ -29,12 +31,17 @@ async def test_legacy_ensure_device_tracker_platform_validation(hass, mqtt_mock)
assert await async_setup_component(
hass, DOMAIN, {DOMAIN: {CONF_PLATFORM: "mqtt", "devices": {dev_id: topic}}}
)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
assert mock_sp.call_count == 1
# Deprecated in HA Core 2022.6
async def test_legacy_new_message(hass, mock_device_tracker_conf, mqtt_mock):
async def test_legacy_new_message(
hass, mock_device_tracker_conf, mqtt_mock_entry_no_yaml_config
):
"""Test new message."""
await mqtt_mock_entry_no_yaml_config()
dev_id = "paulus"
entity_id = f"{DOMAIN}.{dev_id}"
topic = "/location/paulus"
@ -51,9 +58,10 @@ async def test_legacy_new_message(hass, mock_device_tracker_conf, mqtt_mock):
# Deprecated in HA Core 2022.6
async def test_legacy_single_level_wildcard_topic(
hass, mock_device_tracker_conf, mqtt_mock
hass, mock_device_tracker_conf, mqtt_mock_entry_no_yaml_config
):
"""Test single level wildcard topic."""
await mqtt_mock_entry_no_yaml_config()
dev_id = "paulus"
entity_id = f"{DOMAIN}.{dev_id}"
subscription = "/location/+/paulus"
@ -73,9 +81,10 @@ async def test_legacy_single_level_wildcard_topic(
# Deprecated in HA Core 2022.6
async def test_legacy_multi_level_wildcard_topic(
hass, mock_device_tracker_conf, mqtt_mock
hass, mock_device_tracker_conf, mqtt_mock_entry_no_yaml_config
):
"""Test multi level wildcard topic."""
await mqtt_mock_entry_no_yaml_config()
dev_id = "paulus"
entity_id = f"{DOMAIN}.{dev_id}"
subscription = "/location/#"
@ -95,9 +104,10 @@ async def test_legacy_multi_level_wildcard_topic(
# Deprecated in HA Core 2022.6
async def test_legacy_single_level_wildcard_topic_not_matching(
hass, mock_device_tracker_conf, mqtt_mock
hass, mock_device_tracker_conf, mqtt_mock_entry_no_yaml_config
):
"""Test not matching single level wildcard topic."""
await mqtt_mock_entry_no_yaml_config()
dev_id = "paulus"
entity_id = f"{DOMAIN}.{dev_id}"
subscription = "/location/+/paulus"
@ -117,9 +127,10 @@ async def test_legacy_single_level_wildcard_topic_not_matching(
# Deprecated in HA Core 2022.6
async def test_legacy_multi_level_wildcard_topic_not_matching(
hass, mock_device_tracker_conf, mqtt_mock
hass, mock_device_tracker_conf, mqtt_mock_entry_no_yaml_config
):
"""Test not matching multi level wildcard topic."""
await mqtt_mock_entry_no_yaml_config()
dev_id = "paulus"
entity_id = f"{DOMAIN}.{dev_id}"
subscription = "/location/#"
@ -139,9 +150,10 @@ async def test_legacy_multi_level_wildcard_topic_not_matching(
# Deprecated in HA Core 2022.6
async def test_legacy_matching_custom_payload_for_home_and_not_home(
hass, mock_device_tracker_conf, mqtt_mock
hass, mock_device_tracker_conf, mqtt_mock_entry_no_yaml_config
):
"""Test custom payload_home sets state to home and custom payload_not_home sets state to not_home."""
await mqtt_mock_entry_no_yaml_config()
dev_id = "paulus"
entity_id = f"{DOMAIN}.{dev_id}"
topic = "/location/paulus"
@ -172,9 +184,10 @@ async def test_legacy_matching_custom_payload_for_home_and_not_home(
# Deprecated in HA Core 2022.6
async def test_legacy_not_matching_custom_payload_for_home_and_not_home(
hass, mock_device_tracker_conf, mqtt_mock
hass, mock_device_tracker_conf, mqtt_mock_entry_no_yaml_config
):
"""Test not matching payload does not set state to home or not_home."""
await mqtt_mock_entry_no_yaml_config()
dev_id = "paulus"
entity_id = f"{DOMAIN}.{dev_id}"
topic = "/location/paulus"
@ -202,8 +215,11 @@ async def test_legacy_not_matching_custom_payload_for_home_and_not_home(
# Deprecated in HA Core 2022.6
async def test_legacy_matching_source_type(hass, mock_device_tracker_conf, mqtt_mock):
async def test_legacy_matching_source_type(
hass, mock_device_tracker_conf, mqtt_mock_entry_no_yaml_config
):
"""Test setting source type."""
await mqtt_mock_entry_no_yaml_config()
dev_id = "paulus"
entity_id = f"{DOMAIN}.{dev_id}"
topic = "/location/paulus"

View File

@ -33,8 +33,9 @@ def entity_reg(hass):
return mock_registry(hass)
async def test_discover_device_tracker(hass, mqtt_mock, caplog):
async def test_discover_device_tracker(hass, mqtt_mock_entry_no_yaml_config, caplog):
"""Test discovering an MQTT device tracker component."""
await mqtt_mock_entry_no_yaml_config()
async_fire_mqtt_message(
hass,
"homeassistant/device_tracker/bla/config",
@ -50,8 +51,9 @@ async def test_discover_device_tracker(hass, mqtt_mock, caplog):
@pytest.mark.no_fail_on_log_exception
async def test_discovery_broken(hass, mqtt_mock, caplog):
async def test_discovery_broken(hass, mqtt_mock_entry_no_yaml_config, caplog):
"""Test handling of bad discovery message."""
await mqtt_mock_entry_no_yaml_config()
async_fire_mqtt_message(
hass,
"homeassistant/device_tracker/bla/config",
@ -74,8 +76,11 @@ async def test_discovery_broken(hass, mqtt_mock, caplog):
assert state.name == "Beer"
async def test_non_duplicate_device_tracker_discovery(hass, mqtt_mock, caplog):
async def test_non_duplicate_device_tracker_discovery(
hass, mqtt_mock_entry_no_yaml_config, caplog
):
"""Test for a non duplicate component."""
await mqtt_mock_entry_no_yaml_config()
async_fire_mqtt_message(
hass,
"homeassistant/device_tracker/bla/config",
@ -97,8 +102,9 @@ async def test_non_duplicate_device_tracker_discovery(hass, mqtt_mock, caplog):
assert "Component has already been discovered: device_tracker bla" in caplog.text
async def test_device_tracker_removal(hass, mqtt_mock, caplog):
async def test_device_tracker_removal(hass, mqtt_mock_entry_no_yaml_config, caplog):
"""Test removal of component through empty discovery message."""
await mqtt_mock_entry_no_yaml_config()
async_fire_mqtt_message(
hass,
"homeassistant/device_tracker/bla/config",
@ -114,8 +120,9 @@ async def test_device_tracker_removal(hass, mqtt_mock, caplog):
assert state is None
async def test_device_tracker_rediscover(hass, mqtt_mock, caplog):
async def test_device_tracker_rediscover(hass, mqtt_mock_entry_no_yaml_config, caplog):
"""Test rediscover of removed component."""
await mqtt_mock_entry_no_yaml_config()
async_fire_mqtt_message(
hass,
"homeassistant/device_tracker/bla/config",
@ -140,8 +147,11 @@ async def test_device_tracker_rediscover(hass, mqtt_mock, caplog):
assert state is not None
async def test_duplicate_device_tracker_removal(hass, mqtt_mock, caplog):
async def test_duplicate_device_tracker_removal(
hass, mqtt_mock_entry_no_yaml_config, caplog
):
"""Test for a non duplicate component."""
await mqtt_mock_entry_no_yaml_config()
async_fire_mqtt_message(
hass,
"homeassistant/device_tracker/bla/config",
@ -160,8 +170,11 @@ async def test_duplicate_device_tracker_removal(hass, mqtt_mock, caplog):
)
async def test_device_tracker_discovery_update(hass, mqtt_mock, caplog):
async def test_device_tracker_discovery_update(
hass, mqtt_mock_entry_no_yaml_config, caplog
):
"""Test for a discovery update event."""
await mqtt_mock_entry_no_yaml_config()
async_fire_mqtt_message(
hass,
"homeassistant/device_tracker/bla/config",
@ -186,10 +199,12 @@ async def test_device_tracker_discovery_update(hass, mqtt_mock, caplog):
async def test_cleanup_device_tracker(
hass, hass_ws_client, device_reg, entity_reg, mqtt_mock
hass, hass_ws_client, device_reg, entity_reg, mqtt_mock_entry_no_yaml_config
):
"""Test discovered device is cleaned up when removed from registry."""
assert await async_setup_component(hass, "config", {})
await hass.async_block_till_done()
mqtt_mock = await mqtt_mock_entry_no_yaml_config()
ws_client = await hass_ws_client(hass)
async_fire_mqtt_message(
@ -242,8 +257,11 @@ async def test_cleanup_device_tracker(
)
async def test_setting_device_tracker_value_via_mqtt_message(hass, mqtt_mock, caplog):
async def test_setting_device_tracker_value_via_mqtt_message(
hass, mqtt_mock_entry_no_yaml_config, caplog
):
"""Test the setting of the value via MQTT."""
await mqtt_mock_entry_no_yaml_config()
async_fire_mqtt_message(
hass,
"homeassistant/device_tracker/bla/config",
@ -266,9 +284,10 @@ async def test_setting_device_tracker_value_via_mqtt_message(hass, mqtt_mock, ca
async def test_setting_device_tracker_value_via_mqtt_message_and_template(
hass, mqtt_mock, caplog
hass, mqtt_mock_entry_no_yaml_config, caplog
):
"""Test the setting of the value via MQTT."""
await mqtt_mock_entry_no_yaml_config()
async_fire_mqtt_message(
hass,
"homeassistant/device_tracker/bla/config",
@ -290,9 +309,10 @@ async def test_setting_device_tracker_value_via_mqtt_message_and_template(
async def test_setting_device_tracker_value_via_mqtt_message_and_template2(
hass, mqtt_mock, caplog
hass, mqtt_mock_entry_no_yaml_config, caplog
):
"""Test the setting of the value via MQTT."""
await mqtt_mock_entry_no_yaml_config()
async_fire_mqtt_message(
hass,
"homeassistant/device_tracker/bla/config",
@ -317,9 +337,10 @@ async def test_setting_device_tracker_value_via_mqtt_message_and_template2(
async def test_setting_device_tracker_location_via_mqtt_message(
hass, mqtt_mock, caplog
hass, mqtt_mock_entry_no_yaml_config, caplog
):
"""Test the setting of the location via MQTT."""
await mqtt_mock_entry_no_yaml_config()
async_fire_mqtt_message(
hass,
"homeassistant/device_tracker/bla/config",
@ -337,9 +358,10 @@ async def test_setting_device_tracker_location_via_mqtt_message(
async def test_setting_device_tracker_location_via_lat_lon_message(
hass, mqtt_mock, caplog
hass, mqtt_mock_entry_no_yaml_config, caplog
):
"""Test the setting of the latitude and longitude via MQTT."""
await mqtt_mock_entry_no_yaml_config()
async_fire_mqtt_message(
hass,
"homeassistant/device_tracker/bla/config",
@ -391,8 +413,14 @@ async def test_setting_device_tracker_location_via_lat_lon_message(
assert state.state == STATE_UNKNOWN
async def test_setting_blocked_attribute_via_mqtt_json_message(hass, mqtt_mock):
async def test_setting_blocked_attribute_via_mqtt_json_message(
hass, mqtt_mock_entry_no_yaml_config
):
"""Test the setting of attribute via MQTT with JSON payload."""
await help_test_setting_blocked_attribute_via_mqtt_json_message(
hass, mqtt_mock, device_tracker.DOMAIN, DEFAULT_CONFIG, None
hass,
mqtt_mock_entry_no_yaml_config,
device_tracker.DOMAIN,
DEFAULT_CONFIG,
None,
)

View File

@ -39,8 +39,11 @@ def calls(hass):
return async_mock_service(hass, "test", "automation")
async def test_get_triggers(hass, device_reg, entity_reg, mqtt_mock):
async def test_get_triggers(
hass, device_reg, entity_reg, mqtt_mock_entry_no_yaml_config
):
"""Test we get the expected triggers from a discovered mqtt device."""
await mqtt_mock_entry_no_yaml_config()
data1 = (
'{ "automation_type":"trigger",'
' "device":{"identifiers":["0AFFD2"]},'
@ -70,8 +73,11 @@ async def test_get_triggers(hass, device_reg, entity_reg, mqtt_mock):
assert_lists_same(triggers, expected_triggers)
async def test_get_unknown_triggers(hass, device_reg, entity_reg, mqtt_mock):
async def test_get_unknown_triggers(
hass, device_reg, entity_reg, mqtt_mock_entry_no_yaml_config
):
"""Test we don't get unknown triggers."""
await mqtt_mock_entry_no_yaml_config()
# Discover a sensor (without device triggers)
data1 = (
'{ "device":{"identifiers":["0AFFD2"]},'
@ -112,8 +118,11 @@ async def test_get_unknown_triggers(hass, device_reg, entity_reg, mqtt_mock):
assert_lists_same(triggers, [])
async def test_get_non_existing_triggers(hass, device_reg, entity_reg, mqtt_mock):
async def test_get_non_existing_triggers(
hass, device_reg, entity_reg, mqtt_mock_entry_no_yaml_config
):
"""Test getting non existing triggers."""
await mqtt_mock_entry_no_yaml_config()
# Discover a sensor (without device triggers)
data1 = (
'{ "device":{"identifiers":["0AFFD2"]},'
@ -131,8 +140,11 @@ async def test_get_non_existing_triggers(hass, device_reg, entity_reg, mqtt_mock
@pytest.mark.no_fail_on_log_exception
async def test_discover_bad_triggers(hass, device_reg, entity_reg, mqtt_mock):
async def test_discover_bad_triggers(
hass, device_reg, entity_reg, mqtt_mock_entry_no_yaml_config
):
"""Test bad discovery message."""
await mqtt_mock_entry_no_yaml_config()
# Test sending bad data
data0 = (
'{ "automation_type":"trigger",'
@ -176,8 +188,11 @@ async def test_discover_bad_triggers(hass, device_reg, entity_reg, mqtt_mock):
assert_lists_same(triggers, expected_triggers)
async def test_update_remove_triggers(hass, device_reg, entity_reg, mqtt_mock):
async def test_update_remove_triggers(
hass, device_reg, entity_reg, mqtt_mock_entry_no_yaml_config
):
"""Test triggers can be updated and removed."""
await mqtt_mock_entry_no_yaml_config()
config1 = {
"automation_type": "trigger",
"device": {"identifiers": ["0AFFD2"]},
@ -240,8 +255,11 @@ async def test_update_remove_triggers(hass, device_reg, entity_reg, mqtt_mock):
assert device_entry is None
async def test_if_fires_on_mqtt_message(hass, device_reg, calls, mqtt_mock):
async def test_if_fires_on_mqtt_message(
hass, device_reg, calls, mqtt_mock_entry_no_yaml_config
):
"""Test triggers firing."""
await mqtt_mock_entry_no_yaml_config()
data1 = (
'{ "automation_type":"trigger",'
' "device":{"identifiers":["0AFFD2"]},'
@ -313,8 +331,11 @@ async def test_if_fires_on_mqtt_message(hass, device_reg, calls, mqtt_mock):
assert calls[1].data["some"] == "long_press"
async def test_if_fires_on_mqtt_message_template(hass, device_reg, calls, mqtt_mock):
async def test_if_fires_on_mqtt_message_template(
hass, device_reg, calls, mqtt_mock_entry_no_yaml_config
):
"""Test triggers firing."""
await mqtt_mock_entry_no_yaml_config()
data1 = (
'{ "automation_type":"trigger",'
' "device":{"identifiers":["0AFFD2"]},'
@ -389,9 +410,10 @@ async def test_if_fires_on_mqtt_message_template(hass, device_reg, calls, mqtt_m
async def test_if_fires_on_mqtt_message_late_discover(
hass, device_reg, calls, mqtt_mock
hass, device_reg, calls, mqtt_mock_entry_no_yaml_config
):
"""Test triggers firing of MQTT device triggers discovered after setup."""
await mqtt_mock_entry_no_yaml_config()
data0 = (
'{ "device":{"identifiers":["0AFFD2"]},'
' "state_topic": "foobar/sensor",'
@ -472,9 +494,10 @@ async def test_if_fires_on_mqtt_message_late_discover(
async def test_if_fires_on_mqtt_message_after_update(
hass, device_reg, calls, mqtt_mock
hass, device_reg, calls, mqtt_mock_entry_no_yaml_config
):
"""Test triggers firing after update."""
await mqtt_mock_entry_no_yaml_config()
data1 = (
'{ "automation_type":"trigger",'
' "device":{"identifiers":["0AFFD2"]},'
@ -515,6 +538,7 @@ async def test_if_fires_on_mqtt_message_after_update(
]
},
)
await hass.async_block_till_done()
# Fake short press.
async_fire_mqtt_message(hass, "foobar/triggers/button1", "")
@ -546,8 +570,11 @@ async def test_if_fires_on_mqtt_message_after_update(
assert len(calls) == 3
async def test_no_resubscribe_same_topic(hass, device_reg, mqtt_mock):
async def test_no_resubscribe_same_topic(
hass, device_reg, mqtt_mock_entry_no_yaml_config
):
"""Test subscription to topics without change."""
mqtt_mock = await mqtt_mock_entry_no_yaml_config()
data1 = (
'{ "automation_type":"trigger",'
' "device":{"identifiers":["0AFFD2"]},'
@ -589,9 +616,10 @@ async def test_no_resubscribe_same_topic(hass, device_reg, mqtt_mock):
async def test_not_fires_on_mqtt_message_after_remove_by_mqtt(
hass, device_reg, calls, mqtt_mock
hass, device_reg, calls, mqtt_mock_entry_no_yaml_config
):
"""Test triggers not firing after removal."""
await mqtt_mock_entry_no_yaml_config()
data1 = (
'{ "automation_type":"trigger",'
' "device":{"identifiers":["0AFFD2"]},'
@ -625,6 +653,7 @@ async def test_not_fires_on_mqtt_message_after_remove_by_mqtt(
]
},
)
await hass.async_block_till_done()
# Fake short press.
async_fire_mqtt_message(hass, "foobar/triggers/button1", "short_press")
@ -649,10 +678,13 @@ async def test_not_fires_on_mqtt_message_after_remove_by_mqtt(
async def test_not_fires_on_mqtt_message_after_remove_from_registry(
hass, hass_ws_client, device_reg, calls, mqtt_mock
hass, hass_ws_client, device_reg, calls, mqtt_mock_entry_no_yaml_config
):
"""Test triggers not firing after removal."""
assert await async_setup_component(hass, "config", {})
await hass.async_block_till_done()
await mqtt_mock_entry_no_yaml_config()
ws_client = await hass_ws_client(hass)
data1 = (
@ -713,8 +745,9 @@ async def test_not_fires_on_mqtt_message_after_remove_from_registry(
assert len(calls) == 1
async def test_attach_remove(hass, device_reg, mqtt_mock):
async def test_attach_remove(hass, device_reg, mqtt_mock_entry_no_yaml_config):
"""Test attach and removal of trigger."""
await mqtt_mock_entry_no_yaml_config()
data1 = (
'{ "automation_type":"trigger",'
' "device":{"identifiers":["0AFFD2"]},'
@ -766,8 +799,9 @@ async def test_attach_remove(hass, device_reg, mqtt_mock):
assert len(calls) == 1
async def test_attach_remove_late(hass, device_reg, mqtt_mock):
async def test_attach_remove_late(hass, device_reg, mqtt_mock_entry_no_yaml_config):
"""Test attach and removal of trigger ."""
await mqtt_mock_entry_no_yaml_config()
data0 = (
'{ "device":{"identifiers":["0AFFD2"]},'
' "state_topic": "foobar/sensor",'
@ -827,8 +861,9 @@ async def test_attach_remove_late(hass, device_reg, mqtt_mock):
assert len(calls) == 1
async def test_attach_remove_late2(hass, device_reg, mqtt_mock):
async def test_attach_remove_late2(hass, device_reg, mqtt_mock_entry_no_yaml_config):
"""Test attach and removal of trigger ."""
await mqtt_mock_entry_no_yaml_config()
data0 = (
'{ "device":{"identifiers":["0AFFD2"]},'
' "state_topic": "foobar/sensor",'
@ -882,8 +917,9 @@ async def test_attach_remove_late2(hass, device_reg, mqtt_mock):
assert len(calls) == 0
async def test_entity_device_info_with_connection(hass, mqtt_mock):
async def test_entity_device_info_with_connection(hass, mqtt_mock_entry_no_yaml_config):
"""Test MQTT device registry integration."""
await mqtt_mock_entry_no_yaml_config()
registry = dr.async_get(hass)
data = json.dumps(
@ -915,8 +951,9 @@ async def test_entity_device_info_with_connection(hass, mqtt_mock):
assert device.sw_version == "0.1-beta"
async def test_entity_device_info_with_identifier(hass, mqtt_mock):
async def test_entity_device_info_with_identifier(hass, mqtt_mock_entry_no_yaml_config):
"""Test MQTT device registry integration."""
await mqtt_mock_entry_no_yaml_config()
registry = dr.async_get(hass)
data = json.dumps(
@ -946,8 +983,9 @@ async def test_entity_device_info_with_identifier(hass, mqtt_mock):
assert device.sw_version == "0.1-beta"
async def test_entity_device_info_update(hass, mqtt_mock):
async def test_entity_device_info_update(hass, mqtt_mock_entry_no_yaml_config):
"""Test device registry update."""
await mqtt_mock_entry_no_yaml_config()
registry = dr.async_get(hass)
config = {
@ -983,8 +1021,11 @@ async def test_entity_device_info_update(hass, mqtt_mock):
assert device.name == "Milk"
async def test_cleanup_trigger(hass, hass_ws_client, device_reg, entity_reg, mqtt_mock):
async def test_cleanup_trigger(
hass, hass_ws_client, device_reg, entity_reg, mqtt_mock_entry_no_yaml_config
):
"""Test trigger discovery topic is cleaned when device is removed from registry."""
mqtt_mock = await mqtt_mock_entry_no_yaml_config()
assert await async_setup_component(hass, "config", {})
ws_client = await hass_ws_client(hass)
@ -1034,8 +1075,11 @@ async def test_cleanup_trigger(hass, hass_ws_client, device_reg, entity_reg, mqt
)
async def test_cleanup_device(hass, device_reg, entity_reg, mqtt_mock):
async def test_cleanup_device(
hass, device_reg, entity_reg, mqtt_mock_entry_no_yaml_config
):
"""Test removal from device registry when trigger is removed."""
await mqtt_mock_entry_no_yaml_config()
config = {
"automation_type": "trigger",
"topic": "test-topic",
@ -1065,8 +1109,11 @@ async def test_cleanup_device(hass, device_reg, entity_reg, mqtt_mock):
assert device_entry is None
async def test_cleanup_device_several_triggers(hass, device_reg, entity_reg, mqtt_mock):
async def test_cleanup_device_several_triggers(
hass, device_reg, entity_reg, mqtt_mock_entry_no_yaml_config
):
"""Test removal from device registry when the last trigger is removed."""
await mqtt_mock_entry_no_yaml_config()
config1 = {
"automation_type": "trigger",
"topic": "test-topic",
@ -1122,11 +1169,14 @@ async def test_cleanup_device_several_triggers(hass, device_reg, entity_reg, mqt
assert device_entry is None
async def test_cleanup_device_with_entity1(hass, device_reg, entity_reg, mqtt_mock):
async def test_cleanup_device_with_entity1(
hass, device_reg, entity_reg, mqtt_mock_entry_no_yaml_config
):
"""Test removal from device registry for device with entity.
Trigger removed first, then entity.
"""
await mqtt_mock_entry_no_yaml_config()
config1 = {
"automation_type": "trigger",
"topic": "test-topic",
@ -1178,11 +1228,14 @@ async def test_cleanup_device_with_entity1(hass, device_reg, entity_reg, mqtt_mo
assert device_entry is None
async def test_cleanup_device_with_entity2(hass, device_reg, entity_reg, mqtt_mock):
async def test_cleanup_device_with_entity2(
hass, device_reg, entity_reg, mqtt_mock_entry_no_yaml_config
):
"""Test removal from device registry for device with entity.
Entity removed first, then trigger.
"""
await mqtt_mock_entry_no_yaml_config()
config1 = {
"automation_type": "trigger",
"topic": "test-topic",
@ -1234,11 +1287,12 @@ async def test_cleanup_device_with_entity2(hass, device_reg, entity_reg, mqtt_mo
assert device_entry is None
async def test_trigger_debug_info(hass, mqtt_mock):
async def test_trigger_debug_info(hass, mqtt_mock_entry_no_yaml_config):
"""Test debug_info.
This is a test helper for MQTT debug_info.
"""
await mqtt_mock_entry_no_yaml_config()
registry = dr.async_get(hass)
config1 = {

View File

@ -37,8 +37,11 @@ def device_reg(hass):
return mock_device_registry(hass)
async def test_entry_diagnostics(hass, device_reg, hass_client, mqtt_mock):
async def test_entry_diagnostics(
hass, device_reg, hass_client, mqtt_mock_entry_no_yaml_config
):
"""Test config entry diagnostics."""
mqtt_mock = await mqtt_mock_entry_no_yaml_config()
config_entry = hass.config_entries.async_entries(mqtt.DOMAIN)[0]
mqtt_mock.connected = True
@ -154,8 +157,11 @@ async def test_entry_diagnostics(hass, device_reg, hass_client, mqtt_mock):
}
],
)
async def test_redact_diagnostics(hass, device_reg, hass_client, mqtt_mock):
async def test_redact_diagnostics(
hass, device_reg, hass_client, mqtt_mock_entry_no_yaml_config
):
"""Test redacting diagnostics."""
mqtt_mock = await mqtt_mock_entry_no_yaml_config()
expected_config = dict(default_config)
expected_config["password"] = "**REDACTED**"
expected_config["username"] = "**REDACTED**"

View File

@ -48,8 +48,9 @@ def entity_reg(hass):
"mqtt_config",
[{mqtt.CONF_BROKER: "mock-broker", mqtt.CONF_DISCOVERY: False}],
)
async def test_subscribing_config_topic(hass, mqtt_mock):
async def test_subscribing_config_topic(hass, mqtt_mock_entry_no_yaml_config):
"""Test setting up discovery."""
mqtt_mock = await mqtt_mock_entry_no_yaml_config()
entry = hass.config_entries.async_entries(mqtt.DOMAIN)[0]
discovery_topic = "homeassistant"
@ -71,8 +72,9 @@ async def test_subscribing_config_topic(hass, mqtt_mock):
("homeassistant/binary_sensor/rörkrökare/config", True),
],
)
async def test_invalid_topic(hass, mqtt_mock, caplog, topic, log):
async def test_invalid_topic(hass, mqtt_mock_entry_no_yaml_config, caplog, topic, log):
"""Test sending to invalid topic."""
await mqtt_mock_entry_no_yaml_config()
with patch(
"homeassistant.components.mqtt.discovery.async_dispatcher_send"
) as mock_dispatcher_send:
@ -90,8 +92,9 @@ async def test_invalid_topic(hass, mqtt_mock, caplog, topic, log):
caplog.clear()
async def test_invalid_json(hass, mqtt_mock, caplog):
async def test_invalid_json(hass, mqtt_mock_entry_no_yaml_config, caplog):
"""Test sending in invalid JSON."""
await mqtt_mock_entry_no_yaml_config()
with patch(
"homeassistant.components.mqtt.discovery.async_dispatcher_send"
) as mock_dispatcher_send:
@ -106,8 +109,9 @@ async def test_invalid_json(hass, mqtt_mock, caplog):
assert not mock_dispatcher_send.called
async def test_only_valid_components(hass, mqtt_mock, caplog):
async def test_only_valid_components(hass, mqtt_mock_entry_no_yaml_config, caplog):
"""Test for a valid component."""
await mqtt_mock_entry_no_yaml_config()
with patch(
"homeassistant.components.mqtt.discovery.async_dispatcher_send"
) as mock_dispatcher_send:
@ -127,8 +131,9 @@ async def test_only_valid_components(hass, mqtt_mock, caplog):
assert not mock_dispatcher_send.called
async def test_correct_config_discovery(hass, mqtt_mock, caplog):
async def test_correct_config_discovery(hass, mqtt_mock_entry_no_yaml_config, caplog):
"""Test sending in correct JSON."""
await mqtt_mock_entry_no_yaml_config()
async_fire_mqtt_message(
hass,
"homeassistant/binary_sensor/bla/config",
@ -143,8 +148,9 @@ async def test_correct_config_discovery(hass, mqtt_mock, caplog):
assert ("binary_sensor", "bla") in hass.data[ALREADY_DISCOVERED]
async def test_discover_fan(hass, mqtt_mock, caplog):
async def test_discover_fan(hass, mqtt_mock_entry_no_yaml_config, caplog):
"""Test discovering an MQTT fan."""
await mqtt_mock_entry_no_yaml_config()
async_fire_mqtt_message(
hass,
"homeassistant/fan/bla/config",
@ -159,8 +165,9 @@ async def test_discover_fan(hass, mqtt_mock, caplog):
assert ("fan", "bla") in hass.data[ALREADY_DISCOVERED]
async def test_discover_climate(hass, mqtt_mock, caplog):
async def test_discover_climate(hass, mqtt_mock_entry_no_yaml_config, caplog):
"""Test discovering an MQTT climate component."""
await mqtt_mock_entry_no_yaml_config()
data = (
'{ "name": "ClimateTest",'
' "current_temperature_topic": "climate/bla/current_temp",'
@ -177,8 +184,11 @@ async def test_discover_climate(hass, mqtt_mock, caplog):
assert ("climate", "bla") in hass.data[ALREADY_DISCOVERED]
async def test_discover_alarm_control_panel(hass, mqtt_mock, caplog):
async def test_discover_alarm_control_panel(
hass, mqtt_mock_entry_no_yaml_config, caplog
):
"""Test discovering an MQTT alarm control panel component."""
await mqtt_mock_entry_no_yaml_config()
data = (
'{ "name": "AlarmControlPanelTest",'
' "state_topic": "test_topic",'
@ -341,9 +351,10 @@ async def test_discover_alarm_control_panel(hass, mqtt_mock, caplog):
],
)
async def test_discovery_with_object_id(
hass, mqtt_mock, caplog, topic, config, entity_id, name, domain
hass, mqtt_mock_entry_no_yaml_config, caplog, topic, config, entity_id, name, domain
):
"""Test discovering an MQTT entity with object_id."""
await mqtt_mock_entry_no_yaml_config()
async_fire_mqtt_message(hass, topic, config)
await hass.async_block_till_done()
@ -354,8 +365,9 @@ async def test_discovery_with_object_id(
assert (domain, "object bla") in hass.data[ALREADY_DISCOVERED]
async def test_discovery_incl_nodeid(hass, mqtt_mock, caplog):
async def test_discovery_incl_nodeid(hass, mqtt_mock_entry_no_yaml_config, caplog):
"""Test sending in correct JSON with optional node_id included."""
await mqtt_mock_entry_no_yaml_config()
async_fire_mqtt_message(
hass,
"homeassistant/binary_sensor/my_node_id/bla/config",
@ -370,8 +382,9 @@ async def test_discovery_incl_nodeid(hass, mqtt_mock, caplog):
assert ("binary_sensor", "my_node_id bla") in hass.data[ALREADY_DISCOVERED]
async def test_non_duplicate_discovery(hass, mqtt_mock, caplog):
async def test_non_duplicate_discovery(hass, mqtt_mock_entry_no_yaml_config, caplog):
"""Test for a non duplicate component."""
await mqtt_mock_entry_no_yaml_config()
async_fire_mqtt_message(
hass,
"homeassistant/binary_sensor/bla/config",
@ -393,8 +406,9 @@ async def test_non_duplicate_discovery(hass, mqtt_mock, caplog):
assert "Component has already been discovered: binary_sensor bla" in caplog.text
async def test_removal(hass, mqtt_mock, caplog):
async def test_removal(hass, mqtt_mock_entry_no_yaml_config, caplog):
"""Test removal of component through empty discovery message."""
await mqtt_mock_entry_no_yaml_config()
async_fire_mqtt_message(
hass,
"homeassistant/binary_sensor/bla/config",
@ -410,8 +424,9 @@ async def test_removal(hass, mqtt_mock, caplog):
assert state is None
async def test_rediscover(hass, mqtt_mock, caplog):
async def test_rediscover(hass, mqtt_mock_entry_no_yaml_config, caplog):
"""Test rediscover of removed component."""
await mqtt_mock_entry_no_yaml_config()
async_fire_mqtt_message(
hass,
"homeassistant/binary_sensor/bla/config",
@ -436,9 +451,9 @@ async def test_rediscover(hass, mqtt_mock, caplog):
assert state is not None
async def test_rapid_rediscover(hass, mqtt_mock, caplog):
async def test_rapid_rediscover(hass, mqtt_mock_entry_no_yaml_config, caplog):
"""Test immediate rediscover of removed component."""
await mqtt_mock_entry_no_yaml_config()
events = async_capture_events(hass, EVENT_STATE_CHANGED)
async_fire_mqtt_message(
@ -485,9 +500,9 @@ async def test_rapid_rediscover(hass, mqtt_mock, caplog):
assert events[4].data["old_state"] is None
async def test_rapid_rediscover_unique(hass, mqtt_mock, caplog):
async def test_rapid_rediscover_unique(hass, mqtt_mock_entry_no_yaml_config, caplog):
"""Test immediate rediscover of removed component."""
await mqtt_mock_entry_no_yaml_config()
events = []
@ha.callback
@ -544,9 +559,9 @@ async def test_rapid_rediscover_unique(hass, mqtt_mock, caplog):
assert events[3].data["old_state"] is None
async def test_rapid_reconfigure(hass, mqtt_mock, caplog):
async def test_rapid_reconfigure(hass, mqtt_mock_entry_no_yaml_config, caplog):
"""Test immediate reconfigure of added component."""
await mqtt_mock_entry_no_yaml_config()
events = []
@ha.callback
@ -596,8 +611,9 @@ async def test_rapid_reconfigure(hass, mqtt_mock, caplog):
assert events[2].data["new_state"].attributes["friendly_name"] == "Wine"
async def test_duplicate_removal(hass, mqtt_mock, caplog):
async def test_duplicate_removal(hass, mqtt_mock_entry_no_yaml_config, caplog):
"""Test for a non duplicate component."""
await mqtt_mock_entry_no_yaml_config()
async_fire_mqtt_message(
hass,
"homeassistant/binary_sensor/bla/config",
@ -614,8 +630,11 @@ async def test_duplicate_removal(hass, mqtt_mock, caplog):
assert "Component has already been discovered: binary_sensor bla" not in caplog.text
async def test_cleanup_device(hass, hass_ws_client, device_reg, entity_reg, mqtt_mock):
async def test_cleanup_device(
hass, hass_ws_client, device_reg, entity_reg, mqtt_mock_entry_no_yaml_config
):
"""Test discvered device is cleaned up when entry removed from device."""
mqtt_mock = await mqtt_mock_entry_no_yaml_config()
assert await async_setup_component(hass, "config", {})
ws_client = await hass_ws_client(hass)
@ -669,8 +688,11 @@ async def test_cleanup_device(hass, hass_ws_client, device_reg, entity_reg, mqtt
)
async def test_cleanup_device_mqtt(hass, device_reg, entity_reg, mqtt_mock):
async def test_cleanup_device_mqtt(
hass, device_reg, entity_reg, mqtt_mock_entry_no_yaml_config
):
"""Test discvered device is cleaned up when removed through MQTT."""
mqtt_mock = await mqtt_mock_entry_no_yaml_config()
data = (
'{ "device":{"identifiers":["0AFFD2"]},'
' "state_topic": "foobar/sensor",'
@ -709,10 +731,12 @@ async def test_cleanup_device_mqtt(hass, device_reg, entity_reg, mqtt_mock):
async def test_cleanup_device_multiple_config_entries(
hass, hass_ws_client, device_reg, entity_reg, mqtt_mock
hass, hass_ws_client, device_reg, entity_reg, mqtt_mock_entry_no_yaml_config
):
"""Test discovered device is cleaned up when entry removed from device."""
assert await async_setup_component(hass, "config", {})
await hass.async_block_till_done()
mqtt_mock = await mqtt_mock_entry_no_yaml_config()
ws_client = await hass_ws_client(hass)
config_entry = MockConfigEntry(domain="test", data={})
@ -804,9 +828,10 @@ async def test_cleanup_device_multiple_config_entries(
async def test_cleanup_device_multiple_config_entries_mqtt(
hass, device_reg, entity_reg, mqtt_mock
hass, device_reg, entity_reg, mqtt_mock_entry_no_yaml_config
):
"""Test discovered device is cleaned up when removed through MQTT."""
mqtt_mock = await mqtt_mock_entry_no_yaml_config()
config_entry = MockConfigEntry(domain="test", data={})
config_entry.add_to_hass(hass)
device_entry = device_reg.async_get_or_create(
@ -880,8 +905,9 @@ async def test_cleanup_device_multiple_config_entries_mqtt(
mqtt_mock.async_publish.assert_not_called()
async def test_discovery_expansion(hass, mqtt_mock, caplog):
async def test_discovery_expansion(hass, mqtt_mock_entry_no_yaml_config, caplog):
"""Test expansion of abbreviated discovery payload."""
await mqtt_mock_entry_no_yaml_config()
data = (
'{ "~": "some/base/topic",'
' "name": "DiscoveryExpansionTest1",'
@ -937,8 +963,9 @@ async def test_discovery_expansion(hass, mqtt_mock, caplog):
assert state.state == STATE_UNAVAILABLE
async def test_discovery_expansion_2(hass, mqtt_mock, caplog):
async def test_discovery_expansion_2(hass, mqtt_mock_entry_no_yaml_config, caplog):
"""Test expansion of abbreviated discovery payload."""
await mqtt_mock_entry_no_yaml_config()
data = (
'{ "~": "some/base/topic",'
' "name": "DiscoveryExpansionTest1",'
@ -977,8 +1004,9 @@ async def test_discovery_expansion_2(hass, mqtt_mock, caplog):
@pytest.mark.no_fail_on_log_exception
async def test_discovery_expansion_3(hass, mqtt_mock, caplog):
async def test_discovery_expansion_3(hass, mqtt_mock_entry_no_yaml_config, caplog):
"""Test expansion of broken discovery payload."""
await mqtt_mock_entry_no_yaml_config()
data = (
'{ "~": "some/base/topic",'
' "name": "DiscoveryExpansionTest1",'
@ -1008,9 +1036,10 @@ async def test_discovery_expansion_3(hass, mqtt_mock, caplog):
async def test_discovery_expansion_without_encoding_and_value_template_1(
hass, mqtt_mock, caplog
hass, mqtt_mock_entry_no_yaml_config, caplog
):
"""Test expansion of raw availability payload with a template as list."""
await mqtt_mock_entry_no_yaml_config()
data = (
'{ "~": "some/base/topic",'
' "name": "DiscoveryExpansionTest1",'
@ -1056,9 +1085,10 @@ async def test_discovery_expansion_without_encoding_and_value_template_1(
async def test_discovery_expansion_without_encoding_and_value_template_2(
hass, mqtt_mock, caplog
hass, mqtt_mock_entry_no_yaml_config, caplog
):
"""Test expansion of raw availability payload with a template directly."""
await mqtt_mock_entry_no_yaml_config()
data = (
'{ "~": "some/base/topic",'
' "name": "DiscoveryExpansionTest1",'
@ -1133,8 +1163,11 @@ ABBREVIATIONS_WHITE_LIST = [
]
async def test_missing_discover_abbreviations(hass, mqtt_mock, caplog):
async def test_missing_discover_abbreviations(
hass, mqtt_mock_entry_no_yaml_config, caplog
):
"""Check MQTT platforms for missing abbreviations."""
await mqtt_mock_entry_no_yaml_config()
missing = []
regex = re.compile(r"(CONF_[a-zA-Z\d_]*) *= *[\'\"]([a-zA-Z\d_]*)[\'\"]")
for fil in Path(mqtt.__file__).parent.rglob("*.py"):
@ -1157,8 +1190,11 @@ async def test_missing_discover_abbreviations(hass, mqtt_mock, caplog):
assert not missing
async def test_no_implicit_state_topic_switch(hass, mqtt_mock, caplog):
async def test_no_implicit_state_topic_switch(
hass, mqtt_mock_entry_no_yaml_config, caplog
):
"""Test no implicit state topic for switch."""
await mqtt_mock_entry_no_yaml_config()
data = '{ "name": "Test1",' ' "command_topic": "cmnd"' "}"
async_fire_mqtt_message(hass, "homeassistant/switch/bla/config", data)
@ -1187,8 +1223,11 @@ async def test_no_implicit_state_topic_switch(hass, mqtt_mock, caplog):
}
],
)
async def test_complex_discovery_topic_prefix(hass, mqtt_mock, caplog):
async def test_complex_discovery_topic_prefix(
hass, mqtt_mock_entry_no_yaml_config, caplog
):
"""Tests handling of discovery topic prefix with multiple slashes."""
await mqtt_mock_entry_no_yaml_config()
async_fire_mqtt_message(
hass,
("my_home/homeassistant/register/binary_sensor/node1/object1/config"),
@ -1204,9 +1243,10 @@ async def test_complex_discovery_topic_prefix(hass, mqtt_mock, caplog):
async def test_mqtt_integration_discovery_subscribe_unsubscribe(
hass, mqtt_client_mock, mqtt_mock
hass, mqtt_client_mock, mqtt_mock_entry_no_yaml_config
):
"""Check MQTT integration discovery subscribe and unsubscribe."""
mqtt_mock = await mqtt_mock_entry_no_yaml_config()
mock_entity_platform(hass, "config_flow.comp", None)
entry = hass.config_entries.async_entries("mqtt")[0]
@ -1243,8 +1283,11 @@ async def test_mqtt_integration_discovery_subscribe_unsubscribe(
assert not mqtt_client_mock.unsubscribe.called
async def test_mqtt_discovery_unsubscribe_once(hass, mqtt_client_mock, mqtt_mock):
async def test_mqtt_discovery_unsubscribe_once(
hass, mqtt_client_mock, mqtt_mock_entry_no_yaml_config
):
"""Check MQTT integration discovery unsubscribe once."""
mqtt_mock = await mqtt_mock_entry_no_yaml_config()
mock_entity_platform(hass, "config_flow.comp", None)
entry = hass.config_entries.async_entries("mqtt")[0]

View File

@ -74,16 +74,25 @@ DEFAULT_CONFIG = {
}
async def test_fail_setup_if_no_command_topic(hass, mqtt_mock):
async def test_fail_setup_if_no_command_topic(
hass, caplog, mqtt_mock_entry_no_yaml_config
):
"""Test if command fails with command topic."""
assert await async_setup_component(
hass, fan.DOMAIN, {fan.DOMAIN: {"platform": "mqtt", "name": "test"}}
)
await hass.async_block_till_done()
await mqtt_mock_entry_no_yaml_config()
assert hass.states.get("fan.test") is None
assert (
"Invalid config for [fan.mqtt]: required key not provided @ data['command_topic']"
in caplog.text
)
async def test_controlling_state_via_topic(hass, mqtt_mock, caplog):
async def test_controlling_state_via_topic(
hass, mqtt_mock_entry_with_yaml_config, caplog
):
"""Test the controlling state via topic."""
assert await async_setup_component(
hass,
@ -120,6 +129,7 @@ async def test_controlling_state_via_topic(hass, mqtt_mock, caplog):
},
)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("fan.test")
assert state.state == STATE_UNKNOWN
@ -202,7 +212,7 @@ async def test_controlling_state_via_topic(hass, mqtt_mock, caplog):
async def test_controlling_state_via_topic_with_different_speed_range(
hass, mqtt_mock, caplog
hass, mqtt_mock_entry_with_yaml_config, caplog
):
"""Test the controlling state via topic using an alternate speed range."""
assert await async_setup_component(
@ -241,6 +251,7 @@ async def test_controlling_state_via_topic_with_different_speed_range(
},
)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
async_fire_mqtt_message(hass, "percentage-state-topic1", "100")
state = hass.states.get("fan.test1")
@ -264,7 +275,7 @@ async def test_controlling_state_via_topic_with_different_speed_range(
async def test_controlling_state_via_topic_no_percentage_topics(
hass, mqtt_mock, caplog
hass, mqtt_mock_entry_with_yaml_config, caplog
):
"""Test the controlling state via topic without percentage topics."""
assert await async_setup_component(
@ -289,6 +300,7 @@ async def test_controlling_state_via_topic_no_percentage_topics(
},
)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("fan.test")
assert state.state == STATE_UNKNOWN
@ -318,7 +330,9 @@ async def test_controlling_state_via_topic_no_percentage_topics(
caplog.clear()
async def test_controlling_state_via_topic_and_json_message(hass, mqtt_mock, caplog):
async def test_controlling_state_via_topic_and_json_message(
hass, mqtt_mock_entry_with_yaml_config, caplog
):
"""Test the controlling state via topic and JSON message (percentage mode)."""
assert await async_setup_component(
hass,
@ -353,6 +367,7 @@ async def test_controlling_state_via_topic_and_json_message(hass, mqtt_mock, cap
},
)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("fan.test")
assert state.state == STATE_UNKNOWN
@ -421,7 +436,7 @@ async def test_controlling_state_via_topic_and_json_message(hass, mqtt_mock, cap
async def test_controlling_state_via_topic_and_json_message_shared_topic(
hass, mqtt_mock, caplog
hass, mqtt_mock_entry_with_yaml_config, caplog
):
"""Test the controlling state via topic and JSON message using a shared topic."""
assert await async_setup_component(
@ -457,6 +472,7 @@ async def test_controlling_state_via_topic_and_json_message_shared_topic(
},
)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("fan.test")
assert state.state == STATE_UNKNOWN
@ -509,7 +525,9 @@ async def test_controlling_state_via_topic_and_json_message_shared_topic(
caplog.clear()
async def test_sending_mqtt_commands_and_optimistic(hass, mqtt_mock, caplog):
async def test_sending_mqtt_commands_and_optimistic(
hass, mqtt_mock_entry_with_yaml_config, caplog
):
"""Test optimistic mode without state topic."""
assert await async_setup_component(
hass,
@ -535,6 +553,7 @@ async def test_sending_mqtt_commands_and_optimistic(hass, mqtt_mock, caplog):
},
)
await hass.async_block_till_done()
mqtt_mock = await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("fan.test")
assert state.state == STATE_UNKNOWN
@ -630,7 +649,9 @@ async def test_sending_mqtt_commands_and_optimistic(hass, mqtt_mock, caplog):
assert state.attributes.get(ATTR_ASSUMED_STATE)
async def test_sending_mqtt_commands_with_alternate_speed_range(hass, mqtt_mock):
async def test_sending_mqtt_commands_with_alternate_speed_range(
hass, mqtt_mock_entry_with_yaml_config
):
"""Test the controlling state via topic using an alternate speed range."""
assert await async_setup_component(
hass,
@ -668,6 +689,7 @@ async def test_sending_mqtt_commands_with_alternate_speed_range(hass, mqtt_mock)
},
)
await hass.async_block_till_done()
mqtt_mock = await mqtt_mock_entry_with_yaml_config()
await common.async_set_percentage(hass, "fan.test1", 0)
mqtt_mock.async_publish.assert_called_once_with(
@ -734,7 +756,9 @@ async def test_sending_mqtt_commands_with_alternate_speed_range(hass, mqtt_mock)
assert state.attributes.get(ATTR_ASSUMED_STATE)
async def test_sending_mqtt_commands_and_optimistic_no_legacy(hass, mqtt_mock, caplog):
async def test_sending_mqtt_commands_and_optimistic_no_legacy(
hass, mqtt_mock_entry_with_yaml_config, caplog
):
"""Test optimistic mode without state topic without legacy speed command topic."""
assert await async_setup_component(
hass,
@ -755,6 +779,7 @@ async def test_sending_mqtt_commands_and_optimistic_no_legacy(hass, mqtt_mock, c
},
)
await hass.async_block_till_done()
mqtt_mock = await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("fan.test")
assert state.state == STATE_UNKNOWN
@ -862,7 +887,9 @@ async def test_sending_mqtt_commands_and_optimistic_no_legacy(hass, mqtt_mock, c
await common.async_turn_on(hass, "fan.test", preset_mode="freaking-high")
async def test_sending_mqtt_command_templates_(hass, mqtt_mock, caplog):
async def test_sending_mqtt_command_templates_(
hass, mqtt_mock_entry_with_yaml_config, caplog
):
"""Test optimistic mode without state topic without legacy speed command topic."""
assert await async_setup_component(
hass,
@ -888,6 +915,7 @@ async def test_sending_mqtt_command_templates_(hass, mqtt_mock, caplog):
},
)
await hass.async_block_till_done()
mqtt_mock = await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("fan.test")
assert state.state == STATE_UNKNOWN
@ -1002,7 +1030,7 @@ async def test_sending_mqtt_command_templates_(hass, mqtt_mock, caplog):
async def test_sending_mqtt_commands_and_optimistic_no_percentage_topic(
hass, mqtt_mock, caplog
hass, mqtt_mock_entry_with_yaml_config, caplog
):
"""Test optimistic mode without state topic without percentage command topic."""
assert await async_setup_component(
@ -1025,6 +1053,7 @@ async def test_sending_mqtt_commands_and_optimistic_no_percentage_topic(
},
)
await hass.async_block_till_done()
mqtt_mock = await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("fan.test")
assert state.state == STATE_UNKNOWN
@ -1061,7 +1090,9 @@ async def test_sending_mqtt_commands_and_optimistic_no_percentage_topic(
assert state.attributes.get(ATTR_ASSUMED_STATE)
async def test_sending_mqtt_commands_and_explicit_optimistic(hass, mqtt_mock, caplog):
async def test_sending_mqtt_commands_and_explicit_optimistic(
hass, mqtt_mock_entry_with_yaml_config, caplog
):
"""Test optimistic mode with state topic and turn on attributes."""
assert await async_setup_component(
hass,
@ -1088,6 +1119,7 @@ async def test_sending_mqtt_commands_and_explicit_optimistic(hass, mqtt_mock, ca
},
)
await hass.async_block_till_done()
mqtt_mock = await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("fan.test")
assert state.state == STATE_UNKNOWN
@ -1305,7 +1337,13 @@ async def test_sending_mqtt_commands_and_explicit_optimistic(hass, mqtt_mock, ca
],
)
async def test_encoding_subscribable_topics(
hass, mqtt_mock, caplog, topic, value, attribute, attribute_value
hass,
mqtt_mock_entry_with_yaml_config,
caplog,
topic,
value,
attribute,
attribute_value,
):
"""Test handling of incoming encoded payload."""
config = copy.deepcopy(DEFAULT_CONFIG[fan.DOMAIN])
@ -1315,7 +1353,7 @@ async def test_encoding_subscribable_topics(
config[CONF_OSCILLATION_COMMAND_TOPIC] = "fan/some_oscillation_command_topic"
await help_test_encoding_subscribable_topics(
hass,
mqtt_mock,
mqtt_mock_entry_with_yaml_config,
caplog,
fan.DOMAIN,
config,
@ -1326,7 +1364,7 @@ async def test_encoding_subscribable_topics(
)
async def test_attributes(hass, mqtt_mock, caplog):
async def test_attributes(hass, mqtt_mock_entry_with_yaml_config, caplog):
"""Test attributes."""
assert await async_setup_component(
hass,
@ -1347,6 +1385,7 @@ async def test_attributes(hass, mqtt_mock, caplog):
},
)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("fan.test")
assert state.state == STATE_UNKNOWN
@ -1376,7 +1415,7 @@ async def test_attributes(hass, mqtt_mock, caplog):
assert state.attributes.get(fan.ATTR_OSCILLATING) is False
async def test_supported_features(hass, mqtt_mock):
async def test_supported_features(hass, mqtt_mock_entry_with_yaml_config):
"""Test optimistic mode without state topic."""
assert await async_setup_component(
hass,
@ -1498,6 +1537,7 @@ async def test_supported_features(hass, mqtt_mock):
},
)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("fan.test1")
assert state.attributes.get(ATTR_SUPPORTED_FEATURES) == 0
@ -1548,77 +1588,103 @@ async def test_supported_features(hass, mqtt_mock):
assert state.attributes.get(ATTR_SUPPORTED_FEATURES) == fan.SUPPORT_PRESET_MODE
async def test_availability_when_connection_lost(hass, mqtt_mock):
async def test_availability_when_connection_lost(
hass, mqtt_mock_entry_with_yaml_config
):
"""Test availability after MQTT disconnection."""
await help_test_availability_when_connection_lost(
hass, mqtt_mock, fan.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_with_yaml_config, fan.DOMAIN, DEFAULT_CONFIG
)
async def test_availability_without_topic(hass, mqtt_mock):
async def test_availability_without_topic(hass, mqtt_mock_entry_with_yaml_config):
"""Test availability without defined availability topic."""
await help_test_availability_without_topic(
hass, mqtt_mock, fan.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_with_yaml_config, fan.DOMAIN, DEFAULT_CONFIG
)
async def test_default_availability_payload(hass, mqtt_mock):
async def test_default_availability_payload(hass, mqtt_mock_entry_with_yaml_config):
"""Test availability by default payload with defined topic."""
await help_test_default_availability_payload(
hass, mqtt_mock, fan.DOMAIN, DEFAULT_CONFIG, True, "state-topic", "1"
hass,
mqtt_mock_entry_with_yaml_config,
fan.DOMAIN,
DEFAULT_CONFIG,
True,
"state-topic",
"1",
)
async def test_custom_availability_payload(hass, mqtt_mock):
async def test_custom_availability_payload(hass, mqtt_mock_entry_with_yaml_config):
"""Test availability by custom payload with defined topic."""
await help_test_custom_availability_payload(
hass, mqtt_mock, fan.DOMAIN, DEFAULT_CONFIG, True, "state-topic", "1"
hass,
mqtt_mock_entry_with_yaml_config,
fan.DOMAIN,
DEFAULT_CONFIG,
True,
"state-topic",
"1",
)
async def test_setting_attribute_via_mqtt_json_message(hass, mqtt_mock):
async def test_setting_attribute_via_mqtt_json_message(
hass, mqtt_mock_entry_with_yaml_config
):
"""Test the setting of attribute via MQTT with JSON payload."""
await help_test_setting_attribute_via_mqtt_json_message(
hass, mqtt_mock, fan.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_with_yaml_config, fan.DOMAIN, DEFAULT_CONFIG
)
async def test_setting_blocked_attribute_via_mqtt_json_message(hass, mqtt_mock):
async def test_setting_blocked_attribute_via_mqtt_json_message(
hass, mqtt_mock_entry_no_yaml_config
):
"""Test the setting of attribute via MQTT with JSON payload."""
await help_test_setting_blocked_attribute_via_mqtt_json_message(
hass, mqtt_mock, fan.DOMAIN, DEFAULT_CONFIG, MQTT_FAN_ATTRIBUTES_BLOCKED
hass,
mqtt_mock_entry_no_yaml_config,
fan.DOMAIN,
DEFAULT_CONFIG,
MQTT_FAN_ATTRIBUTES_BLOCKED,
)
async def test_setting_attribute_with_template(hass, mqtt_mock):
async def test_setting_attribute_with_template(hass, mqtt_mock_entry_with_yaml_config):
"""Test the setting of attribute via MQTT with JSON payload."""
await help_test_setting_attribute_with_template(
hass, mqtt_mock, fan.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_with_yaml_config, fan.DOMAIN, DEFAULT_CONFIG
)
async def test_update_with_json_attrs_not_dict(hass, mqtt_mock, caplog):
async def test_update_with_json_attrs_not_dict(
hass, mqtt_mock_entry_with_yaml_config, caplog
):
"""Test attributes get extracted from a JSON result."""
await help_test_update_with_json_attrs_not_dict(
hass, mqtt_mock, caplog, fan.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_with_yaml_config, caplog, fan.DOMAIN, DEFAULT_CONFIG
)
async def test_update_with_json_attrs_bad_json(hass, mqtt_mock, caplog):
async def test_update_with_json_attrs_bad_json(
hass, mqtt_mock_entry_with_yaml_config, caplog
):
"""Test attributes get extracted from a JSON result."""
await help_test_update_with_json_attrs_bad_JSON(
hass, mqtt_mock, caplog, fan.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_with_yaml_config, caplog, fan.DOMAIN, DEFAULT_CONFIG
)
async def test_discovery_update_attr(hass, mqtt_mock, caplog):
async def test_discovery_update_attr(hass, mqtt_mock_entry_no_yaml_config, caplog):
"""Test update of discovered MQTTAttributes."""
await help_test_discovery_update_attr(
hass, mqtt_mock, caplog, fan.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_no_yaml_config, caplog, fan.DOMAIN, DEFAULT_CONFIG
)
async def test_unique_id(hass, mqtt_mock):
async def test_unique_id(hass, mqtt_mock_entry_with_yaml_config):
"""Test unique_id option only creates one fan per id."""
config = {
fan.DOMAIN: [
@ -1638,89 +1704,107 @@ async def test_unique_id(hass, mqtt_mock):
},
]
}
await help_test_unique_id(hass, mqtt_mock, fan.DOMAIN, config)
await help_test_unique_id(
hass, mqtt_mock_entry_with_yaml_config, fan.DOMAIN, config
)
async def test_discovery_removal_fan(hass, mqtt_mock, caplog):
async def test_discovery_removal_fan(hass, mqtt_mock_entry_no_yaml_config, caplog):
"""Test removal of discovered fan."""
data = '{ "name": "test", "command_topic": "test_topic" }'
await help_test_discovery_removal(hass, mqtt_mock, caplog, fan.DOMAIN, data)
await help_test_discovery_removal(
hass, mqtt_mock_entry_no_yaml_config, caplog, fan.DOMAIN, data
)
async def test_discovery_update_fan(hass, mqtt_mock, caplog):
async def test_discovery_update_fan(hass, mqtt_mock_entry_no_yaml_config, caplog):
"""Test update of discovered fan."""
config1 = {"name": "Beer", "command_topic": "test_topic"}
config2 = {"name": "Milk", "command_topic": "test_topic"}
await help_test_discovery_update(
hass, mqtt_mock, caplog, fan.DOMAIN, config1, config2
hass, mqtt_mock_entry_no_yaml_config, caplog, fan.DOMAIN, config1, config2
)
async def test_discovery_update_unchanged_fan(hass, mqtt_mock, caplog):
async def test_discovery_update_unchanged_fan(
hass, mqtt_mock_entry_no_yaml_config, caplog
):
"""Test update of discovered fan."""
data1 = '{ "name": "Beer", "command_topic": "test_topic" }'
with patch(
"homeassistant.components.mqtt.fan.MqttFan.discovery_update"
) as discovery_update:
await help_test_discovery_update_unchanged(
hass, mqtt_mock, caplog, fan.DOMAIN, data1, discovery_update
hass,
mqtt_mock_entry_no_yaml_config,
caplog,
fan.DOMAIN,
data1,
discovery_update,
)
@pytest.mark.no_fail_on_log_exception
async def test_discovery_broken(hass, mqtt_mock, caplog):
async def test_discovery_broken(hass, mqtt_mock_entry_no_yaml_config, caplog):
"""Test handling of bad discovery message."""
data1 = '{ "name": "Beer" }'
data2 = '{ "name": "Milk", "command_topic": "test_topic" }'
await help_test_discovery_broken(hass, mqtt_mock, caplog, fan.DOMAIN, data1, data2)
await help_test_discovery_broken(
hass, mqtt_mock_entry_no_yaml_config, caplog, fan.DOMAIN, data1, data2
)
async def test_entity_device_info_with_connection(hass, mqtt_mock):
async def test_entity_device_info_with_connection(hass, mqtt_mock_entry_no_yaml_config):
"""Test MQTT fan device registry integration."""
await help_test_entity_device_info_with_connection(
hass, mqtt_mock, fan.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_no_yaml_config, fan.DOMAIN, DEFAULT_CONFIG
)
async def test_entity_device_info_with_identifier(hass, mqtt_mock):
async def test_entity_device_info_with_identifier(hass, mqtt_mock_entry_no_yaml_config):
"""Test MQTT fan device registry integration."""
await help_test_entity_device_info_with_identifier(
hass, mqtt_mock, fan.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_no_yaml_config, fan.DOMAIN, DEFAULT_CONFIG
)
async def test_entity_device_info_update(hass, mqtt_mock):
async def test_entity_device_info_update(hass, mqtt_mock_entry_no_yaml_config):
"""Test device registry update."""
await help_test_entity_device_info_update(
hass, mqtt_mock, fan.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_no_yaml_config, fan.DOMAIN, DEFAULT_CONFIG
)
async def test_entity_device_info_remove(hass, mqtt_mock):
async def test_entity_device_info_remove(hass, mqtt_mock_entry_no_yaml_config):
"""Test device registry remove."""
await help_test_entity_device_info_remove(
hass, mqtt_mock, fan.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_no_yaml_config, fan.DOMAIN, DEFAULT_CONFIG
)
async def test_entity_id_update_subscriptions(hass, mqtt_mock):
async def test_entity_id_update_subscriptions(hass, mqtt_mock_entry_with_yaml_config):
"""Test MQTT subscriptions are managed when entity_id is updated."""
await help_test_entity_id_update_subscriptions(
hass, mqtt_mock, fan.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_with_yaml_config, fan.DOMAIN, DEFAULT_CONFIG
)
async def test_entity_id_update_discovery_update(hass, mqtt_mock):
async def test_entity_id_update_discovery_update(hass, mqtt_mock_entry_no_yaml_config):
"""Test MQTT discovery update when entity_id is updated."""
await help_test_entity_id_update_discovery_update(
hass, mqtt_mock, fan.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_no_yaml_config, fan.DOMAIN, DEFAULT_CONFIG
)
async def test_entity_debug_info_message(hass, mqtt_mock):
async def test_entity_debug_info_message(hass, mqtt_mock_entry_no_yaml_config):
"""Test MQTT debug info."""
await help_test_entity_debug_info_message(
hass, mqtt_mock, fan.DOMAIN, DEFAULT_CONFIG, fan.SERVICE_TURN_ON
hass,
mqtt_mock_entry_no_yaml_config,
fan.DOMAIN,
DEFAULT_CONFIG,
fan.SERVICE_TURN_ON,
)
@ -1766,7 +1850,7 @@ async def test_entity_debug_info_message(hass, mqtt_mock):
)
async def test_publishing_with_custom_encoding(
hass,
mqtt_mock,
mqtt_mock_entry_with_yaml_config,
caplog,
service,
topic,
@ -1782,7 +1866,7 @@ async def test_publishing_with_custom_encoding(
await help_test_publishing_with_custom_encoding(
hass,
mqtt_mock,
mqtt_mock_entry_with_yaml_config,
caplog,
domain,
config,
@ -1794,11 +1878,13 @@ async def test_publishing_with_custom_encoding(
)
async def test_reloadable(hass, mqtt_mock, caplog, tmp_path):
async def test_reloadable(hass, mqtt_mock_entry_with_yaml_config, caplog, tmp_path):
"""Test reloading the MQTT platform."""
domain = fan.DOMAIN
config = DEFAULT_CONFIG[domain]
await help_test_reloadable(hass, mqtt_mock, caplog, tmp_path, domain, config)
await help_test_reloadable(
hass, mqtt_mock_entry_with_yaml_config, caplog, tmp_path, domain, config
)
async def test_reloadable_late(hass, mqtt_client_mock, caplog, tmp_path):

View File

@ -116,7 +116,7 @@ async def async_set_humidity(
await hass.services.async_call(DOMAIN, SERVICE_SET_HUMIDITY, data, blocking=True)
async def test_fail_setup_if_no_command_topic(hass, mqtt_mock):
async def test_fail_setup_if_no_command_topic(hass, mqtt_mock_entry_no_yaml_config):
"""Test if command fails with command topic."""
assert await async_setup_component(
hass,
@ -124,10 +124,13 @@ async def test_fail_setup_if_no_command_topic(hass, mqtt_mock):
{humidifier.DOMAIN: {"platform": "mqtt", "name": "test"}},
)
await hass.async_block_till_done()
await mqtt_mock_entry_no_yaml_config()
assert hass.states.get("humidifier.test") is None
async def test_controlling_state_via_topic(hass, mqtt_mock, caplog):
async def test_controlling_state_via_topic(
hass, mqtt_mock_entry_with_yaml_config, caplog
):
"""Test the controlling state via topic."""
assert await async_setup_component(
hass,
@ -158,6 +161,7 @@ async def test_controlling_state_via_topic(hass, mqtt_mock, caplog):
},
)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("humidifier.test")
assert state.state == STATE_UNKNOWN
@ -228,7 +232,9 @@ async def test_controlling_state_via_topic(hass, mqtt_mock, caplog):
assert state.state == STATE_UNKNOWN
async def test_controlling_state_via_topic_and_json_message(hass, mqtt_mock, caplog):
async def test_controlling_state_via_topic_and_json_message(
hass, mqtt_mock_entry_with_yaml_config, caplog
):
"""Test the controlling state via topic and JSON message."""
assert await async_setup_component(
hass,
@ -255,6 +261,7 @@ async def test_controlling_state_via_topic_and_json_message(hass, mqtt_mock, cap
},
)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("humidifier.test")
assert state.state == STATE_UNKNOWN
@ -314,7 +321,7 @@ async def test_controlling_state_via_topic_and_json_message(hass, mqtt_mock, cap
async def test_controlling_state_via_topic_and_json_message_shared_topic(
hass, mqtt_mock, caplog
hass, mqtt_mock_entry_with_yaml_config, caplog
):
"""Test the controlling state via topic and JSON message using a shared topic."""
assert await async_setup_component(
@ -342,6 +349,7 @@ async def test_controlling_state_via_topic_and_json_message_shared_topic(
},
)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("humidifier.test")
assert state.state == STATE_UNKNOWN
@ -390,7 +398,9 @@ async def test_controlling_state_via_topic_and_json_message_shared_topic(
caplog.clear()
async def test_sending_mqtt_commands_and_optimistic(hass, mqtt_mock, caplog):
async def test_sending_mqtt_commands_and_optimistic(
hass, mqtt_mock_entry_with_yaml_config, caplog
):
"""Test optimistic mode without state topic."""
assert await async_setup_component(
hass,
@ -413,6 +423,7 @@ async def test_sending_mqtt_commands_and_optimistic(hass, mqtt_mock, caplog):
},
)
await hass.async_block_till_done()
mqtt_mock = await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("humidifier.test")
assert state.state == STATE_UNKNOWN
@ -483,7 +494,9 @@ async def test_sending_mqtt_commands_and_optimistic(hass, mqtt_mock, caplog):
assert state.attributes.get(ATTR_ASSUMED_STATE)
async def test_sending_mqtt_command_templates_(hass, mqtt_mock, caplog):
async def test_sending_mqtt_command_templates_(
hass, mqtt_mock_entry_with_yaml_config, caplog
):
"""Testing command templates with optimistic mode without state topic."""
assert await async_setup_component(
hass,
@ -507,6 +520,7 @@ async def test_sending_mqtt_command_templates_(hass, mqtt_mock, caplog):
},
)
await hass.async_block_till_done()
mqtt_mock = await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("humidifier.test")
assert state.state == STATE_UNKNOWN
@ -577,7 +591,9 @@ async def test_sending_mqtt_command_templates_(hass, mqtt_mock, caplog):
assert state.attributes.get(ATTR_ASSUMED_STATE)
async def test_sending_mqtt_commands_and_explicit_optimistic(hass, mqtt_mock, caplog):
async def test_sending_mqtt_commands_and_explicit_optimistic(
hass, mqtt_mock_entry_with_yaml_config, caplog
):
"""Test optimistic mode with state topic and turn on attributes."""
assert await async_setup_component(
hass,
@ -602,6 +618,7 @@ async def test_sending_mqtt_commands_and_explicit_optimistic(hass, mqtt_mock, ca
},
)
await hass.async_block_till_done()
mqtt_mock = await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("humidifier.test")
assert state.state == STATE_UNKNOWN
@ -701,7 +718,13 @@ async def test_sending_mqtt_commands_and_explicit_optimistic(hass, mqtt_mock, ca
],
)
async def test_encoding_subscribable_topics(
hass, mqtt_mock, caplog, topic, value, attribute, attribute_value
hass,
mqtt_mock_entry_with_yaml_config,
caplog,
topic,
value,
attribute,
attribute_value,
):
"""Test handling of incoming encoded payload."""
config = copy.deepcopy(DEFAULT_CONFIG[humidifier.DOMAIN])
@ -709,7 +732,7 @@ async def test_encoding_subscribable_topics(
config[CONF_MODE_COMMAND_TOPIC] = "humidifier/some_mode_command_topic"
await help_test_encoding_subscribable_topics(
hass,
mqtt_mock,
mqtt_mock_entry_with_yaml_config,
caplog,
humidifier.DOMAIN,
config,
@ -720,7 +743,7 @@ async def test_encoding_subscribable_topics(
)
async def test_attributes(hass, mqtt_mock, caplog):
async def test_attributes(hass, mqtt_mock_entry_with_yaml_config, caplog):
"""Test attributes."""
assert await async_setup_component(
hass,
@ -740,6 +763,7 @@ async def test_attributes(hass, mqtt_mock, caplog):
},
)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("humidifier.test")
assert state.state == STATE_UNKNOWN
@ -765,7 +789,7 @@ async def test_attributes(hass, mqtt_mock, caplog):
assert state.attributes.get(humidifier.ATTR_MODE) is None
async def test_invalid_configurations(hass, mqtt_mock, caplog):
async def test_invalid_configurations(hass, mqtt_mock_entry_with_yaml_config, caplog):
"""Test invalid configurations."""
assert await async_setup_component(
hass,
@ -834,6 +858,7 @@ async def test_invalid_configurations(hass, mqtt_mock, caplog):
},
)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
assert hass.states.get("humidifier.test_valid_1") is not None
assert hass.states.get("humidifier.test_valid_2") is not None
assert hass.states.get("humidifier.test_valid_3") is not None
@ -847,7 +872,7 @@ async def test_invalid_configurations(hass, mqtt_mock, caplog):
assert hass.states.get("humidifier.test_invalid_mode_is_reset") is None
async def test_supported_features(hass, mqtt_mock):
async def test_supported_features(hass, mqtt_mock_entry_with_yaml_config):
"""Test supported features."""
assert await async_setup_component(
hass,
@ -896,6 +921,7 @@ async def test_supported_features(hass, mqtt_mock):
},
)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("humidifier.test1")
assert state.attributes.get(ATTR_SUPPORTED_FEATURES) == 0
@ -916,81 +942,111 @@ async def test_supported_features(hass, mqtt_mock):
assert state is None
async def test_availability_when_connection_lost(hass, mqtt_mock):
async def test_availability_when_connection_lost(
hass, mqtt_mock_entry_with_yaml_config
):
"""Test availability after MQTT disconnection."""
await help_test_availability_when_connection_lost(
hass, mqtt_mock, humidifier.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_with_yaml_config, humidifier.DOMAIN, DEFAULT_CONFIG
)
async def test_availability_without_topic(hass, mqtt_mock):
async def test_availability_without_topic(hass, mqtt_mock_entry_with_yaml_config):
"""Test availability without defined availability topic."""
await help_test_availability_without_topic(
hass, mqtt_mock, humidifier.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_with_yaml_config, humidifier.DOMAIN, DEFAULT_CONFIG
)
async def test_default_availability_payload(hass, mqtt_mock):
async def test_default_availability_payload(hass, mqtt_mock_entry_with_yaml_config):
"""Test availability by default payload with defined topic."""
await help_test_default_availability_payload(
hass, mqtt_mock, humidifier.DOMAIN, DEFAULT_CONFIG, True, "state-topic", "1"
hass,
mqtt_mock_entry_with_yaml_config,
humidifier.DOMAIN,
DEFAULT_CONFIG,
True,
"state-topic",
"1",
)
async def test_custom_availability_payload(hass, mqtt_mock):
async def test_custom_availability_payload(hass, mqtt_mock_entry_with_yaml_config):
"""Test availability by custom payload with defined topic."""
await help_test_custom_availability_payload(
hass, mqtt_mock, humidifier.DOMAIN, DEFAULT_CONFIG, True, "state-topic", "1"
hass,
mqtt_mock_entry_with_yaml_config,
humidifier.DOMAIN,
DEFAULT_CONFIG,
True,
"state-topic",
"1",
)
async def test_setting_attribute_via_mqtt_json_message(hass, mqtt_mock):
async def test_setting_attribute_via_mqtt_json_message(
hass, mqtt_mock_entry_with_yaml_config
):
"""Test the setting of attribute via MQTT with JSON payload."""
await help_test_setting_attribute_via_mqtt_json_message(
hass, mqtt_mock, humidifier.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_with_yaml_config, humidifier.DOMAIN, DEFAULT_CONFIG
)
async def test_setting_blocked_attribute_via_mqtt_json_message(hass, mqtt_mock):
async def test_setting_blocked_attribute_via_mqtt_json_message(
hass, mqtt_mock_entry_no_yaml_config
):
"""Test the setting of attribute via MQTT with JSON payload."""
await help_test_setting_blocked_attribute_via_mqtt_json_message(
hass,
mqtt_mock,
mqtt_mock_entry_no_yaml_config,
humidifier.DOMAIN,
DEFAULT_CONFIG,
MQTT_HUMIDIFIER_ATTRIBUTES_BLOCKED,
)
async def test_setting_attribute_with_template(hass, mqtt_mock):
async def test_setting_attribute_with_template(hass, mqtt_mock_entry_with_yaml_config):
"""Test the setting of attribute via MQTT with JSON payload."""
await help_test_setting_attribute_with_template(
hass, mqtt_mock, humidifier.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_with_yaml_config, humidifier.DOMAIN, DEFAULT_CONFIG
)
async def test_update_with_json_attrs_not_dict(hass, mqtt_mock, caplog):
async def test_update_with_json_attrs_not_dict(
hass, mqtt_mock_entry_with_yaml_config, caplog
):
"""Test attributes get extracted from a JSON result."""
await help_test_update_with_json_attrs_not_dict(
hass, mqtt_mock, caplog, humidifier.DOMAIN, DEFAULT_CONFIG
hass,
mqtt_mock_entry_with_yaml_config,
caplog,
humidifier.DOMAIN,
DEFAULT_CONFIG,
)
async def test_update_with_json_attrs_bad_json(hass, mqtt_mock, caplog):
async def test_update_with_json_attrs_bad_json(
hass, mqtt_mock_entry_with_yaml_config, caplog
):
"""Test attributes get extracted from a JSON result."""
await help_test_update_with_json_attrs_bad_JSON(
hass, mqtt_mock, caplog, humidifier.DOMAIN, DEFAULT_CONFIG
hass,
mqtt_mock_entry_with_yaml_config,
caplog,
humidifier.DOMAIN,
DEFAULT_CONFIG,
)
async def test_discovery_update_attr(hass, mqtt_mock, caplog):
async def test_discovery_update_attr(hass, mqtt_mock_entry_no_yaml_config, caplog):
"""Test update of discovered MQTTAttributes."""
await help_test_discovery_update_attr(
hass, mqtt_mock, caplog, humidifier.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_no_yaml_config, caplog, humidifier.DOMAIN, DEFAULT_CONFIG
)
async def test_unique_id(hass, mqtt_mock):
async def test_unique_id(hass, mqtt_mock_entry_with_yaml_config):
"""Test unique_id option only creates one fan per id."""
config = {
humidifier.DOMAIN: [
@ -1012,16 +1068,24 @@ async def test_unique_id(hass, mqtt_mock):
},
]
}
await help_test_unique_id(hass, mqtt_mock, humidifier.DOMAIN, config)
await help_test_unique_id(
hass, mqtt_mock_entry_with_yaml_config, humidifier.DOMAIN, config
)
async def test_discovery_removal_humidifier(hass, mqtt_mock, caplog):
async def test_discovery_removal_humidifier(
hass, mqtt_mock_entry_no_yaml_config, caplog
):
"""Test removal of discovered humidifier."""
data = '{ "name": "test", "command_topic": "test_topic", "target_humidity_command_topic": "test-topic2" }'
await help_test_discovery_removal(hass, mqtt_mock, caplog, humidifier.DOMAIN, data)
await help_test_discovery_removal(
hass, mqtt_mock_entry_no_yaml_config, caplog, humidifier.DOMAIN, data
)
async def test_discovery_update_humidifier(hass, mqtt_mock, caplog):
async def test_discovery_update_humidifier(
hass, mqtt_mock_entry_no_yaml_config, caplog
):
"""Test update of discovered humidifier."""
config1 = {
"name": "Beer",
@ -1034,77 +1098,93 @@ async def test_discovery_update_humidifier(hass, mqtt_mock, caplog):
"target_humidity_command_topic": "test-topic2",
}
await help_test_discovery_update(
hass, mqtt_mock, caplog, humidifier.DOMAIN, config1, config2
hass,
mqtt_mock_entry_no_yaml_config,
caplog,
humidifier.DOMAIN,
config1,
config2,
)
async def test_discovery_update_unchanged_humidifier(hass, mqtt_mock, caplog):
async def test_discovery_update_unchanged_humidifier(
hass, mqtt_mock_entry_no_yaml_config, caplog
):
"""Test update of discovered humidifier."""
data1 = '{ "name": "Beer", "command_topic": "test_topic", "target_humidity_command_topic": "test-topic2" }'
with patch(
"homeassistant.components.mqtt.fan.MqttFan.discovery_update"
) as discovery_update:
await help_test_discovery_update_unchanged(
hass, mqtt_mock, caplog, humidifier.DOMAIN, data1, discovery_update
hass,
mqtt_mock_entry_no_yaml_config,
caplog,
humidifier.DOMAIN,
data1,
discovery_update,
)
@pytest.mark.no_fail_on_log_exception
async def test_discovery_broken(hass, mqtt_mock, caplog):
async def test_discovery_broken(hass, mqtt_mock_entry_no_yaml_config, caplog):
"""Test handling of bad discovery message."""
data1 = '{ "name": "Beer" }'
data2 = '{ "name": "Milk", "command_topic": "test_topic", "target_humidity_command_topic": "test-topic2" }'
await help_test_discovery_broken(
hass, mqtt_mock, caplog, humidifier.DOMAIN, data1, data2
hass, mqtt_mock_entry_no_yaml_config, caplog, humidifier.DOMAIN, data1, data2
)
async def test_entity_device_info_with_connection(hass, mqtt_mock):
async def test_entity_device_info_with_connection(hass, mqtt_mock_entry_no_yaml_config):
"""Test MQTT fan device registry integration."""
await help_test_entity_device_info_with_connection(
hass, mqtt_mock, humidifier.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_no_yaml_config, humidifier.DOMAIN, DEFAULT_CONFIG
)
async def test_entity_device_info_with_identifier(hass, mqtt_mock):
async def test_entity_device_info_with_identifier(hass, mqtt_mock_entry_no_yaml_config):
"""Test MQTT fan device registry integration."""
await help_test_entity_device_info_with_identifier(
hass, mqtt_mock, humidifier.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_no_yaml_config, humidifier.DOMAIN, DEFAULT_CONFIG
)
async def test_entity_device_info_update(hass, mqtt_mock):
async def test_entity_device_info_update(hass, mqtt_mock_entry_no_yaml_config):
"""Test device registry update."""
await help_test_entity_device_info_update(
hass, mqtt_mock, humidifier.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_no_yaml_config, humidifier.DOMAIN, DEFAULT_CONFIG
)
async def test_entity_device_info_remove(hass, mqtt_mock):
async def test_entity_device_info_remove(hass, mqtt_mock_entry_no_yaml_config):
"""Test device registry remove."""
await help_test_entity_device_info_remove(
hass, mqtt_mock, humidifier.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_no_yaml_config, humidifier.DOMAIN, DEFAULT_CONFIG
)
async def test_entity_id_update_subscriptions(hass, mqtt_mock):
async def test_entity_id_update_subscriptions(hass, mqtt_mock_entry_with_yaml_config):
"""Test MQTT subscriptions are managed when entity_id is updated."""
await help_test_entity_id_update_subscriptions(
hass, mqtt_mock, humidifier.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_with_yaml_config, humidifier.DOMAIN, DEFAULT_CONFIG
)
async def test_entity_id_update_discovery_update(hass, mqtt_mock):
async def test_entity_id_update_discovery_update(hass, mqtt_mock_entry_no_yaml_config):
"""Test MQTT discovery update when entity_id is updated."""
await help_test_entity_id_update_discovery_update(
hass, mqtt_mock, humidifier.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_no_yaml_config, humidifier.DOMAIN, DEFAULT_CONFIG
)
async def test_entity_debug_info_message(hass, mqtt_mock):
async def test_entity_debug_info_message(hass, mqtt_mock_entry_no_yaml_config):
"""Test MQTT debug info."""
await help_test_entity_debug_info_message(
hass, mqtt_mock, humidifier.DOMAIN, DEFAULT_CONFIG, humidifier.SERVICE_TURN_ON
hass,
mqtt_mock_entry_no_yaml_config,
humidifier.DOMAIN,
DEFAULT_CONFIG,
humidifier.SERVICE_TURN_ON,
)
@ -1143,7 +1223,7 @@ async def test_entity_debug_info_message(hass, mqtt_mock):
)
async def test_publishing_with_custom_encoding(
hass,
mqtt_mock,
mqtt_mock_entry_with_yaml_config,
caplog,
service,
topic,
@ -1159,7 +1239,7 @@ async def test_publishing_with_custom_encoding(
await help_test_publishing_with_custom_encoding(
hass,
mqtt_mock,
mqtt_mock_entry_with_yaml_config,
caplog,
domain,
config,
@ -1171,11 +1251,13 @@ async def test_publishing_with_custom_encoding(
)
async def test_reloadable(hass, mqtt_mock, caplog, tmp_path):
async def test_reloadable(hass, mqtt_mock_entry_with_yaml_config, caplog, tmp_path):
"""Test reloading the MQTT platform."""
domain = humidifier.DOMAIN
config = DEFAULT_CONFIG[domain]
await help_test_reloadable(hass, mqtt_mock, caplog, tmp_path, domain, config)
await help_test_reloadable(
hass, mqtt_mock_entry_with_yaml_config, caplog, tmp_path, domain, config
)
async def test_reloadable_late(hass, mqtt_client_mock, caplog, tmp_path):

View File

@ -96,22 +96,27 @@ def record_calls(calls):
async def test_mqtt_connects_on_home_assistant_mqtt_setup(
hass, mqtt_client_mock, mqtt_mock
hass, mqtt_client_mock, mqtt_mock_entry_no_yaml_config
):
"""Test if client is connected after mqtt init on bootstrap."""
await mqtt_mock_entry_no_yaml_config()
assert mqtt_client_mock.connect.call_count == 1
async def test_mqtt_disconnects_on_home_assistant_stop(hass, mqtt_mock):
async def test_mqtt_disconnects_on_home_assistant_stop(
hass, mqtt_mock_entry_no_yaml_config
):
"""Test if client stops on HA stop."""
mqtt_mock = await mqtt_mock_entry_no_yaml_config()
hass.bus.fire(EVENT_HOMEASSISTANT_STOP)
await hass.async_block_till_done()
await hass.async_block_till_done()
assert mqtt_mock.async_disconnect.called
async def test_publish(hass, mqtt_mock):
async def test_publish(hass, mqtt_mock_entry_no_yaml_config):
"""Test the publish function."""
mqtt_mock = await mqtt_mock_entry_no_yaml_config()
await mqtt.async_publish(hass, "test-topic", "test-payload")
await hass.async_block_till_done()
assert mqtt_mock.async_publish.called
@ -208,7 +213,7 @@ async def test_command_template_value(hass):
assert cmd_tpl.async_render(None, variables=variables) == "beer"
async def test_command_template_variables(hass, mqtt_mock):
async def test_command_template_variables(hass, mqtt_mock_entry_with_yaml_config):
"""Test the rendering of enitity_variables."""
topic = "test/select"
@ -232,6 +237,7 @@ async def test_command_template_variables(hass, mqtt_mock):
},
)
await hass.async_block_till_done()
mqtt_mock = await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("select.test_select")
assert state.state == "milk"
@ -291,8 +297,11 @@ async def test_value_template_value(hass):
assert val_tpl.async_render_with_possible_json_value('{"id": 4321}') == "4321"
async def test_service_call_without_topic_does_not_publish(hass, mqtt_mock):
async def test_service_call_without_topic_does_not_publish(
hass, mqtt_mock_entry_no_yaml_config
):
"""Test the service call if topic is missing."""
mqtt_mock = await mqtt_mock_entry_no_yaml_config()
with pytest.raises(vol.Invalid):
await hass.services.async_call(
mqtt.DOMAIN,
@ -304,12 +313,13 @@ async def test_service_call_without_topic_does_not_publish(hass, mqtt_mock):
async def test_service_call_with_topic_and_topic_template_does_not_publish(
hass, mqtt_mock
hass, mqtt_mock_entry_no_yaml_config
):
"""Test the service call with topic/topic template.
If both 'topic' and 'topic_template' are provided then fail.
"""
mqtt_mock = await mqtt_mock_entry_no_yaml_config()
topic = "test/topic"
topic_template = "test/{{ 'topic' }}"
with pytest.raises(vol.Invalid):
@ -327,9 +337,10 @@ async def test_service_call_with_topic_and_topic_template_does_not_publish(
async def test_service_call_with_invalid_topic_template_does_not_publish(
hass, mqtt_mock
hass, mqtt_mock_entry_no_yaml_config
):
"""Test the service call with a problematic topic template."""
mqtt_mock = await mqtt_mock_entry_no_yaml_config()
await hass.services.async_call(
mqtt.DOMAIN,
mqtt.SERVICE_PUBLISH,
@ -342,11 +353,14 @@ async def test_service_call_with_invalid_topic_template_does_not_publish(
assert not mqtt_mock.async_publish.called
async def test_service_call_with_template_topic_renders_template(hass, mqtt_mock):
async def test_service_call_with_template_topic_renders_template(
hass, mqtt_mock_entry_no_yaml_config
):
"""Test the service call with rendered topic template.
If 'topic_template' is provided and 'topic' is not, then render it.
"""
mqtt_mock = await mqtt_mock_entry_no_yaml_config()
await hass.services.async_call(
mqtt.DOMAIN,
mqtt.SERVICE_PUBLISH,
@ -360,11 +374,14 @@ async def test_service_call_with_template_topic_renders_template(hass, mqtt_mock
assert mqtt_mock.async_publish.call_args[0][0] == "test/2"
async def test_service_call_with_template_topic_renders_invalid_topic(hass, mqtt_mock):
async def test_service_call_with_template_topic_renders_invalid_topic(
hass, mqtt_mock_entry_no_yaml_config
):
"""Test the service call with rendered, invalid topic template.
If a wildcard topic is rendered, then fail.
"""
mqtt_mock = await mqtt_mock_entry_no_yaml_config()
await hass.services.async_call(
mqtt.DOMAIN,
mqtt.SERVICE_PUBLISH,
@ -378,12 +395,13 @@ async def test_service_call_with_template_topic_renders_invalid_topic(hass, mqtt
async def test_service_call_with_invalid_rendered_template_topic_doesnt_render_template(
hass, mqtt_mock
hass, mqtt_mock_entry_no_yaml_config
):
"""Test the service call with unrendered template.
If both 'payload' and 'payload_template' are provided then fail.
"""
mqtt_mock = await mqtt_mock_entry_no_yaml_config()
payload = "not a template"
payload_template = "a template"
with pytest.raises(vol.Invalid):
@ -400,11 +418,14 @@ async def test_service_call_with_invalid_rendered_template_topic_doesnt_render_t
assert not mqtt_mock.async_publish.called
async def test_service_call_with_template_payload_renders_template(hass, mqtt_mock):
async def test_service_call_with_template_payload_renders_template(
hass, mqtt_mock_entry_no_yaml_config
):
"""Test the service call with rendered template.
If 'payload_template' is provided and 'payload' is not, then render it.
"""
mqtt_mock = await mqtt_mock_entry_no_yaml_config()
await hass.services.async_call(
mqtt.DOMAIN,
mqtt.SERVICE_PUBLISH,
@ -429,8 +450,9 @@ async def test_service_call_with_template_payload_renders_template(hass, mqtt_mo
mqtt_mock.reset_mock()
async def test_service_call_with_bad_template(hass, mqtt_mock):
async def test_service_call_with_bad_template(hass, mqtt_mock_entry_no_yaml_config):
"""Test the service call with a bad template does not publish."""
mqtt_mock = await mqtt_mock_entry_no_yaml_config()
await hass.services.async_call(
mqtt.DOMAIN,
mqtt.SERVICE_PUBLISH,
@ -440,11 +462,14 @@ async def test_service_call_with_bad_template(hass, mqtt_mock):
assert not mqtt_mock.async_publish.called
async def test_service_call_with_payload_doesnt_render_template(hass, mqtt_mock):
async def test_service_call_with_payload_doesnt_render_template(
hass, mqtt_mock_entry_no_yaml_config
):
"""Test the service call with unrendered template.
If both 'payload' and 'payload_template' are provided then fail.
"""
mqtt_mock = await mqtt_mock_entry_no_yaml_config()
payload = "not a template"
payload_template = "a template"
with pytest.raises(vol.Invalid):
@ -461,11 +486,14 @@ async def test_service_call_with_payload_doesnt_render_template(hass, mqtt_mock)
assert not mqtt_mock.async_publish.called
async def test_service_call_with_ascii_qos_retain_flags(hass, mqtt_mock):
async def test_service_call_with_ascii_qos_retain_flags(
hass, mqtt_mock_entry_no_yaml_config
):
"""Test the service call with args that can be misinterpreted.
Empty payload message and ascii formatted qos and retain flags.
"""
mqtt_mock = await mqtt_mock_entry_no_yaml_config()
await hass.services.async_call(
mqtt.DOMAIN,
mqtt.SERVICE_PUBLISH,
@ -665,9 +693,10 @@ def test_entity_device_info_schema():
async def test_receiving_non_utf8_message_gets_logged(
hass, mqtt_mock, calls, record_calls, caplog
hass, mqtt_mock_entry_no_yaml_config, calls, record_calls, caplog
):
"""Test receiving a non utf8 encoded message."""
await mqtt_mock_entry_no_yaml_config()
await mqtt.async_subscribe(hass, "test-topic", record_calls)
async_fire_mqtt_message(hass, "test-topic", b"\x9a")
@ -679,9 +708,10 @@ async def test_receiving_non_utf8_message_gets_logged(
async def test_all_subscriptions_run_when_decode_fails(
hass, mqtt_mock, calls, record_calls
hass, mqtt_mock_entry_no_yaml_config, calls, record_calls
):
"""Test all other subscriptions still run when decode fails for one."""
await mqtt_mock_entry_no_yaml_config()
await mqtt.async_subscribe(hass, "test-topic", record_calls, encoding="ascii")
await mqtt.async_subscribe(hass, "test-topic", record_calls)
@ -691,8 +721,11 @@ async def test_all_subscriptions_run_when_decode_fails(
assert len(calls) == 1
async def test_subscribe_topic(hass, mqtt_mock, calls, record_calls):
async def test_subscribe_topic(
hass, mqtt_mock_entry_no_yaml_config, calls, record_calls
):
"""Test the subscription of a topic."""
await mqtt_mock_entry_no_yaml_config()
unsub = await mqtt.async_subscribe(hass, "test-topic", record_calls)
async_fire_mqtt_message(hass, "test-topic", "test-payload")
@ -714,8 +747,11 @@ async def test_subscribe_topic(hass, mqtt_mock, calls, record_calls):
unsub()
async def test_subscribe_topic_non_async(hass, mqtt_mock, calls, record_calls):
async def test_subscribe_topic_non_async(
hass, mqtt_mock_entry_no_yaml_config, calls, record_calls
):
"""Test the subscription of a topic using the non-async function."""
await mqtt_mock_entry_no_yaml_config()
unsub = await hass.async_add_executor_job(
mqtt.subscribe, hass, "test-topic", record_calls
)
@ -736,14 +772,18 @@ async def test_subscribe_topic_non_async(hass, mqtt_mock, calls, record_calls):
assert len(calls) == 1
async def test_subscribe_bad_topic(hass, mqtt_mock, calls, record_calls):
async def test_subscribe_bad_topic(
hass, mqtt_mock_entry_no_yaml_config, calls, record_calls
):
"""Test the subscription of a topic."""
await mqtt_mock_entry_no_yaml_config()
with pytest.raises(HomeAssistantError):
await mqtt.async_subscribe(hass, 55, record_calls)
async def test_subscribe_deprecated(hass, mqtt_mock):
async def test_subscribe_deprecated(hass, mqtt_mock_entry_no_yaml_config):
"""Test the subscription of a topic using deprecated callback signature."""
mqtt_mock = await mqtt_mock_entry_no_yaml_config()
@callback
def record_calls(topic, payload, qos):
@ -789,8 +829,9 @@ async def test_subscribe_deprecated(hass, mqtt_mock):
assert len(calls) == 1
async def test_subscribe_deprecated_async(hass, mqtt_mock):
async def test_subscribe_deprecated_async(hass, mqtt_mock_entry_no_yaml_config):
"""Test the subscription of a topic using deprecated coroutine signature."""
mqtt_mock = await mqtt_mock_entry_no_yaml_config()
def async_record_calls(topic, payload, qos):
"""Record calls."""
@ -835,8 +876,11 @@ async def test_subscribe_deprecated_async(hass, mqtt_mock):
assert len(calls) == 1
async def test_subscribe_topic_not_match(hass, mqtt_mock, calls, record_calls):
async def test_subscribe_topic_not_match(
hass, mqtt_mock_entry_no_yaml_config, calls, record_calls
):
"""Test if subscribed topic is not a match."""
await mqtt_mock_entry_no_yaml_config()
await mqtt.async_subscribe(hass, "test-topic", record_calls)
async_fire_mqtt_message(hass, "another-test-topic", "test-payload")
@ -845,8 +889,11 @@ async def test_subscribe_topic_not_match(hass, mqtt_mock, calls, record_calls):
assert len(calls) == 0
async def test_subscribe_topic_level_wildcard(hass, mqtt_mock, calls, record_calls):
async def test_subscribe_topic_level_wildcard(
hass, mqtt_mock_entry_no_yaml_config, calls, record_calls
):
"""Test the subscription of wildcard topics."""
await mqtt_mock_entry_no_yaml_config()
await mqtt.async_subscribe(hass, "test-topic/+/on", record_calls)
async_fire_mqtt_message(hass, "test-topic/bier/on", "test-payload")
@ -858,9 +905,10 @@ async def test_subscribe_topic_level_wildcard(hass, mqtt_mock, calls, record_cal
async def test_subscribe_topic_level_wildcard_no_subtree_match(
hass, mqtt_mock, calls, record_calls
hass, mqtt_mock_entry_no_yaml_config, calls, record_calls
):
"""Test the subscription of wildcard topics."""
await mqtt_mock_entry_no_yaml_config()
await mqtt.async_subscribe(hass, "test-topic/+/on", record_calls)
async_fire_mqtt_message(hass, "test-topic/bier", "test-payload")
@ -870,9 +918,10 @@ async def test_subscribe_topic_level_wildcard_no_subtree_match(
async def test_subscribe_topic_level_wildcard_root_topic_no_subtree_match(
hass, mqtt_mock, calls, record_calls
hass, mqtt_mock_entry_no_yaml_config, calls, record_calls
):
"""Test the subscription of wildcard topics."""
await mqtt_mock_entry_no_yaml_config()
await mqtt.async_subscribe(hass, "test-topic/#", record_calls)
async_fire_mqtt_message(hass, "test-topic-123", "test-payload")
@ -882,9 +931,10 @@ async def test_subscribe_topic_level_wildcard_root_topic_no_subtree_match(
async def test_subscribe_topic_subtree_wildcard_subtree_topic(
hass, mqtt_mock, calls, record_calls
hass, mqtt_mock_entry_no_yaml_config, calls, record_calls
):
"""Test the subscription of wildcard topics."""
await mqtt_mock_entry_no_yaml_config()
await mqtt.async_subscribe(hass, "test-topic/#", record_calls)
async_fire_mqtt_message(hass, "test-topic/bier/on", "test-payload")
@ -896,9 +946,10 @@ async def test_subscribe_topic_subtree_wildcard_subtree_topic(
async def test_subscribe_topic_subtree_wildcard_root_topic(
hass, mqtt_mock, calls, record_calls
hass, mqtt_mock_entry_no_yaml_config, calls, record_calls
):
"""Test the subscription of wildcard topics."""
await mqtt_mock_entry_no_yaml_config()
await mqtt.async_subscribe(hass, "test-topic/#", record_calls)
async_fire_mqtt_message(hass, "test-topic", "test-payload")
@ -910,9 +961,10 @@ async def test_subscribe_topic_subtree_wildcard_root_topic(
async def test_subscribe_topic_subtree_wildcard_no_match(
hass, mqtt_mock, calls, record_calls
hass, mqtt_mock_entry_no_yaml_config, calls, record_calls
):
"""Test the subscription of wildcard topics."""
await mqtt_mock_entry_no_yaml_config()
await mqtt.async_subscribe(hass, "test-topic/#", record_calls)
async_fire_mqtt_message(hass, "another-test-topic", "test-payload")
@ -922,9 +974,10 @@ async def test_subscribe_topic_subtree_wildcard_no_match(
async def test_subscribe_topic_level_wildcard_and_wildcard_root_topic(
hass, mqtt_mock, calls, record_calls
hass, mqtt_mock_entry_no_yaml_config, calls, record_calls
):
"""Test the subscription of wildcard topics."""
await mqtt_mock_entry_no_yaml_config()
await mqtt.async_subscribe(hass, "+/test-topic/#", record_calls)
async_fire_mqtt_message(hass, "hi/test-topic", "test-payload")
@ -936,9 +989,10 @@ async def test_subscribe_topic_level_wildcard_and_wildcard_root_topic(
async def test_subscribe_topic_level_wildcard_and_wildcard_subtree_topic(
hass, mqtt_mock, calls, record_calls
hass, mqtt_mock_entry_no_yaml_config, calls, record_calls
):
"""Test the subscription of wildcard topics."""
await mqtt_mock_entry_no_yaml_config()
await mqtt.async_subscribe(hass, "+/test-topic/#", record_calls)
async_fire_mqtt_message(hass, "hi/test-topic/here-iam", "test-payload")
@ -950,9 +1004,10 @@ async def test_subscribe_topic_level_wildcard_and_wildcard_subtree_topic(
async def test_subscribe_topic_level_wildcard_and_wildcard_level_no_match(
hass, mqtt_mock, calls, record_calls
hass, mqtt_mock_entry_no_yaml_config, calls, record_calls
):
"""Test the subscription of wildcard topics."""
await mqtt_mock_entry_no_yaml_config()
await mqtt.async_subscribe(hass, "+/test-topic/#", record_calls)
async_fire_mqtt_message(hass, "hi/here-iam/test-topic", "test-payload")
@ -962,9 +1017,10 @@ async def test_subscribe_topic_level_wildcard_and_wildcard_level_no_match(
async def test_subscribe_topic_level_wildcard_and_wildcard_no_match(
hass, mqtt_mock, calls, record_calls
hass, mqtt_mock_entry_no_yaml_config, calls, record_calls
):
"""Test the subscription of wildcard topics."""
await mqtt_mock_entry_no_yaml_config()
await mqtt.async_subscribe(hass, "+/test-topic/#", record_calls)
async_fire_mqtt_message(hass, "hi/another-test-topic", "test-payload")
@ -973,8 +1029,11 @@ async def test_subscribe_topic_level_wildcard_and_wildcard_no_match(
assert len(calls) == 0
async def test_subscribe_topic_sys_root(hass, mqtt_mock, calls, record_calls):
async def test_subscribe_topic_sys_root(
hass, mqtt_mock_entry_no_yaml_config, calls, record_calls
):
"""Test the subscription of $ root topics."""
await mqtt_mock_entry_no_yaml_config()
await mqtt.async_subscribe(hass, "$test-topic/subtree/on", record_calls)
async_fire_mqtt_message(hass, "$test-topic/subtree/on", "test-payload")
@ -986,9 +1045,10 @@ async def test_subscribe_topic_sys_root(hass, mqtt_mock, calls, record_calls):
async def test_subscribe_topic_sys_root_and_wildcard_topic(
hass, mqtt_mock, calls, record_calls
hass, mqtt_mock_entry_no_yaml_config, calls, record_calls
):
"""Test the subscription of $ root and wildcard topics."""
await mqtt_mock_entry_no_yaml_config()
await mqtt.async_subscribe(hass, "$test-topic/#", record_calls)
async_fire_mqtt_message(hass, "$test-topic/some-topic", "test-payload")
@ -1000,9 +1060,10 @@ async def test_subscribe_topic_sys_root_and_wildcard_topic(
async def test_subscribe_topic_sys_root_and_wildcard_subtree_topic(
hass, mqtt_mock, calls, record_calls
hass, mqtt_mock_entry_no_yaml_config, calls, record_calls
):
"""Test the subscription of $ root and wildcard subtree topics."""
await mqtt_mock_entry_no_yaml_config()
await mqtt.async_subscribe(hass, "$test-topic/subtree/#", record_calls)
async_fire_mqtt_message(hass, "$test-topic/subtree/some-topic", "test-payload")
@ -1013,8 +1074,11 @@ async def test_subscribe_topic_sys_root_and_wildcard_subtree_topic(
assert calls[0][0].payload == "test-payload"
async def test_subscribe_special_characters(hass, mqtt_mock, calls, record_calls):
async def test_subscribe_special_characters(
hass, mqtt_mock_entry_no_yaml_config, calls, record_calls
):
"""Test the subscription to topics with special characters."""
await mqtt_mock_entry_no_yaml_config()
topic = "/test-topic/$(.)[^]{-}"
payload = "p4y.l[]a|> ?"
@ -1027,13 +1091,16 @@ async def test_subscribe_special_characters(hass, mqtt_mock, calls, record_calls
assert calls[0][0].payload == payload
async def test_subscribe_same_topic(hass, mqtt_client_mock, mqtt_mock):
async def test_subscribe_same_topic(
hass, mqtt_client_mock, mqtt_mock_entry_no_yaml_config
):
"""
Test subscring to same topic twice and simulate retained messages.
When subscribing to the same topic again, SUBSCRIBE must be sent to the broker again
for it to resend any retained messages.
"""
mqtt_mock = await mqtt_mock_entry_no_yaml_config()
# Fake that the client is connected
mqtt_mock().connected = True
@ -1061,9 +1128,10 @@ async def test_subscribe_same_topic(hass, mqtt_client_mock, mqtt_mock):
async def test_not_calling_unsubscribe_with_active_subscribers(
hass, mqtt_client_mock, mqtt_mock
hass, mqtt_client_mock, mqtt_mock_entry_no_yaml_config
):
"""Test not calling unsubscribe() when other subscribers are active."""
mqtt_mock = await mqtt_mock_entry_no_yaml_config()
# Fake that the client is connected
mqtt_mock().connected = True
@ -1077,8 +1145,9 @@ async def test_not_calling_unsubscribe_with_active_subscribers(
assert not mqtt_client_mock.unsubscribe.called
async def test_unsubscribe_race(hass, mqtt_client_mock, mqtt_mock):
async def test_unsubscribe_race(hass, mqtt_client_mock, mqtt_mock_entry_no_yaml_config):
"""Test not calling unsubscribe() when other subscribers are active."""
mqtt_mock = await mqtt_mock_entry_no_yaml_config()
# Fake that the client is connected
mqtt_mock().connected = True
@ -1113,8 +1182,11 @@ async def test_unsubscribe_race(hass, mqtt_client_mock, mqtt_mock):
"mqtt_config",
[{mqtt.CONF_BROKER: "mock-broker", mqtt.CONF_DISCOVERY: False}],
)
async def test_restore_subscriptions_on_reconnect(hass, mqtt_client_mock, mqtt_mock):
async def test_restore_subscriptions_on_reconnect(
hass, mqtt_client_mock, mqtt_mock_entry_no_yaml_config
):
"""Test subscriptions are restored on reconnect."""
mqtt_mock = await mqtt_mock_entry_no_yaml_config()
# Fake that the client is connected
mqtt_mock().connected = True
@ -1123,7 +1195,7 @@ async def test_restore_subscriptions_on_reconnect(hass, mqtt_client_mock, mqtt_m
assert mqtt_client_mock.subscribe.call_count == 1
mqtt_client_mock.on_disconnect(None, None, 0)
with patch("homeassistant.components.mqtt.DISCOVERY_COOLDOWN", 0):
with patch("homeassistant.components.mqtt.client.DISCOVERY_COOLDOWN", 0):
mqtt_client_mock.on_connect(None, None, None, 0)
await hass.async_block_till_done()
assert mqtt_client_mock.subscribe.call_count == 2
@ -1134,9 +1206,10 @@ async def test_restore_subscriptions_on_reconnect(hass, mqtt_client_mock, mqtt_m
[{mqtt.CONF_BROKER: "mock-broker", mqtt.CONF_DISCOVERY: False}],
)
async def test_restore_all_active_subscriptions_on_reconnect(
hass, mqtt_client_mock, mqtt_mock
hass, mqtt_client_mock, mqtt_mock_entry_no_yaml_config
):
"""Test active subscriptions are restored correctly on reconnect."""
mqtt_mock = await mqtt_mock_entry_no_yaml_config()
# Fake that the client is connected
mqtt_mock().connected = True
@ -1157,7 +1230,7 @@ async def test_restore_all_active_subscriptions_on_reconnect(
assert mqtt_client_mock.unsubscribe.call_count == 0
mqtt_client_mock.on_disconnect(None, None, 0)
with patch("homeassistant.components.mqtt.DISCOVERY_COOLDOWN", 0):
with patch("homeassistant.components.mqtt.client.DISCOVERY_COOLDOWN", 0):
mqtt_client_mock.on_connect(None, None, None, 0)
await hass.async_block_till_done()
@ -1176,9 +1249,10 @@ async def test_initial_setup_logs_error(hass, caplog, mqtt_client_mock):
async def test_logs_error_if_no_connect_broker(
hass, caplog, mqtt_mock, mqtt_client_mock
hass, caplog, mqtt_mock_entry_no_yaml_config, mqtt_client_mock
):
"""Test for setup failure if connection to broker is missing."""
await mqtt_mock_entry_no_yaml_config()
# test with rc = 3 -> broker unavailable
mqtt_client_mock.on_connect(mqtt_client_mock, None, None, 3)
await hass.async_block_till_done()
@ -1188,9 +1262,12 @@ async def test_logs_error_if_no_connect_broker(
)
@patch("homeassistant.components.mqtt.TIMEOUT_ACK", 0.3)
async def test_handle_mqtt_on_callback(hass, caplog, mqtt_mock, mqtt_client_mock):
@patch("homeassistant.components.mqtt.client.TIMEOUT_ACK", 0.3)
async def test_handle_mqtt_on_callback(
hass, caplog, mqtt_mock_entry_no_yaml_config, mqtt_client_mock
):
"""Test receiving an ACK callback before waiting for it."""
await mqtt_mock_entry_no_yaml_config()
# Simulate an ACK for mid == 1, this will call mqtt_mock._mqtt_handle_mid(mid)
mqtt_client_mock.on_publish(mqtt_client_mock, None, 1)
await hass.async_block_till_done()
@ -1224,8 +1301,11 @@ async def test_publish_error(hass, caplog):
assert "Failed to connect to MQTT server: Out of memory." in caplog.text
async def test_handle_message_callback(hass, caplog, mqtt_mock, mqtt_client_mock):
async def test_handle_message_callback(
hass, caplog, mqtt_mock_entry_no_yaml_config, mqtt_client_mock
):
"""Test for handling an incoming message callback."""
await mqtt_mock_entry_no_yaml_config()
msg = ReceiveMessage("some-topic", b"test-payload", 0, False)
mqtt_client_mock.on_connect(mqtt_client_mock, None, None, 0)
await mqtt.async_subscribe(hass, "some-topic", lambda *args: 0)
@ -1331,7 +1411,7 @@ async def test_setup_mqtt_client_protocol(hass):
"""Test MQTT client protocol setup."""
entry = MockConfigEntry(
domain=mqtt.DOMAIN,
data={mqtt.CONF_BROKER: "test-broker", mqtt.CONF_PROTOCOL: "3.1"},
data={mqtt.CONF_BROKER: "test-broker", mqtt.config.CONF_PROTOCOL: "3.1"},
)
with patch("paho.mqtt.client.Client") as mock_client:
mock_client.on_connect(return_value=0)
@ -1341,7 +1421,7 @@ async def test_setup_mqtt_client_protocol(hass):
assert mock_client.call_args[1]["protocol"] == 3
@patch("homeassistant.components.mqtt.TIMEOUT_ACK", 0.2)
@patch("homeassistant.components.mqtt.client.TIMEOUT_ACK", 0.2)
async def test_handle_mqtt_timeout_on_callback(hass, caplog):
"""Test publish without receiving an ACK callback."""
mid = 0
@ -1478,15 +1558,18 @@ async def test_setup_without_tls_config_uses_tlsv1_under_python36(hass):
}
],
)
async def test_custom_birth_message(hass, mqtt_client_mock, mqtt_mock):
async def test_custom_birth_message(
hass, mqtt_client_mock, mqtt_mock_entry_no_yaml_config
):
"""Test sending birth message."""
await mqtt_mock_entry_no_yaml_config()
birth = asyncio.Event()
async def wait_birth(topic, payload, qos):
"""Handle birth message."""
birth.set()
with patch("homeassistant.components.mqtt.DISCOVERY_COOLDOWN", 0.1):
with patch("homeassistant.components.mqtt.client.DISCOVERY_COOLDOWN", 0.1):
await mqtt.async_subscribe(hass, "birth", wait_birth)
mqtt_client_mock.on_connect(None, None, 0, 0)
await hass.async_block_till_done()
@ -1508,15 +1591,18 @@ async def test_custom_birth_message(hass, mqtt_client_mock, mqtt_mock):
}
],
)
async def test_default_birth_message(hass, mqtt_client_mock, mqtt_mock):
async def test_default_birth_message(
hass, mqtt_client_mock, mqtt_mock_entry_no_yaml_config
):
"""Test sending birth message."""
await mqtt_mock_entry_no_yaml_config()
birth = asyncio.Event()
async def wait_birth(topic, payload, qos):
"""Handle birth message."""
birth.set()
with patch("homeassistant.components.mqtt.DISCOVERY_COOLDOWN", 0.1):
with patch("homeassistant.components.mqtt.client.DISCOVERY_COOLDOWN", 0.1):
await mqtt.async_subscribe(hass, "homeassistant/status", wait_birth)
mqtt_client_mock.on_connect(None, None, 0, 0)
await hass.async_block_till_done()
@ -1530,9 +1616,10 @@ async def test_default_birth_message(hass, mqtt_client_mock, mqtt_mock):
"mqtt_config",
[{mqtt.CONF_BROKER: "mock-broker", mqtt.CONF_BIRTH_MESSAGE: {}}],
)
async def test_no_birth_message(hass, mqtt_client_mock, mqtt_mock):
async def test_no_birth_message(hass, mqtt_client_mock, mqtt_mock_entry_no_yaml_config):
"""Test disabling birth message."""
with patch("homeassistant.components.mqtt.DISCOVERY_COOLDOWN", 0.1):
await mqtt_mock_entry_no_yaml_config()
with patch("homeassistant.components.mqtt.client.DISCOVERY_COOLDOWN", 0.1):
mqtt_client_mock.on_connect(None, None, 0, 0)
await hass.async_block_till_done()
await asyncio.sleep(0.2)
@ -1553,8 +1640,12 @@ async def test_no_birth_message(hass, mqtt_client_mock, mqtt_mock):
}
],
)
async def test_delayed_birth_message(hass, mqtt_client_mock, mqtt_config, mqtt_mock):
async def test_delayed_birth_message(
hass, mqtt_client_mock, mqtt_config, mqtt_mock_entry_no_yaml_config
):
"""Test sending birth message does not happen until Home Assistant starts."""
mqtt_mock = await mqtt_mock_entry_no_yaml_config()
hass.state = CoreState.starting
birth = asyncio.Event()
@ -1580,7 +1671,7 @@ async def test_delayed_birth_message(hass, mqtt_client_mock, mqtt_config, mqtt_m
"""Handle birth message."""
birth.set()
with patch("homeassistant.components.mqtt.DISCOVERY_COOLDOWN", 0.1):
with patch("homeassistant.components.mqtt.client.DISCOVERY_COOLDOWN", 0.1):
await mqtt.async_subscribe(hass, "homeassistant/status", wait_birth)
mqtt_client_mock.on_connect(None, None, 0, 0)
await hass.async_block_till_done()
@ -1610,15 +1701,23 @@ async def test_delayed_birth_message(hass, mqtt_client_mock, mqtt_config, mqtt_m
}
],
)
async def test_custom_will_message(hass, mqtt_client_mock, mqtt_mock):
async def test_custom_will_message(
hass, mqtt_client_mock, mqtt_mock_entry_no_yaml_config
):
"""Test will message."""
await mqtt_mock_entry_no_yaml_config()
mqtt_client_mock.will_set.assert_called_with(
topic="death", payload="death", qos=0, retain=False
)
async def test_default_will_message(hass, mqtt_client_mock, mqtt_mock):
async def test_default_will_message(
hass, mqtt_client_mock, mqtt_mock_entry_no_yaml_config
):
"""Test will message."""
await mqtt_mock_entry_no_yaml_config()
mqtt_client_mock.will_set.assert_called_with(
topic="homeassistant/status", payload="offline", qos=0, retain=False
)
@ -1628,8 +1727,10 @@ async def test_default_will_message(hass, mqtt_client_mock, mqtt_mock):
"mqtt_config",
[{mqtt.CONF_BROKER: "mock-broker", mqtt.CONF_WILL_MESSAGE: {}}],
)
async def test_no_will_message(hass, mqtt_client_mock, mqtt_mock):
async def test_no_will_message(hass, mqtt_client_mock, mqtt_mock_entry_no_yaml_config):
"""Test will message."""
await mqtt_mock_entry_no_yaml_config()
mqtt_client_mock.will_set.assert_not_called()
@ -1643,8 +1744,12 @@ async def test_no_will_message(hass, mqtt_client_mock, mqtt_mock):
}
],
)
async def test_mqtt_subscribes_topics_on_connect(hass, mqtt_client_mock, mqtt_mock):
async def test_mqtt_subscribes_topics_on_connect(
hass, mqtt_client_mock, mqtt_mock_entry_no_yaml_config
):
"""Test subscription to topic on connect."""
await mqtt_mock_entry_no_yaml_config()
await mqtt.async_subscribe(hass, "topic/test", None)
await mqtt.async_subscribe(hass, "home/sensor", None, 2)
await mqtt.async_subscribe(hass, "still/pending", None)
@ -1662,7 +1767,9 @@ async def test_mqtt_subscribes_topics_on_connect(hass, mqtt_client_mock, mqtt_mo
assert calls == expected
async def test_setup_entry_with_config_override(hass, device_reg, mqtt_client_mock):
async def test_setup_entry_with_config_override(
hass, device_reg, mqtt_mock_entry_with_yaml_config
):
"""Test if the MQTT component loads with no config and config entry can be setup."""
data = (
'{ "device":{"identifiers":["0AFFD2"]},'
@ -1672,6 +1779,8 @@ async def test_setup_entry_with_config_override(hass, device_reg, mqtt_client_mo
# mqtt present in yaml config
assert await async_setup_component(hass, mqtt.DOMAIN, {})
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
# User sets up a config entry
entry = MockConfigEntry(domain=mqtt.DOMAIN, data={mqtt.CONF_BROKER: "test-broker"})
@ -1734,8 +1843,11 @@ async def test_fail_no_broker(hass, device_reg, mqtt_client_mock, caplog):
@pytest.mark.no_fail_on_log_exception
async def test_message_callback_exception_gets_logged(hass, caplog, mqtt_mock):
async def test_message_callback_exception_gets_logged(
hass, caplog, mqtt_mock_entry_no_yaml_config
):
"""Test exception raised by message handler."""
await mqtt_mock_entry_no_yaml_config()
@callback
def bad_handler(*args):
@ -1752,8 +1864,11 @@ async def test_message_callback_exception_gets_logged(hass, caplog, mqtt_mock):
)
async def test_mqtt_ws_subscription(hass, hass_ws_client, mqtt_mock):
async def test_mqtt_ws_subscription(
hass, hass_ws_client, mqtt_mock_entry_no_yaml_config
):
"""Test MQTT websocket subscription."""
await mqtt_mock_entry_no_yaml_config()
client = await hass_ws_client(hass)
await client.send_json({"id": 5, "type": "mqtt/subscribe", "topic": "test-topic"})
response = await client.receive_json()
@ -1782,9 +1897,10 @@ async def test_mqtt_ws_subscription(hass, hass_ws_client, mqtt_mock):
async def test_mqtt_ws_subscription_not_admin(
hass, hass_ws_client, mqtt_mock, hass_read_only_access_token
hass, hass_ws_client, mqtt_mock_entry_no_yaml_config, hass_read_only_access_token
):
"""Test MQTT websocket user is not admin."""
await mqtt_mock_entry_no_yaml_config()
client = await hass_ws_client(hass, access_token=hass_read_only_access_token)
await client.send_json({"id": 5, "type": "mqtt/subscribe", "topic": "test-topic"})
response = await client.receive_json()
@ -1793,8 +1909,9 @@ async def test_mqtt_ws_subscription_not_admin(
assert response["error"]["message"] == "Unauthorized"
async def test_dump_service(hass, mqtt_mock):
async def test_dump_service(hass, mqtt_mock_entry_no_yaml_config):
"""Test that we can dump a topic."""
await mqtt_mock_entry_no_yaml_config()
mopen = mock_open()
await hass.services.async_call(
@ -1814,10 +1931,12 @@ async def test_dump_service(hass, mqtt_mock):
async def test_mqtt_ws_remove_discovered_device(
hass, device_reg, entity_reg, hass_ws_client, mqtt_mock
hass, device_reg, entity_reg, hass_ws_client, mqtt_mock_entry_no_yaml_config
):
"""Test MQTT websocket device removal."""
assert await async_setup_component(hass, "config", {})
await hass.async_block_till_done()
await mqtt_mock_entry_no_yaml_config()
data = (
'{ "device":{"identifiers":["0AFFD2"]},'
@ -1851,9 +1970,10 @@ async def test_mqtt_ws_remove_discovered_device(
async def test_mqtt_ws_get_device_debug_info(
hass, device_reg, hass_ws_client, mqtt_mock
hass, device_reg, hass_ws_client, mqtt_mock_entry_no_yaml_config
):
"""Test MQTT websocket device debug info."""
await mqtt_mock_entry_no_yaml_config()
config_sensor = {
"device": {"identifiers": ["0AFFD2"]},
"platform": "mqtt",
@ -1913,9 +2033,10 @@ async def test_mqtt_ws_get_device_debug_info(
async def test_mqtt_ws_get_device_debug_info_binary(
hass, device_reg, hass_ws_client, mqtt_mock
hass, device_reg, hass_ws_client, mqtt_mock_entry_no_yaml_config
):
"""Test MQTT websocket device debug info."""
await mqtt_mock_entry_no_yaml_config()
config = {
"device": {"identifiers": ["0AFFD2"]},
"platform": "mqtt",
@ -1975,8 +2096,9 @@ async def test_mqtt_ws_get_device_debug_info_binary(
assert response["result"] == expected_result
async def test_debug_info_multiple_devices(hass, mqtt_mock):
async def test_debug_info_multiple_devices(hass, mqtt_mock_entry_no_yaml_config):
"""Test we get correct debug_info when multiple devices are present."""
await mqtt_mock_entry_no_yaml_config()
devices = [
{
"domain": "sensor",
@ -2054,8 +2176,11 @@ async def test_debug_info_multiple_devices(hass, mqtt_mock):
assert discovery_data["payload"] == d["config"]
async def test_debug_info_multiple_entities_triggers(hass, mqtt_mock):
async def test_debug_info_multiple_entities_triggers(
hass, mqtt_mock_entry_no_yaml_config
):
"""Test we get correct debug_info for a device with multiple entities and triggers."""
await mqtt_mock_entry_no_yaml_config()
config = [
{
"domain": "sensor",
@ -2137,8 +2262,11 @@ async def test_debug_info_multiple_entities_triggers(hass, mqtt_mock):
} in discovery_data
async def test_debug_info_non_mqtt(hass, device_reg, entity_reg, mqtt_mock):
async def test_debug_info_non_mqtt(
hass, device_reg, entity_reg, mqtt_mock_entry_no_yaml_config
):
"""Test we get empty debug_info for a device with non MQTT entities."""
await mqtt_mock_entry_no_yaml_config()
DOMAIN = "sensor"
platform = getattr(hass.components, f"test.{DOMAIN}")
platform.init()
@ -2164,8 +2292,9 @@ async def test_debug_info_non_mqtt(hass, device_reg, entity_reg, mqtt_mock):
assert len(debug_info_data["triggers"]) == 0
async def test_debug_info_wildcard(hass, mqtt_mock):
async def test_debug_info_wildcard(hass, mqtt_mock_entry_no_yaml_config):
"""Test debug info."""
await mqtt_mock_entry_no_yaml_config()
config = {
"device": {"identifiers": ["helloworld"]},
"platform": "mqtt",
@ -2210,8 +2339,9 @@ async def test_debug_info_wildcard(hass, mqtt_mock):
} in debug_info_data["entities"][0]["subscriptions"]
async def test_debug_info_filter_same(hass, mqtt_mock):
async def test_debug_info_filter_same(hass, mqtt_mock_entry_no_yaml_config):
"""Test debug info removes messages with same timestamp."""
await mqtt_mock_entry_no_yaml_config()
config = {
"device": {"identifiers": ["helloworld"]},
"platform": "mqtt",
@ -2268,8 +2398,9 @@ async def test_debug_info_filter_same(hass, mqtt_mock):
} == debug_info_data["entities"][0]["subscriptions"][0]
async def test_debug_info_same_topic(hass, mqtt_mock):
async def test_debug_info_same_topic(hass, mqtt_mock_entry_no_yaml_config):
"""Test debug info."""
await mqtt_mock_entry_no_yaml_config()
config = {
"device": {"identifiers": ["helloworld"]},
"platform": "mqtt",
@ -2320,8 +2451,9 @@ async def test_debug_info_same_topic(hass, mqtt_mock):
async_fire_mqtt_message(hass, "sensor/status", "123", qos=0, retain=False)
async def test_debug_info_qos_retain(hass, mqtt_mock):
async def test_debug_info_qos_retain(hass, mqtt_mock_entry_no_yaml_config):
"""Test debug info."""
await mqtt_mock_entry_no_yaml_config()
config = {
"device": {"identifiers": ["helloworld"]},
"platform": "mqtt",
@ -2377,8 +2509,10 @@ async def test_debug_info_qos_retain(hass, mqtt_mock):
} in debug_info_data["entities"][0]["subscriptions"][0]["messages"]
async def test_publish_json_from_template(hass, mqtt_mock):
async def test_publish_json_from_template(hass, mqtt_mock_entry_no_yaml_config):
"""Test the publishing of call to services."""
mqtt_mock = await mqtt_mock_entry_no_yaml_config()
test_str = "{'valid': 'python', 'invalid': 'json'}"
test_str_tpl = "{'valid': '{{ \"python\" }}', 'invalid': 'json'}"
@ -2424,8 +2558,11 @@ async def test_publish_json_from_template(hass, mqtt_mock):
assert mqtt_mock.async_publish.call_args[0][1] == test_str
async def test_subscribe_connection_status(hass, mqtt_mock, mqtt_client_mock):
async def test_subscribe_connection_status(
hass, mqtt_mock_entry_no_yaml_config, mqtt_client_mock
):
"""Test connextion status subscription."""
mqtt_mock = await mqtt_mock_entry_no_yaml_config()
mqtt_connected_calls = []
@callback
@ -2459,7 +2596,9 @@ async def test_subscribe_connection_status(hass, mqtt_mock, mqtt_client_mock):
assert mqtt_connected_calls[1] is False
async def test_one_deprecation_warning_per_platform(hass, mqtt_mock, caplog):
async def test_one_deprecation_warning_per_platform(
hass, mqtt_mock_entry_with_yaml_config, caplog
):
"""Test a deprecation warning is is logged once per platform."""
platform = "light"
config = {"platform": "mqtt", "command_topic": "test-topic"}
@ -2469,6 +2608,7 @@ async def test_one_deprecation_warning_per_platform(hass, mqtt_mock, caplog):
config2["name"] = "test2"
await async_setup_component(hass, platform, {platform: [config1, config2]})
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
count = 0
for record in caplog.records:
if record.levelname == "WARNING" and (

View File

@ -6,7 +6,7 @@ from unittest.mock import patch
import pytest
from homeassistant.components import vacuum
from homeassistant.components.mqtt import CONF_COMMAND_TOPIC
from homeassistant.components.mqtt.const import CONF_COMMAND_TOPIC
from homeassistant.components.mqtt.vacuum import schema_legacy as mqttvacuum
from homeassistant.components.mqtt.vacuum.schema import services_to_strings
from homeassistant.components.mqtt.vacuum.schema_legacy import (
@ -89,12 +89,13 @@ DEFAULT_CONFIG = {
DEFAULT_CONFIG_2 = {vacuum.DOMAIN: {"platform": "mqtt", "name": "test"}}
async def test_default_supported_features(hass, mqtt_mock):
async def test_default_supported_features(hass, mqtt_mock_entry_with_yaml_config):
"""Test that the correct supported features."""
assert await async_setup_component(
hass, vacuum.DOMAIN, {vacuum.DOMAIN: DEFAULT_CONFIG}
)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
entity = hass.states.get("vacuum.mqtttest")
entity_features = entity.attributes.get(mqttvacuum.CONF_SUPPORTED_FEATURES, 0)
assert sorted(services_to_strings(entity_features, SERVICE_TO_STRING)) == sorted(
@ -110,7 +111,7 @@ async def test_default_supported_features(hass, mqtt_mock):
)
async def test_all_commands(hass, mqtt_mock):
async def test_all_commands(hass, mqtt_mock_entry_with_yaml_config):
"""Test simple commands to the vacuum."""
config = deepcopy(DEFAULT_CONFIG)
config[mqttvacuum.CONF_SUPPORTED_FEATURES] = services_to_strings(
@ -119,6 +120,7 @@ async def test_all_commands(hass, mqtt_mock):
assert await async_setup_component(hass, vacuum.DOMAIN, {vacuum.DOMAIN: config})
await hass.async_block_till_done()
mqtt_mock = await mqtt_mock_entry_with_yaml_config()
await common.async_turn_on(hass, "vacuum.mqtttest")
mqtt_mock.async_publish.assert_called_once_with(
@ -189,7 +191,9 @@ async def test_all_commands(hass, mqtt_mock):
}
async def test_commands_without_supported_features(hass, mqtt_mock):
async def test_commands_without_supported_features(
hass, mqtt_mock_entry_with_yaml_config
):
"""Test commands which are not supported by the vacuum."""
config = deepcopy(DEFAULT_CONFIG)
services = mqttvacuum.STRING_TO_SERVICE["status"]
@ -199,6 +203,7 @@ async def test_commands_without_supported_features(hass, mqtt_mock):
assert await async_setup_component(hass, vacuum.DOMAIN, {vacuum.DOMAIN: config})
await hass.async_block_till_done()
mqtt_mock = await mqtt_mock_entry_with_yaml_config()
await common.async_turn_on(hass, "vacuum.mqtttest")
mqtt_mock.async_publish.assert_not_called()
@ -237,7 +242,9 @@ async def test_commands_without_supported_features(hass, mqtt_mock):
mqtt_mock.async_publish.reset_mock()
async def test_attributes_without_supported_features(hass, mqtt_mock):
async def test_attributes_without_supported_features(
hass, mqtt_mock_entry_with_yaml_config
):
"""Test attributes which are not supported by the vacuum."""
config = deepcopy(DEFAULT_CONFIG)
services = mqttvacuum.STRING_TO_SERVICE["turn_on"]
@ -247,6 +254,7 @@ async def test_attributes_without_supported_features(hass, mqtt_mock):
assert await async_setup_component(hass, vacuum.DOMAIN, {vacuum.DOMAIN: config})
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
message = """{
"battery_level": 54,
@ -264,7 +272,7 @@ async def test_attributes_without_supported_features(hass, mqtt_mock):
assert state.attributes.get(ATTR_FAN_SPEED_LIST) is None
async def test_status(hass, mqtt_mock):
async def test_status(hass, mqtt_mock_entry_with_yaml_config):
"""Test status updates from the vacuum."""
config = deepcopy(DEFAULT_CONFIG)
config[mqttvacuum.CONF_SUPPORTED_FEATURES] = services_to_strings(
@ -273,6 +281,7 @@ async def test_status(hass, mqtt_mock):
assert await async_setup_component(hass, vacuum.DOMAIN, {vacuum.DOMAIN: config})
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
message = """{
"battery_level": 54,
@ -304,7 +313,7 @@ async def test_status(hass, mqtt_mock):
assert state.attributes.get(ATTR_FAN_SPEED) == "min"
async def test_status_battery(hass, mqtt_mock):
async def test_status_battery(hass, mqtt_mock_entry_with_yaml_config):
"""Test status updates from the vacuum."""
config = deepcopy(DEFAULT_CONFIG)
config[mqttvacuum.CONF_SUPPORTED_FEATURES] = services_to_strings(
@ -313,6 +322,7 @@ async def test_status_battery(hass, mqtt_mock):
assert await async_setup_component(hass, vacuum.DOMAIN, {vacuum.DOMAIN: config})
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
message = """{
"battery_level": 54
@ -322,7 +332,7 @@ async def test_status_battery(hass, mqtt_mock):
assert state.attributes.get(ATTR_BATTERY_ICON) == "mdi:battery-50"
async def test_status_cleaning(hass, mqtt_mock):
async def test_status_cleaning(hass, mqtt_mock_entry_with_yaml_config):
"""Test status updates from the vacuum."""
config = deepcopy(DEFAULT_CONFIG)
config[mqttvacuum.CONF_SUPPORTED_FEATURES] = services_to_strings(
@ -331,6 +341,7 @@ async def test_status_cleaning(hass, mqtt_mock):
assert await async_setup_component(hass, vacuum.DOMAIN, {vacuum.DOMAIN: config})
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
message = """{
"cleaning": true
@ -340,7 +351,7 @@ async def test_status_cleaning(hass, mqtt_mock):
assert state.state == STATE_ON
async def test_status_docked(hass, mqtt_mock):
async def test_status_docked(hass, mqtt_mock_entry_with_yaml_config):
"""Test status updates from the vacuum."""
config = deepcopy(DEFAULT_CONFIG)
config[mqttvacuum.CONF_SUPPORTED_FEATURES] = services_to_strings(
@ -349,6 +360,7 @@ async def test_status_docked(hass, mqtt_mock):
assert await async_setup_component(hass, vacuum.DOMAIN, {vacuum.DOMAIN: config})
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
message = """{
"docked": true
@ -358,7 +370,7 @@ async def test_status_docked(hass, mqtt_mock):
assert state.state == STATE_OFF
async def test_status_charging(hass, mqtt_mock):
async def test_status_charging(hass, mqtt_mock_entry_with_yaml_config):
"""Test status updates from the vacuum."""
config = deepcopy(DEFAULT_CONFIG)
config[mqttvacuum.CONF_SUPPORTED_FEATURES] = services_to_strings(
@ -367,6 +379,7 @@ async def test_status_charging(hass, mqtt_mock):
assert await async_setup_component(hass, vacuum.DOMAIN, {vacuum.DOMAIN: config})
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
message = """{
"charging": true
@ -376,7 +389,7 @@ async def test_status_charging(hass, mqtt_mock):
assert state.attributes.get(ATTR_BATTERY_ICON) == "mdi:battery-outline"
async def test_status_fan_speed(hass, mqtt_mock):
async def test_status_fan_speed(hass, mqtt_mock_entry_with_yaml_config):
"""Test status updates from the vacuum."""
config = deepcopy(DEFAULT_CONFIG)
config[mqttvacuum.CONF_SUPPORTED_FEATURES] = services_to_strings(
@ -385,6 +398,7 @@ async def test_status_fan_speed(hass, mqtt_mock):
assert await async_setup_component(hass, vacuum.DOMAIN, {vacuum.DOMAIN: config})
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
message = """{
"fan_speed": "max"
@ -394,7 +408,7 @@ async def test_status_fan_speed(hass, mqtt_mock):
assert state.attributes.get(ATTR_FAN_SPEED) == "max"
async def test_status_fan_speed_list(hass, mqtt_mock):
async def test_status_fan_speed_list(hass, mqtt_mock_entry_with_yaml_config):
"""Test status updates from the vacuum."""
config = deepcopy(DEFAULT_CONFIG)
config[mqttvacuum.CONF_SUPPORTED_FEATURES] = services_to_strings(
@ -403,12 +417,13 @@ async def test_status_fan_speed_list(hass, mqtt_mock):
assert await async_setup_component(hass, vacuum.DOMAIN, {vacuum.DOMAIN: config})
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("vacuum.mqtttest")
assert state.attributes.get(ATTR_FAN_SPEED_LIST) == ["min", "medium", "high", "max"]
async def test_status_no_fan_speed_list(hass, mqtt_mock):
async def test_status_no_fan_speed_list(hass, mqtt_mock_entry_with_yaml_config):
"""Test status updates from the vacuum.
If the vacuum doesn't support fan speed, fan speed list should be None.
@ -421,12 +436,13 @@ async def test_status_no_fan_speed_list(hass, mqtt_mock):
assert await async_setup_component(hass, vacuum.DOMAIN, {vacuum.DOMAIN: config})
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("vacuum.mqtttest")
assert state.attributes.get(ATTR_FAN_SPEED_LIST) is None
async def test_status_error(hass, mqtt_mock):
async def test_status_error(hass, mqtt_mock_entry_with_yaml_config):
"""Test status updates from the vacuum."""
config = deepcopy(DEFAULT_CONFIG)
config[mqttvacuum.CONF_SUPPORTED_FEATURES] = services_to_strings(
@ -435,6 +451,7 @@ async def test_status_error(hass, mqtt_mock):
assert await async_setup_component(hass, vacuum.DOMAIN, {vacuum.DOMAIN: config})
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
message = """{
"error": "Error1"
@ -451,7 +468,7 @@ async def test_status_error(hass, mqtt_mock):
assert state.attributes.get(ATTR_STATUS) == "Stopped"
async def test_battery_template(hass, mqtt_mock):
async def test_battery_template(hass, mqtt_mock_entry_with_yaml_config):
"""Test that you can use non-default templates for battery_level."""
config = deepcopy(DEFAULT_CONFIG)
config.update(
@ -466,6 +483,7 @@ async def test_battery_template(hass, mqtt_mock):
assert await async_setup_component(hass, vacuum.DOMAIN, {vacuum.DOMAIN: config})
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
async_fire_mqtt_message(hass, "retroroomba/battery_level", "54")
state = hass.states.get("vacuum.mqtttest")
@ -473,7 +491,7 @@ async def test_battery_template(hass, mqtt_mock):
assert state.attributes.get(ATTR_BATTERY_ICON) == "mdi:battery-50"
async def test_status_invalid_json(hass, mqtt_mock):
async def test_status_invalid_json(hass, mqtt_mock_entry_with_yaml_config):
"""Test to make sure nothing breaks if the vacuum sends bad JSON."""
config = deepcopy(DEFAULT_CONFIG)
config[mqttvacuum.CONF_SUPPORTED_FEATURES] = services_to_strings(
@ -482,6 +500,7 @@ async def test_status_invalid_json(hass, mqtt_mock):
assert await async_setup_component(hass, vacuum.DOMAIN, {vacuum.DOMAIN: config})
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
async_fire_mqtt_message(hass, "vacuum/state", '{"asdfasas false}')
state = hass.states.get("vacuum.mqtttest")
@ -489,153 +508,169 @@ async def test_status_invalid_json(hass, mqtt_mock):
assert state.attributes.get(ATTR_STATUS) == "Stopped"
async def test_missing_battery_template(hass, mqtt_mock):
async def test_missing_battery_template(hass, mqtt_mock_entry_no_yaml_config):
"""Test to make sure missing template is not allowed."""
config = deepcopy(DEFAULT_CONFIG)
config.pop(mqttvacuum.CONF_BATTERY_LEVEL_TEMPLATE)
assert await async_setup_component(hass, vacuum.DOMAIN, {vacuum.DOMAIN: config})
await hass.async_block_till_done()
await mqtt_mock_entry_no_yaml_config()
state = hass.states.get("vacuum.mqtttest")
assert state is None
async def test_missing_charging_template(hass, mqtt_mock):
async def test_missing_charging_template(hass, mqtt_mock_entry_no_yaml_config):
"""Test to make sure missing template is not allowed."""
config = deepcopy(DEFAULT_CONFIG)
config.pop(mqttvacuum.CONF_CHARGING_TEMPLATE)
assert await async_setup_component(hass, vacuum.DOMAIN, {vacuum.DOMAIN: config})
await hass.async_block_till_done()
await mqtt_mock_entry_no_yaml_config()
state = hass.states.get("vacuum.mqtttest")
assert state is None
async def test_missing_cleaning_template(hass, mqtt_mock):
async def test_missing_cleaning_template(hass, mqtt_mock_entry_no_yaml_config):
"""Test to make sure missing template is not allowed."""
config = deepcopy(DEFAULT_CONFIG)
config.pop(mqttvacuum.CONF_CLEANING_TEMPLATE)
assert await async_setup_component(hass, vacuum.DOMAIN, {vacuum.DOMAIN: config})
await hass.async_block_till_done()
await mqtt_mock_entry_no_yaml_config()
state = hass.states.get("vacuum.mqtttest")
assert state is None
async def test_missing_docked_template(hass, mqtt_mock):
async def test_missing_docked_template(hass, mqtt_mock_entry_no_yaml_config):
"""Test to make sure missing template is not allowed."""
config = deepcopy(DEFAULT_CONFIG)
config.pop(mqttvacuum.CONF_DOCKED_TEMPLATE)
assert await async_setup_component(hass, vacuum.DOMAIN, {vacuum.DOMAIN: config})
await hass.async_block_till_done()
await mqtt_mock_entry_no_yaml_config()
state = hass.states.get("vacuum.mqtttest")
assert state is None
async def test_missing_error_template(hass, mqtt_mock):
async def test_missing_error_template(hass, mqtt_mock_entry_no_yaml_config):
"""Test to make sure missing template is not allowed."""
config = deepcopy(DEFAULT_CONFIG)
config.pop(mqttvacuum.CONF_ERROR_TEMPLATE)
assert await async_setup_component(hass, vacuum.DOMAIN, {vacuum.DOMAIN: config})
await hass.async_block_till_done()
await mqtt_mock_entry_no_yaml_config()
state = hass.states.get("vacuum.mqtttest")
assert state is None
async def test_missing_fan_speed_template(hass, mqtt_mock):
async def test_missing_fan_speed_template(hass, mqtt_mock_entry_no_yaml_config):
"""Test to make sure missing template is not allowed."""
config = deepcopy(DEFAULT_CONFIG)
config.pop(mqttvacuum.CONF_FAN_SPEED_TEMPLATE)
assert await async_setup_component(hass, vacuum.DOMAIN, {vacuum.DOMAIN: config})
await hass.async_block_till_done()
await mqtt_mock_entry_no_yaml_config()
state = hass.states.get("vacuum.mqtttest")
assert state is None
async def test_availability_when_connection_lost(hass, mqtt_mock):
async def test_availability_when_connection_lost(
hass, mqtt_mock_entry_with_yaml_config
):
"""Test availability after MQTT disconnection."""
await help_test_availability_when_connection_lost(
hass, mqtt_mock, vacuum.DOMAIN, DEFAULT_CONFIG_2
hass, mqtt_mock_entry_with_yaml_config, vacuum.DOMAIN, DEFAULT_CONFIG_2
)
async def test_availability_without_topic(hass, mqtt_mock):
async def test_availability_without_topic(hass, mqtt_mock_entry_with_yaml_config):
"""Test availability without defined availability topic."""
await help_test_availability_without_topic(
hass, mqtt_mock, vacuum.DOMAIN, DEFAULT_CONFIG_2
hass, mqtt_mock_entry_with_yaml_config, vacuum.DOMAIN, DEFAULT_CONFIG_2
)
async def test_default_availability_payload(hass, mqtt_mock):
async def test_default_availability_payload(hass, mqtt_mock_entry_with_yaml_config):
"""Test availability by default payload with defined topic."""
await help_test_default_availability_payload(
hass, mqtt_mock, vacuum.DOMAIN, DEFAULT_CONFIG_2
hass, mqtt_mock_entry_with_yaml_config, vacuum.DOMAIN, DEFAULT_CONFIG_2
)
async def test_custom_availability_payload(hass, mqtt_mock):
async def test_custom_availability_payload(hass, mqtt_mock_entry_with_yaml_config):
"""Test availability by custom payload with defined topic."""
await help_test_custom_availability_payload(
hass, mqtt_mock, vacuum.DOMAIN, DEFAULT_CONFIG_2
hass, mqtt_mock_entry_with_yaml_config, vacuum.DOMAIN, DEFAULT_CONFIG_2
)
async def test_setting_attribute_via_mqtt_json_message(hass, mqtt_mock):
async def test_setting_attribute_via_mqtt_json_message(
hass, mqtt_mock_entry_with_yaml_config
):
"""Test the setting of attribute via MQTT with JSON payload."""
await help_test_setting_attribute_via_mqtt_json_message(
hass, mqtt_mock, vacuum.DOMAIN, DEFAULT_CONFIG_2
hass, mqtt_mock_entry_with_yaml_config, vacuum.DOMAIN, DEFAULT_CONFIG_2
)
async def test_setting_blocked_attribute_via_mqtt_json_message(hass, mqtt_mock):
async def test_setting_blocked_attribute_via_mqtt_json_message(
hass, mqtt_mock_entry_no_yaml_config
):
"""Test the setting of attribute via MQTT with JSON payload."""
await help_test_setting_blocked_attribute_via_mqtt_json_message(
hass,
mqtt_mock,
mqtt_mock_entry_no_yaml_config,
vacuum.DOMAIN,
DEFAULT_CONFIG_2,
MQTT_LEGACY_VACUUM_ATTRIBUTES_BLOCKED,
)
async def test_setting_attribute_with_template(hass, mqtt_mock):
async def test_setting_attribute_with_template(hass, mqtt_mock_entry_with_yaml_config):
"""Test the setting of attribute via MQTT with JSON payload."""
await help_test_setting_attribute_with_template(
hass, mqtt_mock, vacuum.DOMAIN, DEFAULT_CONFIG_2
hass, mqtt_mock_entry_with_yaml_config, vacuum.DOMAIN, DEFAULT_CONFIG_2
)
async def test_update_with_json_attrs_not_dict(hass, mqtt_mock, caplog):
async def test_update_with_json_attrs_not_dict(
hass, mqtt_mock_entry_with_yaml_config, caplog
):
"""Test attributes get extracted from a JSON result."""
await help_test_update_with_json_attrs_not_dict(
hass, mqtt_mock, caplog, vacuum.DOMAIN, DEFAULT_CONFIG_2
hass, mqtt_mock_entry_with_yaml_config, caplog, vacuum.DOMAIN, DEFAULT_CONFIG_2
)
async def test_update_with_json_attrs_bad_JSON(hass, mqtt_mock, caplog):
async def test_update_with_json_attrs_bad_JSON(
hass, mqtt_mock_entry_with_yaml_config, caplog
):
"""Test attributes get extracted from a JSON result."""
await help_test_update_with_json_attrs_bad_JSON(
hass, mqtt_mock, caplog, vacuum.DOMAIN, DEFAULT_CONFIG_2
hass, mqtt_mock_entry_with_yaml_config, caplog, vacuum.DOMAIN, DEFAULT_CONFIG_2
)
async def test_discovery_update_attr(hass, mqtt_mock, caplog):
async def test_discovery_update_attr(hass, mqtt_mock_entry_no_yaml_config, caplog):
"""Test update of discovered MQTTAttributes."""
await help_test_discovery_update_attr(
hass, mqtt_mock, caplog, vacuum.DOMAIN, DEFAULT_CONFIG_2
hass, mqtt_mock_entry_no_yaml_config, caplog, vacuum.DOMAIN, DEFAULT_CONFIG_2
)
async def test_unique_id(hass, mqtt_mock):
async def test_unique_id(hass, mqtt_mock_entry_with_yaml_config):
"""Test unique id option only creates one vacuum per unique_id."""
config = {
vacuum.DOMAIN: [
@ -653,74 +688,85 @@ async def test_unique_id(hass, mqtt_mock):
},
]
}
await help_test_unique_id(hass, mqtt_mock, vacuum.DOMAIN, config)
await help_test_unique_id(
hass, mqtt_mock_entry_with_yaml_config, vacuum.DOMAIN, config
)
async def test_discovery_removal_vacuum(hass, mqtt_mock, caplog):
async def test_discovery_removal_vacuum(hass, mqtt_mock_entry_no_yaml_config, caplog):
"""Test removal of discovered vacuum."""
data = json.dumps(DEFAULT_CONFIG_2[vacuum.DOMAIN])
await help_test_discovery_removal(hass, mqtt_mock, caplog, vacuum.DOMAIN, data)
await help_test_discovery_removal(
hass, mqtt_mock_entry_no_yaml_config, caplog, vacuum.DOMAIN, data
)
async def test_discovery_update_vacuum(hass, mqtt_mock, caplog):
async def test_discovery_update_vacuum(hass, mqtt_mock_entry_no_yaml_config, caplog):
"""Test update of discovered vacuum."""
config1 = {"name": "Beer", "command_topic": "test_topic"}
config2 = {"name": "Milk", "command_topic": "test_topic"}
await help_test_discovery_update(
hass, mqtt_mock, caplog, vacuum.DOMAIN, config1, config2
hass, mqtt_mock_entry_no_yaml_config, caplog, vacuum.DOMAIN, config1, config2
)
async def test_discovery_update_unchanged_vacuum(hass, mqtt_mock, caplog):
async def test_discovery_update_unchanged_vacuum(
hass, mqtt_mock_entry_no_yaml_config, caplog
):
"""Test update of discovered vacuum."""
data1 = '{ "name": "Beer", "command_topic": "test_topic" }'
with patch(
"homeassistant.components.mqtt.vacuum.schema_legacy.MqttVacuum.discovery_update"
) as discovery_update:
await help_test_discovery_update_unchanged(
hass, mqtt_mock, caplog, vacuum.DOMAIN, data1, discovery_update
hass,
mqtt_mock_entry_no_yaml_config,
caplog,
vacuum.DOMAIN,
data1,
discovery_update,
)
@pytest.mark.no_fail_on_log_exception
async def test_discovery_broken(hass, mqtt_mock, caplog):
async def test_discovery_broken(hass, mqtt_mock_entry_no_yaml_config, caplog):
"""Test handling of bad discovery message."""
data1 = '{ "name": "Beer",' ' "command_topic": "test_topic#" }'
data2 = '{ "name": "Milk",' ' "command_topic": "test_topic" }'
await help_test_discovery_broken(
hass, mqtt_mock, caplog, vacuum.DOMAIN, data1, data2
hass, mqtt_mock_entry_no_yaml_config, caplog, vacuum.DOMAIN, data1, data2
)
async def test_entity_device_info_with_connection(hass, mqtt_mock):
async def test_entity_device_info_with_connection(hass, mqtt_mock_entry_no_yaml_config):
"""Test MQTT vacuum device registry integration."""
await help_test_entity_device_info_with_connection(
hass, mqtt_mock, vacuum.DOMAIN, DEFAULT_CONFIG_2
hass, mqtt_mock_entry_no_yaml_config, vacuum.DOMAIN, DEFAULT_CONFIG_2
)
async def test_entity_device_info_with_identifier(hass, mqtt_mock):
async def test_entity_device_info_with_identifier(hass, mqtt_mock_entry_no_yaml_config):
"""Test MQTT vacuum device registry integration."""
await help_test_entity_device_info_with_identifier(
hass, mqtt_mock, vacuum.DOMAIN, DEFAULT_CONFIG_2
hass, mqtt_mock_entry_no_yaml_config, vacuum.DOMAIN, DEFAULT_CONFIG_2
)
async def test_entity_device_info_update(hass, mqtt_mock):
async def test_entity_device_info_update(hass, mqtt_mock_entry_no_yaml_config):
"""Test device registry update."""
await help_test_entity_device_info_update(
hass, mqtt_mock, vacuum.DOMAIN, DEFAULT_CONFIG_2
hass, mqtt_mock_entry_no_yaml_config, vacuum.DOMAIN, DEFAULT_CONFIG_2
)
async def test_entity_device_info_remove(hass, mqtt_mock):
async def test_entity_device_info_remove(hass, mqtt_mock_entry_no_yaml_config):
"""Test device registry remove."""
await help_test_entity_device_info_remove(
hass, mqtt_mock, vacuum.DOMAIN, DEFAULT_CONFIG_2
hass, mqtt_mock_entry_no_yaml_config, vacuum.DOMAIN, DEFAULT_CONFIG_2
)
async def test_entity_id_update_subscriptions(hass, mqtt_mock):
async def test_entity_id_update_subscriptions(hass, mqtt_mock_entry_with_yaml_config):
"""Test MQTT subscriptions are managed when entity_id is updated."""
config = {
vacuum.DOMAIN: {
@ -733,18 +779,22 @@ async def test_entity_id_update_subscriptions(hass, mqtt_mock):
}
}
await help_test_entity_id_update_subscriptions(
hass, mqtt_mock, vacuum.DOMAIN, config, ["test-topic", "avty-topic"]
hass,
mqtt_mock_entry_with_yaml_config,
vacuum.DOMAIN,
config,
["test-topic", "avty-topic"],
)
async def test_entity_id_update_discovery_update(hass, mqtt_mock):
async def test_entity_id_update_discovery_update(hass, mqtt_mock_entry_no_yaml_config):
"""Test MQTT discovery update when entity_id is updated."""
await help_test_entity_id_update_discovery_update(
hass, mqtt_mock, vacuum.DOMAIN, DEFAULT_CONFIG_2
hass, mqtt_mock_entry_no_yaml_config, vacuum.DOMAIN, DEFAULT_CONFIG_2
)
async def test_entity_debug_info_message(hass, mqtt_mock):
async def test_entity_debug_info_message(hass, mqtt_mock_entry_no_yaml_config):
"""Test MQTT debug info."""
config = {
vacuum.DOMAIN: {
@ -757,7 +807,11 @@ async def test_entity_debug_info_message(hass, mqtt_mock):
}
}
await help_test_entity_debug_info_message(
hass, mqtt_mock, vacuum.DOMAIN, config, vacuum.SERVICE_TURN_ON
hass,
mqtt_mock_entry_no_yaml_config,
vacuum.DOMAIN,
config,
vacuum.SERVICE_TURN_ON,
)
@ -803,7 +857,7 @@ async def test_entity_debug_info_message(hass, mqtt_mock):
)
async def test_publishing_with_custom_encoding(
hass,
mqtt_mock,
mqtt_mock_entry_with_yaml_config,
caplog,
service,
topic,
@ -824,7 +878,7 @@ async def test_publishing_with_custom_encoding(
await help_test_publishing_with_custom_encoding(
hass,
mqtt_mock,
mqtt_mock_entry_with_yaml_config,
caplog,
domain,
config,
@ -836,11 +890,13 @@ async def test_publishing_with_custom_encoding(
)
async def test_reloadable(hass, mqtt_mock, caplog, tmp_path):
async def test_reloadable(hass, mqtt_mock_entry_with_yaml_config, caplog, tmp_path):
"""Test reloading the MQTT platform."""
domain = vacuum.DOMAIN
config = DEFAULT_CONFIG
await help_test_reloadable(hass, mqtt_mock, caplog, tmp_path, domain, config)
await help_test_reloadable(
hass, mqtt_mock_entry_with_yaml_config, caplog, tmp_path, domain, config
)
async def test_reloadable_late(hass, mqtt_client_mock, caplog, tmp_path):
@ -872,7 +928,13 @@ async def test_reloadable_late(hass, mqtt_client_mock, caplog, tmp_path):
],
)
async def test_encoding_subscribable_topics(
hass, mqtt_mock, caplog, topic, value, attribute, attribute_value
hass,
mqtt_mock_entry_with_yaml_config,
caplog,
topic,
value,
attribute,
attribute_value,
):
"""Test handling of incoming encoded payload."""
config = deepcopy(DEFAULT_CONFIG)
@ -892,7 +954,7 @@ async def test_encoding_subscribable_topics(
await help_test_encoding_subscribable_topics(
hass,
mqtt_mock,
mqtt_mock_entry_with_yaml_config,
caplog,
vacuum.DOMAIN,
config,

View File

@ -251,16 +251,17 @@ DEFAULT_CONFIG = {
}
async def test_fail_setup_if_no_command_topic(hass, mqtt_mock):
async def test_fail_setup_if_no_command_topic(hass, mqtt_mock_entry_no_yaml_config):
"""Test if command fails with command topic."""
assert await async_setup_component(
hass, light.DOMAIN, {light.DOMAIN: {"platform": "mqtt", "name": "test"}}
)
await hass.async_block_till_done()
await mqtt_mock_entry_no_yaml_config()
assert hass.states.get("light.test") is None
async def test_legacy_rgb_white_light(hass, mqtt_mock):
async def test_legacy_rgb_white_light(hass, mqtt_mock_entry_with_yaml_config):
"""Test legacy RGB + white light flags brightness support."""
assert await async_setup_component(
hass,
@ -276,6 +277,7 @@ async def test_legacy_rgb_white_light(hass, mqtt_mock):
},
)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("light.test")
expected_features = (
@ -286,7 +288,9 @@ async def test_legacy_rgb_white_light(hass, mqtt_mock):
assert state.attributes.get(light.ATTR_SUPPORTED_COLOR_MODES) == ["hs", "rgbw"]
async def test_no_color_brightness_color_temp_hs_white_xy_if_no_topics(hass, mqtt_mock):
async def test_no_color_brightness_color_temp_hs_white_xy_if_no_topics(
hass, mqtt_mock_entry_with_yaml_config
):
"""Test if there is no color and brightness if no topic."""
assert await async_setup_component(
hass,
@ -301,6 +305,7 @@ async def test_no_color_brightness_color_temp_hs_white_xy_if_no_topics(hass, mqt
},
)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("light.test")
assert state.state == STATE_UNKNOWN
@ -343,7 +348,9 @@ async def test_no_color_brightness_color_temp_hs_white_xy_if_no_topics(hass, mqt
assert state.state == STATE_UNKNOWN
async def test_legacy_controlling_state_via_topic(hass, mqtt_mock):
async def test_legacy_controlling_state_via_topic(
hass, mqtt_mock_entry_with_yaml_config
):
"""Test the controlling of the state via topic for legacy light (white_value)."""
config = {
light.DOMAIN: {
@ -374,6 +381,7 @@ async def test_legacy_controlling_state_via_topic(hass, mqtt_mock):
assert await async_setup_component(hass, light.DOMAIN, config)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("light.test")
assert state.state == STATE_UNKNOWN
@ -472,7 +480,7 @@ async def test_legacy_controlling_state_via_topic(hass, mqtt_mock):
assert light_state.attributes.get(light.ATTR_SUPPORTED_COLOR_MODES) == color_modes
async def test_controlling_state_via_topic(hass, mqtt_mock):
async def test_controlling_state_via_topic(hass, mqtt_mock_entry_with_yaml_config):
"""Test the controlling of the state via topic."""
config = {
light.DOMAIN: {
@ -505,6 +513,7 @@ async def test_controlling_state_via_topic(hass, mqtt_mock):
assert await async_setup_component(hass, light.DOMAIN, config)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("light.test")
assert state.state == STATE_UNKNOWN
@ -593,7 +602,9 @@ async def test_controlling_state_via_topic(hass, mqtt_mock):
assert light_state.attributes.get(light.ATTR_SUPPORTED_COLOR_MODES) == color_modes
async def test_legacy_invalid_state_via_topic(hass, mqtt_mock, caplog):
async def test_legacy_invalid_state_via_topic(
hass, mqtt_mock_entry_with_yaml_config, caplog
):
"""Test handling of empty data via topic."""
config = {
light.DOMAIN: {
@ -623,6 +634,7 @@ async def test_legacy_invalid_state_via_topic(hass, mqtt_mock, caplog):
assert await async_setup_component(hass, light.DOMAIN, config)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("light.test")
assert state.state == STATE_UNKNOWN
@ -709,7 +721,7 @@ async def test_legacy_invalid_state_via_topic(hass, mqtt_mock, caplog):
assert light_state.attributes["white_value"] == 255
async def test_invalid_state_via_topic(hass, mqtt_mock, caplog):
async def test_invalid_state_via_topic(hass, mqtt_mock_entry_with_yaml_config, caplog):
"""Test handling of empty data via topic."""
config = {
light.DOMAIN: {
@ -742,6 +754,7 @@ async def test_invalid_state_via_topic(hass, mqtt_mock, caplog):
assert await async_setup_component(hass, light.DOMAIN, config)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("light.test")
assert state.state == STATE_UNKNOWN
@ -843,7 +856,7 @@ async def test_invalid_state_via_topic(hass, mqtt_mock, caplog):
assert light_state.attributes["color_temp"] == 153
async def test_brightness_controlling_scale(hass, mqtt_mock):
async def test_brightness_controlling_scale(hass, mqtt_mock_entry_with_yaml_config):
"""Test the brightness controlling scale."""
with assert_setup_component(1, light.DOMAIN):
assert await async_setup_component(
@ -865,6 +878,7 @@ async def test_brightness_controlling_scale(hass, mqtt_mock):
},
)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("light.test")
assert state.state == STATE_UNKNOWN
@ -890,7 +904,9 @@ async def test_brightness_controlling_scale(hass, mqtt_mock):
assert light_state.attributes["brightness"] == 255
async def test_brightness_from_rgb_controlling_scale(hass, mqtt_mock):
async def test_brightness_from_rgb_controlling_scale(
hass, mqtt_mock_entry_with_yaml_config
):
"""Test the brightness controlling scale."""
with assert_setup_component(1, light.DOMAIN):
assert await async_setup_component(
@ -911,6 +927,7 @@ async def test_brightness_from_rgb_controlling_scale(hass, mqtt_mock):
},
)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("light.test")
assert state.state == STATE_UNKNOWN
@ -929,7 +946,9 @@ async def test_brightness_from_rgb_controlling_scale(hass, mqtt_mock):
assert state.attributes.get("brightness") == 127
async def test_legacy_white_value_controlling_scale(hass, mqtt_mock):
async def test_legacy_white_value_controlling_scale(
hass, mqtt_mock_entry_with_yaml_config
):
"""Test the white_value controlling scale."""
with assert_setup_component(1, light.DOMAIN):
assert await async_setup_component(
@ -951,6 +970,7 @@ async def test_legacy_white_value_controlling_scale(hass, mqtt_mock):
},
)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("light.test")
assert state.state == STATE_UNKNOWN
@ -976,7 +996,9 @@ async def test_legacy_white_value_controlling_scale(hass, mqtt_mock):
assert light_state.attributes["white_value"] == 255
async def test_legacy_controlling_state_via_topic_with_templates(hass, mqtt_mock):
async def test_legacy_controlling_state_via_topic_with_templates(
hass, mqtt_mock_entry_with_yaml_config
):
"""Test the setting of the state with a template."""
config = {
light.DOMAIN: {
@ -1011,6 +1033,7 @@ async def test_legacy_controlling_state_via_topic_with_templates(hass, mqtt_mock
assert await async_setup_component(hass, light.DOMAIN, config)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("light.test")
assert state.state == STATE_UNKNOWN
@ -1065,7 +1088,9 @@ async def test_legacy_controlling_state_via_topic_with_templates(hass, mqtt_mock
assert state.state == STATE_UNKNOWN
async def test_controlling_state_via_topic_with_templates(hass, mqtt_mock):
async def test_controlling_state_via_topic_with_templates(
hass, mqtt_mock_entry_with_yaml_config
):
"""Test the setting of the state with a template."""
config = {
light.DOMAIN: {
@ -1104,6 +1129,7 @@ async def test_controlling_state_via_topic_with_templates(hass, mqtt_mock):
assert await async_setup_component(hass, light.DOMAIN, config)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("light.test")
assert state.state == STATE_UNKNOWN
@ -1165,7 +1191,9 @@ async def test_controlling_state_via_topic_with_templates(hass, mqtt_mock):
assert state.attributes.get(light.ATTR_SUPPORTED_COLOR_MODES) == color_modes
async def test_legacy_sending_mqtt_commands_and_optimistic(hass, mqtt_mock):
async def test_legacy_sending_mqtt_commands_and_optimistic(
hass, mqtt_mock_entry_with_yaml_config
):
"""Test the sending of command in optimistic mode."""
config = {
light.DOMAIN: {
@ -1204,6 +1232,7 @@ async def test_legacy_sending_mqtt_commands_and_optimistic(hass, mqtt_mock):
), assert_setup_component(1, light.DOMAIN):
assert await async_setup_component(hass, light.DOMAIN, config)
await hass.async_block_till_done()
mqtt_mock = await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("light.test")
assert state.state == STATE_ON
@ -1295,7 +1324,9 @@ async def test_legacy_sending_mqtt_commands_and_optimistic(hass, mqtt_mock):
assert state.attributes["color_temp"] == 125
async def test_sending_mqtt_commands_and_optimistic(hass, mqtt_mock):
async def test_sending_mqtt_commands_and_optimistic(
hass, mqtt_mock_entry_with_yaml_config
):
"""Test the sending of command in optimistic mode."""
config = {
light.DOMAIN: {
@ -1334,6 +1365,7 @@ async def test_sending_mqtt_commands_and_optimistic(hass, mqtt_mock):
), assert_setup_component(1, light.DOMAIN):
assert await async_setup_component(hass, light.DOMAIN, config)
await hass.async_block_till_done()
mqtt_mock = await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("light.test")
assert state.state == STATE_ON
@ -1484,7 +1516,9 @@ async def test_sending_mqtt_commands_and_optimistic(hass, mqtt_mock):
assert state.attributes.get(light.ATTR_SUPPORTED_COLOR_MODES) == color_modes
async def test_sending_mqtt_rgb_command_with_template(hass, mqtt_mock):
async def test_sending_mqtt_rgb_command_with_template(
hass, mqtt_mock_entry_with_yaml_config
):
"""Test the sending of RGB command with template."""
config = {
light.DOMAIN: {
@ -1502,6 +1536,7 @@ async def test_sending_mqtt_rgb_command_with_template(hass, mqtt_mock):
assert await async_setup_component(hass, light.DOMAIN, config)
await hass.async_block_till_done()
mqtt_mock = await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("light.test")
assert state.state == STATE_UNKNOWN
@ -1521,7 +1556,9 @@ async def test_sending_mqtt_rgb_command_with_template(hass, mqtt_mock):
assert state.attributes["rgb_color"] == (255, 128, 64)
async def test_sending_mqtt_rgbw_command_with_template(hass, mqtt_mock):
async def test_sending_mqtt_rgbw_command_with_template(
hass, mqtt_mock_entry_with_yaml_config
):
"""Test the sending of RGBW command with template."""
config = {
light.DOMAIN: {
@ -1539,6 +1576,7 @@ async def test_sending_mqtt_rgbw_command_with_template(hass, mqtt_mock):
assert await async_setup_component(hass, light.DOMAIN, config)
await hass.async_block_till_done()
mqtt_mock = await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("light.test")
assert state.state == STATE_UNKNOWN
@ -1558,7 +1596,9 @@ async def test_sending_mqtt_rgbw_command_with_template(hass, mqtt_mock):
assert state.attributes["rgbw_color"] == (255, 128, 64, 32)
async def test_sending_mqtt_rgbww_command_with_template(hass, mqtt_mock):
async def test_sending_mqtt_rgbww_command_with_template(
hass, mqtt_mock_entry_with_yaml_config
):
"""Test the sending of RGBWW command with template."""
config = {
light.DOMAIN: {
@ -1576,6 +1616,7 @@ async def test_sending_mqtt_rgbww_command_with_template(hass, mqtt_mock):
assert await async_setup_component(hass, light.DOMAIN, config)
await hass.async_block_till_done()
mqtt_mock = await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("light.test")
assert state.state == STATE_UNKNOWN
@ -1595,7 +1636,9 @@ async def test_sending_mqtt_rgbww_command_with_template(hass, mqtt_mock):
assert state.attributes["rgbww_color"] == (255, 128, 64, 32, 16)
async def test_sending_mqtt_color_temp_command_with_template(hass, mqtt_mock):
async def test_sending_mqtt_color_temp_command_with_template(
hass, mqtt_mock_entry_with_yaml_config
):
"""Test the sending of Color Temp command with template."""
config = {
light.DOMAIN: {
@ -1612,6 +1655,7 @@ async def test_sending_mqtt_color_temp_command_with_template(hass, mqtt_mock):
assert await async_setup_component(hass, light.DOMAIN, config)
await hass.async_block_till_done()
mqtt_mock = await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("light.test")
assert state.state == STATE_UNKNOWN
@ -1631,7 +1675,7 @@ async def test_sending_mqtt_color_temp_command_with_template(hass, mqtt_mock):
assert state.attributes["color_temp"] == 100
async def test_on_command_first(hass, mqtt_mock):
async def test_on_command_first(hass, mqtt_mock_entry_with_yaml_config):
"""Test on command being sent before brightness."""
config = {
light.DOMAIN: {
@ -1645,6 +1689,7 @@ async def test_on_command_first(hass, mqtt_mock):
assert await async_setup_component(hass, light.DOMAIN, config)
await hass.async_block_till_done()
mqtt_mock = await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("light.test")
assert state.state == STATE_UNKNOWN
@ -1667,7 +1712,7 @@ async def test_on_command_first(hass, mqtt_mock):
mqtt_mock.async_publish.assert_called_once_with("test_light/set", "OFF", 0, False)
async def test_on_command_last(hass, mqtt_mock):
async def test_on_command_last(hass, mqtt_mock_entry_with_yaml_config):
"""Test on command being sent after brightness."""
config = {
light.DOMAIN: {
@ -1680,6 +1725,7 @@ async def test_on_command_last(hass, mqtt_mock):
assert await async_setup_component(hass, light.DOMAIN, config)
await hass.async_block_till_done()
mqtt_mock = await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("light.test")
assert state.state == STATE_UNKNOWN
@ -1702,7 +1748,7 @@ async def test_on_command_last(hass, mqtt_mock):
mqtt_mock.async_publish.assert_called_once_with("test_light/set", "OFF", 0, False)
async def test_on_command_brightness(hass, mqtt_mock):
async def test_on_command_brightness(hass, mqtt_mock_entry_with_yaml_config):
"""Test on command being sent as only brightness."""
config = {
light.DOMAIN: {
@ -1717,6 +1763,7 @@ async def test_on_command_brightness(hass, mqtt_mock):
assert await async_setup_component(hass, light.DOMAIN, config)
await hass.async_block_till_done()
mqtt_mock = await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("light.test")
assert state.state == STATE_UNKNOWN
@ -1757,7 +1804,7 @@ async def test_on_command_brightness(hass, mqtt_mock):
)
async def test_on_command_brightness_scaled(hass, mqtt_mock):
async def test_on_command_brightness_scaled(hass, mqtt_mock_entry_with_yaml_config):
"""Test brightness scale."""
config = {
light.DOMAIN: {
@ -1773,6 +1820,7 @@ async def test_on_command_brightness_scaled(hass, mqtt_mock):
assert await async_setup_component(hass, light.DOMAIN, config)
await hass.async_block_till_done()
mqtt_mock = await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("light.test")
assert state.state == STATE_UNKNOWN
@ -1827,7 +1875,7 @@ async def test_on_command_brightness_scaled(hass, mqtt_mock):
)
async def test_legacy_on_command_rgb(hass, mqtt_mock):
async def test_legacy_on_command_rgb(hass, mqtt_mock_entry_with_yaml_config):
"""Test on command in RGB brightness mode."""
config = {
light.DOMAIN: {
@ -1841,6 +1889,7 @@ async def test_legacy_on_command_rgb(hass, mqtt_mock):
assert await async_setup_component(hass, light.DOMAIN, config)
await hass.async_block_till_done()
mqtt_mock = await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("light.test")
assert state.state == STATE_UNKNOWN
@ -1918,7 +1967,7 @@ async def test_legacy_on_command_rgb(hass, mqtt_mock):
mqtt_mock.async_publish.reset_mock()
async def test_on_command_rgb(hass, mqtt_mock):
async def test_on_command_rgb(hass, mqtt_mock_entry_with_yaml_config):
"""Test on command in RGB brightness mode."""
config = {
light.DOMAIN: {
@ -1931,6 +1980,7 @@ async def test_on_command_rgb(hass, mqtt_mock):
assert await async_setup_component(hass, light.DOMAIN, config)
await hass.async_block_till_done()
mqtt_mock = await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("light.test")
assert state.state == STATE_UNKNOWN
@ -2008,7 +2058,7 @@ async def test_on_command_rgb(hass, mqtt_mock):
mqtt_mock.async_publish.reset_mock()
async def test_on_command_rgbw(hass, mqtt_mock):
async def test_on_command_rgbw(hass, mqtt_mock_entry_with_yaml_config):
"""Test on command in RGBW brightness mode."""
config = {
light.DOMAIN: {
@ -2021,6 +2071,7 @@ async def test_on_command_rgbw(hass, mqtt_mock):
assert await async_setup_component(hass, light.DOMAIN, config)
await hass.async_block_till_done()
mqtt_mock = await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("light.test")
assert state.state == STATE_UNKNOWN
@ -2098,7 +2149,7 @@ async def test_on_command_rgbw(hass, mqtt_mock):
mqtt_mock.async_publish.reset_mock()
async def test_on_command_rgbww(hass, mqtt_mock):
async def test_on_command_rgbww(hass, mqtt_mock_entry_with_yaml_config):
"""Test on command in RGBWW brightness mode."""
config = {
light.DOMAIN: {
@ -2111,6 +2162,7 @@ async def test_on_command_rgbww(hass, mqtt_mock):
assert await async_setup_component(hass, light.DOMAIN, config)
await hass.async_block_till_done()
mqtt_mock = await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("light.test")
assert state.state == STATE_UNKNOWN
@ -2188,7 +2240,7 @@ async def test_on_command_rgbww(hass, mqtt_mock):
mqtt_mock.async_publish.reset_mock()
async def test_on_command_rgb_template(hass, mqtt_mock):
async def test_on_command_rgb_template(hass, mqtt_mock_entry_with_yaml_config):
"""Test on command in RGB brightness mode with RGB template."""
config = {
light.DOMAIN: {
@ -2202,6 +2254,7 @@ async def test_on_command_rgb_template(hass, mqtt_mock):
assert await async_setup_component(hass, light.DOMAIN, config)
await hass.async_block_till_done()
mqtt_mock = await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("light.test")
assert state.state == STATE_UNKNOWN
@ -2225,7 +2278,7 @@ async def test_on_command_rgb_template(hass, mqtt_mock):
mqtt_mock.async_publish.assert_called_once_with("test_light/set", "OFF", 0, False)
async def test_on_command_rgbw_template(hass, mqtt_mock):
async def test_on_command_rgbw_template(hass, mqtt_mock_entry_with_yaml_config):
"""Test on command in RGBW brightness mode with RGBW template."""
config = {
light.DOMAIN: {
@ -2239,6 +2292,7 @@ async def test_on_command_rgbw_template(hass, mqtt_mock):
assert await async_setup_component(hass, light.DOMAIN, config)
await hass.async_block_till_done()
mqtt_mock = await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("light.test")
assert state.state == STATE_UNKNOWN
@ -2261,7 +2315,7 @@ async def test_on_command_rgbw_template(hass, mqtt_mock):
mqtt_mock.async_publish.assert_called_once_with("test_light/set", "OFF", 0, False)
async def test_on_command_rgbww_template(hass, mqtt_mock):
async def test_on_command_rgbww_template(hass, mqtt_mock_entry_with_yaml_config):
"""Test on command in RGBWW brightness mode with RGBWW template."""
config = {
light.DOMAIN: {
@ -2275,6 +2329,7 @@ async def test_on_command_rgbww_template(hass, mqtt_mock):
assert await async_setup_component(hass, light.DOMAIN, config)
await hass.async_block_till_done()
mqtt_mock = await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("light.test")
assert state.state == STATE_UNKNOWN
@ -2298,7 +2353,7 @@ async def test_on_command_rgbww_template(hass, mqtt_mock):
mqtt_mock.async_publish.assert_called_once_with("test_light/set", "OFF", 0, False)
async def test_on_command_white(hass, mqtt_mock):
async def test_on_command_white(hass, mqtt_mock_entry_with_yaml_config):
"""Test sending commands for RGB + white light."""
config = {
light.DOMAIN: {
@ -2324,6 +2379,7 @@ async def test_on_command_white(hass, mqtt_mock):
assert await async_setup_component(hass, light.DOMAIN, config)
await hass.async_block_till_done()
mqtt_mock = await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("light.test")
assert state.state == STATE_UNKNOWN
@ -2375,7 +2431,7 @@ async def test_on_command_white(hass, mqtt_mock):
)
async def test_explicit_color_mode(hass, mqtt_mock):
async def test_explicit_color_mode(hass, mqtt_mock_entry_with_yaml_config):
"""Test explicit color mode over mqtt."""
config = {
light.DOMAIN: {
@ -2409,6 +2465,7 @@ async def test_explicit_color_mode(hass, mqtt_mock):
assert await async_setup_component(hass, light.DOMAIN, config)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("light.test")
assert state.state == STATE_UNKNOWN
@ -2525,7 +2582,7 @@ async def test_explicit_color_mode(hass, mqtt_mock):
assert light_state.attributes.get(light.ATTR_SUPPORTED_COLOR_MODES) == color_modes
async def test_explicit_color_mode_templated(hass, mqtt_mock):
async def test_explicit_color_mode_templated(hass, mqtt_mock_entry_with_yaml_config):
"""Test templated explicit color mode over mqtt."""
config = {
light.DOMAIN: {
@ -2550,6 +2607,7 @@ async def test_explicit_color_mode_templated(hass, mqtt_mock):
assert await async_setup_component(hass, light.DOMAIN, config)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("light.test")
assert state.state == STATE_UNKNOWN
@ -2606,7 +2664,7 @@ async def test_explicit_color_mode_templated(hass, mqtt_mock):
assert light_state.attributes.get(light.ATTR_SUPPORTED_COLOR_MODES) == color_modes
async def test_white_state_update(hass, mqtt_mock):
async def test_white_state_update(hass, mqtt_mock_entry_with_yaml_config):
"""Test state updates for RGB + white light."""
config = {
light.DOMAIN: {
@ -2636,6 +2694,7 @@ async def test_white_state_update(hass, mqtt_mock):
assert await async_setup_component(hass, light.DOMAIN, config)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("light.test")
assert state.state == STATE_UNKNOWN
@ -2670,7 +2729,7 @@ async def test_white_state_update(hass, mqtt_mock):
assert state.attributes.get(light.ATTR_SUPPORTED_COLOR_MODES) == color_modes
async def test_effect(hass, mqtt_mock):
async def test_effect(hass, mqtt_mock_entry_with_yaml_config):
"""Test effect."""
config = {
light.DOMAIN: {
@ -2684,6 +2743,7 @@ async def test_effect(hass, mqtt_mock):
assert await async_setup_component(hass, light.DOMAIN, config)
await hass.async_block_till_done()
mqtt_mock = await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("light.test")
assert state.state == STATE_UNKNOWN
@ -2707,77 +2767,91 @@ async def test_effect(hass, mqtt_mock):
mqtt_mock.async_publish.assert_called_once_with("test_light/set", "OFF", 0, False)
async def test_availability_when_connection_lost(hass, mqtt_mock):
async def test_availability_when_connection_lost(
hass, mqtt_mock_entry_with_yaml_config
):
"""Test availability after MQTT disconnection."""
await help_test_availability_when_connection_lost(
hass, mqtt_mock, light.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_with_yaml_config, light.DOMAIN, DEFAULT_CONFIG
)
async def test_availability_without_topic(hass, mqtt_mock):
async def test_availability_without_topic(hass, mqtt_mock_entry_with_yaml_config):
"""Test availability without defined availability topic."""
await help_test_availability_without_topic(
hass, mqtt_mock, light.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_with_yaml_config, light.DOMAIN, DEFAULT_CONFIG
)
async def test_default_availability_payload(hass, mqtt_mock):
async def test_default_availability_payload(hass, mqtt_mock_entry_with_yaml_config):
"""Test availability by default payload with defined topic."""
await help_test_default_availability_payload(
hass, mqtt_mock, light.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_with_yaml_config, light.DOMAIN, DEFAULT_CONFIG
)
async def test_custom_availability_payload(hass, mqtt_mock):
async def test_custom_availability_payload(hass, mqtt_mock_entry_with_yaml_config):
"""Test availability by custom payload with defined topic."""
await help_test_custom_availability_payload(
hass, mqtt_mock, light.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_with_yaml_config, light.DOMAIN, DEFAULT_CONFIG
)
async def test_setting_attribute_via_mqtt_json_message(hass, mqtt_mock):
async def test_setting_attribute_via_mqtt_json_message(
hass, mqtt_mock_entry_with_yaml_config
):
"""Test the setting of attribute via MQTT with JSON payload."""
await help_test_setting_attribute_via_mqtt_json_message(
hass, mqtt_mock, light.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_with_yaml_config, light.DOMAIN, DEFAULT_CONFIG
)
async def test_setting_blocked_attribute_via_mqtt_json_message(hass, mqtt_mock):
async def test_setting_blocked_attribute_via_mqtt_json_message(
hass, mqtt_mock_entry_no_yaml_config
):
"""Test the setting of attribute via MQTT with JSON payload."""
await help_test_setting_blocked_attribute_via_mqtt_json_message(
hass, mqtt_mock, light.DOMAIN, DEFAULT_CONFIG, MQTT_LIGHT_ATTRIBUTES_BLOCKED
hass,
mqtt_mock_entry_no_yaml_config,
light.DOMAIN,
DEFAULT_CONFIG,
MQTT_LIGHT_ATTRIBUTES_BLOCKED,
)
async def test_setting_attribute_with_template(hass, mqtt_mock):
async def test_setting_attribute_with_template(hass, mqtt_mock_entry_with_yaml_config):
"""Test the setting of attribute via MQTT with JSON payload."""
await help_test_setting_attribute_with_template(
hass, mqtt_mock, light.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_with_yaml_config, light.DOMAIN, DEFAULT_CONFIG
)
async def test_update_with_json_attrs_not_dict(hass, mqtt_mock, caplog):
async def test_update_with_json_attrs_not_dict(
hass, mqtt_mock_entry_with_yaml_config, caplog
):
"""Test attributes get extracted from a JSON result."""
await help_test_update_with_json_attrs_not_dict(
hass, mqtt_mock, caplog, light.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_with_yaml_config, caplog, light.DOMAIN, DEFAULT_CONFIG
)
async def test_update_with_json_attrs_bad_JSON(hass, mqtt_mock, caplog):
async def test_update_with_json_attrs_bad_JSON(
hass, mqtt_mock_entry_with_yaml_config, caplog
):
"""Test attributes get extracted from a JSON result."""
await help_test_update_with_json_attrs_bad_JSON(
hass, mqtt_mock, caplog, light.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_with_yaml_config, caplog, light.DOMAIN, DEFAULT_CONFIG
)
async def test_discovery_update_attr(hass, mqtt_mock, caplog):
async def test_discovery_update_attr(hass, mqtt_mock_entry_no_yaml_config, caplog):
"""Test update of discovered MQTTAttributes."""
await help_test_discovery_update_attr(
hass, mqtt_mock, caplog, light.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_no_yaml_config, caplog, light.DOMAIN, DEFAULT_CONFIG
)
async def test_unique_id(hass, mqtt_mock):
async def test_unique_id(hass, mqtt_mock_entry_with_yaml_config):
"""Test unique id option only creates one light per unique_id."""
config = {
light.DOMAIN: [
@ -2797,21 +2871,26 @@ async def test_unique_id(hass, mqtt_mock):
},
]
}
await help_test_unique_id(hass, mqtt_mock, light.DOMAIN, config)
await help_test_unique_id(
hass, mqtt_mock_entry_with_yaml_config, light.DOMAIN, config
)
async def test_discovery_removal_light(hass, mqtt_mock, caplog):
async def test_discovery_removal_light(hass, mqtt_mock_entry_no_yaml_config, caplog):
"""Test removal of discovered light."""
data = (
'{ "name": "test",'
' "state_topic": "test_topic",'
' "command_topic": "test_topic" }'
)
await help_test_discovery_removal(hass, mqtt_mock, caplog, light.DOMAIN, data)
await help_test_discovery_removal(
hass, mqtt_mock_entry_no_yaml_config, caplog, light.DOMAIN, data
)
async def test_discovery_deprecated(hass, mqtt_mock, caplog):
async def test_discovery_deprecated(hass, mqtt_mock_entry_no_yaml_config, caplog):
"""Test discovery of mqtt light with deprecated platform option."""
await mqtt_mock_entry_no_yaml_config()
data = (
'{ "name": "Beer",' ' "platform": "mqtt",' ' "command_topic": "test_topic"}'
)
@ -2822,7 +2901,9 @@ async def test_discovery_deprecated(hass, mqtt_mock, caplog):
assert state.name == "Beer"
async def test_discovery_update_light_topic_and_template(hass, mqtt_mock, caplog):
async def test_discovery_update_light_topic_and_template(
hass, mqtt_mock_entry_no_yaml_config, caplog
):
"""Test update of discovered light."""
config1 = {
"name": "Beer",
@ -3073,7 +3154,7 @@ async def test_discovery_update_light_topic_and_template(hass, mqtt_mock, caplog
await help_test_discovery_update(
hass,
mqtt_mock,
mqtt_mock_entry_no_yaml_config,
caplog,
light.DOMAIN,
config1,
@ -3083,7 +3164,9 @@ async def test_discovery_update_light_topic_and_template(hass, mqtt_mock, caplog
)
async def test_discovery_update_light_template(hass, mqtt_mock, caplog):
async def test_discovery_update_light_template(
hass, mqtt_mock_entry_no_yaml_config, caplog
):
"""Test update of discovered light."""
config1 = {
"name": "Beer",
@ -3292,7 +3375,7 @@ async def test_discovery_update_light_template(hass, mqtt_mock, caplog):
await help_test_discovery_update(
hass,
mqtt_mock,
mqtt_mock_entry_no_yaml_config,
caplog,
light.DOMAIN,
config1,
@ -3302,7 +3385,9 @@ async def test_discovery_update_light_template(hass, mqtt_mock, caplog):
)
async def test_discovery_update_unchanged_light(hass, mqtt_mock, caplog):
async def test_discovery_update_unchanged_light(
hass, mqtt_mock_entry_no_yaml_config, caplog
):
"""Test update of discovered light."""
data1 = (
'{ "name": "Beer",'
@ -3313,12 +3398,17 @@ async def test_discovery_update_unchanged_light(hass, mqtt_mock, caplog):
"homeassistant.components.mqtt.light.schema_basic.MqttLight.discovery_update"
) as discovery_update:
await help_test_discovery_update_unchanged(
hass, mqtt_mock, caplog, light.DOMAIN, data1, discovery_update
hass,
mqtt_mock_entry_no_yaml_config,
caplog,
light.DOMAIN,
data1,
discovery_update,
)
@pytest.mark.no_fail_on_log_exception
async def test_discovery_broken(hass, mqtt_mock, caplog):
async def test_discovery_broken(hass, mqtt_mock_entry_no_yaml_config, caplog):
"""Test handling of bad discovery message."""
data1 = '{ "name": "Beer" }'
data2 = (
@ -3327,60 +3417,64 @@ async def test_discovery_broken(hass, mqtt_mock, caplog):
' "command_topic": "test_topic" }'
)
await help_test_discovery_broken(
hass, mqtt_mock, caplog, light.DOMAIN, data1, data2
hass, mqtt_mock_entry_no_yaml_config, caplog, light.DOMAIN, data1, data2
)
async def test_entity_device_info_with_connection(hass, mqtt_mock):
async def test_entity_device_info_with_connection(hass, mqtt_mock_entry_no_yaml_config):
"""Test MQTT light device registry integration."""
await help_test_entity_device_info_with_connection(
hass, mqtt_mock, light.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_no_yaml_config, light.DOMAIN, DEFAULT_CONFIG
)
async def test_entity_device_info_with_identifier(hass, mqtt_mock):
async def test_entity_device_info_with_identifier(hass, mqtt_mock_entry_no_yaml_config):
"""Test MQTT light device registry integration."""
await help_test_entity_device_info_with_identifier(
hass, mqtt_mock, light.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_no_yaml_config, light.DOMAIN, DEFAULT_CONFIG
)
async def test_entity_device_info_update(hass, mqtt_mock):
async def test_entity_device_info_update(hass, mqtt_mock_entry_no_yaml_config):
"""Test device registry update."""
await help_test_entity_device_info_update(
hass, mqtt_mock, light.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_no_yaml_config, light.DOMAIN, DEFAULT_CONFIG
)
async def test_entity_device_info_remove(hass, mqtt_mock):
async def test_entity_device_info_remove(hass, mqtt_mock_entry_no_yaml_config):
"""Test device registry remove."""
await help_test_entity_device_info_remove(
hass, mqtt_mock, light.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_no_yaml_config, light.DOMAIN, DEFAULT_CONFIG
)
async def test_entity_id_update_subscriptions(hass, mqtt_mock):
async def test_entity_id_update_subscriptions(hass, mqtt_mock_entry_with_yaml_config):
"""Test MQTT subscriptions are managed when entity_id is updated."""
await help_test_entity_id_update_subscriptions(
hass, mqtt_mock, light.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_with_yaml_config, light.DOMAIN, DEFAULT_CONFIG
)
async def test_entity_id_update_discovery_update(hass, mqtt_mock):
async def test_entity_id_update_discovery_update(hass, mqtt_mock_entry_no_yaml_config):
"""Test MQTT discovery update when entity_id is updated."""
await help_test_entity_id_update_discovery_update(
hass, mqtt_mock, light.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_no_yaml_config, light.DOMAIN, DEFAULT_CONFIG
)
async def test_entity_debug_info_message(hass, mqtt_mock):
async def test_entity_debug_info_message(hass, mqtt_mock_entry_no_yaml_config):
"""Test MQTT debug info."""
await help_test_entity_debug_info_message(
hass, mqtt_mock, light.DOMAIN, DEFAULT_CONFIG, light.SERVICE_TURN_ON
hass,
mqtt_mock_entry_no_yaml_config,
light.DOMAIN,
DEFAULT_CONFIG,
light.SERVICE_TURN_ON,
)
async def test_max_mireds(hass, mqtt_mock):
async def test_max_mireds(hass, mqtt_mock_entry_with_yaml_config):
"""Test setting min_mireds and max_mireds."""
config = {
light.DOMAIN: {
@ -3394,6 +3488,7 @@ async def test_max_mireds(hass, mqtt_mock):
assert await async_setup_component(hass, light.DOMAIN, config)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("light.test")
assert state.attributes.get("min_mireds") == 153
@ -3488,7 +3583,7 @@ async def test_max_mireds(hass, mqtt_mock):
)
async def test_publishing_with_custom_encoding(
hass,
mqtt_mock,
mqtt_mock_entry_with_yaml_config,
caplog,
service,
topic,
@ -3508,7 +3603,7 @@ async def test_publishing_with_custom_encoding(
await help_test_publishing_with_custom_encoding(
hass,
mqtt_mock,
mqtt_mock_entry_with_yaml_config,
caplog,
domain,
config,
@ -3522,11 +3617,13 @@ async def test_publishing_with_custom_encoding(
)
async def test_reloadable(hass, mqtt_mock, caplog, tmp_path):
async def test_reloadable(hass, mqtt_mock_entry_with_yaml_config, caplog, tmp_path):
"""Test reloading the MQTT platform."""
domain = light.DOMAIN
config = DEFAULT_CONFIG[domain]
await help_test_reloadable(hass, mqtt_mock, caplog, tmp_path, domain, config)
await help_test_reloadable(
hass, mqtt_mock_entry_with_yaml_config, caplog, tmp_path, domain, config
)
async def test_reloadable_late(hass, mqtt_client_mock, caplog, tmp_path):
@ -3568,7 +3665,14 @@ async def test_reloadable_late(hass, mqtt_client_mock, caplog, tmp_path):
],
)
async def test_encoding_subscribable_topics(
hass, mqtt_mock, caplog, topic, value, attribute, attribute_value, init_payload
hass,
mqtt_mock_entry_with_yaml_config,
caplog,
topic,
value,
attribute,
attribute_value,
init_payload,
):
"""Test handling of incoming encoded payload."""
config = copy.deepcopy(DEFAULT_CONFIG[light.DOMAIN])
@ -3587,7 +3691,7 @@ async def test_encoding_subscribable_topics(
await help_test_encoding_subscribable_topics(
hass,
mqtt_mock,
mqtt_mock_entry_with_yaml_config,
caplog,
light.DOMAIN,
config,
@ -3599,7 +3703,9 @@ async def test_encoding_subscribable_topics(
)
async def test_sending_mqtt_brightness_command_with_template(hass, mqtt_mock):
async def test_sending_mqtt_brightness_command_with_template(
hass, mqtt_mock_entry_with_yaml_config
):
"""Test the sending of Brightness command with template."""
config = {
light.DOMAIN: {
@ -3616,6 +3722,7 @@ async def test_sending_mqtt_brightness_command_with_template(hass, mqtt_mock):
assert await async_setup_component(hass, light.DOMAIN, config)
await hass.async_block_till_done()
mqtt_mock = await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("light.test")
assert state.state == STATE_UNKNOWN
@ -3635,7 +3742,9 @@ async def test_sending_mqtt_brightness_command_with_template(hass, mqtt_mock):
assert state.attributes["brightness"] == 100
async def test_sending_mqtt_effect_command_with_template(hass, mqtt_mock):
async def test_sending_mqtt_effect_command_with_template(
hass, mqtt_mock_entry_with_yaml_config
):
"""Test the sending of Effect command with template."""
config = {
light.DOMAIN: {
@ -3654,6 +3763,7 @@ async def test_sending_mqtt_effect_command_with_template(hass, mqtt_mock):
assert await async_setup_component(hass, light.DOMAIN, config)
await hass.async_block_till_done()
mqtt_mock = await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("light.test")
assert state.state == STATE_UNKNOWN

View File

@ -162,7 +162,7 @@ class JsonValidator:
return json.loads(self.jsondata) == json.loads(other)
async def test_fail_setup_if_no_command_topic(hass, mqtt_mock):
async def test_fail_setup_if_no_command_topic(hass, mqtt_mock_entry_no_yaml_config):
"""Test if setup fails with no command topic."""
assert await async_setup_component(
hass,
@ -170,11 +170,14 @@ async def test_fail_setup_if_no_command_topic(hass, mqtt_mock):
{light.DOMAIN: {"platform": "mqtt", "schema": "json", "name": "test"}},
)
await hass.async_block_till_done()
await mqtt_mock_entry_no_yaml_config()
assert hass.states.get("light.test") is None
@pytest.mark.parametrize("deprecated", ("color_temp", "hs", "rgb", "white_value", "xy"))
async def test_fail_setup_if_color_mode_deprecated(hass, mqtt_mock, deprecated):
async def test_fail_setup_if_color_mode_deprecated(
hass, mqtt_mock_entry_no_yaml_config, deprecated
):
"""Test if setup fails if color mode is combined with deprecated config keys."""
supported_color_modes = ["color_temp", "hs", "rgb", "rgbw", "rgbww", "xy"]
@ -196,6 +199,7 @@ async def test_fail_setup_if_color_mode_deprecated(hass, mqtt_mock, deprecated):
config,
)
await hass.async_block_till_done()
await mqtt_mock_entry_no_yaml_config()
assert hass.states.get("light.test") is None
@ -203,7 +207,7 @@ async def test_fail_setup_if_color_mode_deprecated(hass, mqtt_mock, deprecated):
"supported_color_modes", [["onoff", "rgb"], ["brightness", "rgb"], ["unknown"]]
)
async def test_fail_setup_if_color_modes_invalid(
hass, mqtt_mock, supported_color_modes
hass, mqtt_mock_entry_no_yaml_config, supported_color_modes
):
"""Test if setup fails if supported color modes is invalid."""
config = {
@ -223,10 +227,11 @@ async def test_fail_setup_if_color_modes_invalid(
config,
)
await hass.async_block_till_done()
await mqtt_mock_entry_no_yaml_config()
assert hass.states.get("light.test") is None
async def test_rgb_light(hass, mqtt_mock):
async def test_rgb_light(hass, mqtt_mock_entry_with_yaml_config):
"""Test RGB light flags brightness support."""
assert await async_setup_component(
hass,
@ -242,6 +247,7 @@ async def test_rgb_light(hass, mqtt_mock):
},
)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("light.test")
expected_features = (
@ -253,7 +259,9 @@ async def test_rgb_light(hass, mqtt_mock):
assert state.attributes.get(ATTR_SUPPORTED_FEATURES) == expected_features
async def test_no_color_brightness_color_temp_white_val_if_no_topics(hass, mqtt_mock):
async def test_no_color_brightness_color_temp_white_val_if_no_topics(
hass, mqtt_mock_entry_with_yaml_config
):
"""Test for no RGB, brightness, color temp, effect, white val or XY."""
assert await async_setup_component(
hass,
@ -269,6 +277,7 @@ async def test_no_color_brightness_color_temp_white_val_if_no_topics(hass, mqtt_
},
)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("light.test")
assert state.state == STATE_UNKNOWN
@ -305,7 +314,7 @@ async def test_no_color_brightness_color_temp_white_val_if_no_topics(hass, mqtt_
assert state.state == STATE_UNKNOWN
async def test_controlling_state_via_topic(hass, mqtt_mock):
async def test_controlling_state_via_topic(hass, mqtt_mock_entry_with_yaml_config):
"""Test the controlling of the state via topic."""
assert await async_setup_component(
hass,
@ -329,6 +338,7 @@ async def test_controlling_state_via_topic(hass, mqtt_mock):
},
)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("light.test")
assert state.state == STATE_UNKNOWN
@ -434,7 +444,9 @@ async def test_controlling_state_via_topic(hass, mqtt_mock):
assert light_state.attributes.get("white_value") == 155
async def test_controlling_state_via_topic2(hass, mqtt_mock, caplog):
async def test_controlling_state_via_topic2(
hass, mqtt_mock_entry_with_yaml_config, caplog
):
"""Test the controlling of the state via topic for a light supporting color mode."""
supported_color_modes = ["color_temp", "hs", "rgb", "rgbw", "rgbww", "xy"]
@ -457,6 +469,7 @@ async def test_controlling_state_via_topic2(hass, mqtt_mock, caplog):
},
)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("light.test")
assert state.state == STATE_UNKNOWN
@ -602,7 +615,9 @@ async def test_controlling_state_via_topic2(hass, mqtt_mock, caplog):
assert "Invalid or incomplete color value received" in caplog.text
async def test_sending_mqtt_commands_and_optimistic(hass, mqtt_mock):
async def test_sending_mqtt_commands_and_optimistic(
hass, mqtt_mock_entry_with_yaml_config
):
"""Test the sending of command in optimistic mode."""
fake_state = ha.State(
"light.test",
@ -641,6 +656,7 @@ async def test_sending_mqtt_commands_and_optimistic(hass, mqtt_mock):
},
)
await hass.async_block_till_done()
mqtt_mock = await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("light.test")
assert state.state == STATE_ON
@ -745,7 +761,9 @@ async def test_sending_mqtt_commands_and_optimistic(hass, mqtt_mock):
assert state.attributes["xy_color"] == (0.611, 0.375)
async def test_sending_mqtt_commands_and_optimistic2(hass, mqtt_mock):
async def test_sending_mqtt_commands_and_optimistic2(
hass, mqtt_mock_entry_with_yaml_config
):
"""Test the sending of command in optimistic mode for a light supporting color mode."""
supported_color_modes = ["color_temp", "hs", "rgb", "rgbw", "rgbww", "xy"]
fake_state = ha.State(
@ -783,6 +801,7 @@ async def test_sending_mqtt_commands_and_optimistic2(hass, mqtt_mock):
},
)
await hass.async_block_till_done()
mqtt_mock = await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("light.test")
assert state.state == STATE_ON
@ -953,7 +972,7 @@ async def test_sending_mqtt_commands_and_optimistic2(hass, mqtt_mock):
mqtt_mock.async_publish.reset_mock()
async def test_sending_hs_color(hass, mqtt_mock):
async def test_sending_hs_color(hass, mqtt_mock_entry_with_yaml_config):
"""Test light.turn_on with hs color sends hs color parameters."""
assert await async_setup_component(
hass,
@ -971,6 +990,7 @@ async def test_sending_hs_color(hass, mqtt_mock):
},
)
await hass.async_block_till_done()
mqtt_mock = await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("light.test")
assert state.state == STATE_UNKNOWN
@ -1018,7 +1038,7 @@ async def test_sending_hs_color(hass, mqtt_mock):
)
async def test_sending_rgb_color_no_brightness(hass, mqtt_mock):
async def test_sending_rgb_color_no_brightness(hass, mqtt_mock_entry_with_yaml_config):
"""Test light.turn_on with hs color sends rgb color parameters."""
assert await async_setup_component(
hass,
@ -1034,6 +1054,7 @@ async def test_sending_rgb_color_no_brightness(hass, mqtt_mock):
},
)
await hass.async_block_till_done()
mqtt_mock = await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("light.test")
assert state.state == STATE_UNKNOWN
@ -1071,7 +1092,7 @@ async def test_sending_rgb_color_no_brightness(hass, mqtt_mock):
)
async def test_sending_rgb_color_no_brightness2(hass, mqtt_mock):
async def test_sending_rgb_color_no_brightness2(hass, mqtt_mock_entry_with_yaml_config):
"""Test light.turn_on with hs color sends rgb color parameters."""
supported_color_modes = ["rgb", "rgbw", "rgbww"]
assert await async_setup_component(
@ -1089,6 +1110,7 @@ async def test_sending_rgb_color_no_brightness2(hass, mqtt_mock):
},
)
await hass.async_block_till_done()
mqtt_mock = await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("light.test")
assert state.state == STATE_UNKNOWN
@ -1148,7 +1170,9 @@ async def test_sending_rgb_color_no_brightness2(hass, mqtt_mock):
)
async def test_sending_rgb_color_with_brightness(hass, mqtt_mock):
async def test_sending_rgb_color_with_brightness(
hass, mqtt_mock_entry_with_yaml_config
):
"""Test light.turn_on with hs color sends rgb color parameters."""
assert await async_setup_component(
hass,
@ -1166,6 +1190,7 @@ async def test_sending_rgb_color_with_brightness(hass, mqtt_mock):
},
)
await hass.async_block_till_done()
mqtt_mock = await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("light.test")
assert state.state == STATE_UNKNOWN
@ -1218,7 +1243,9 @@ async def test_sending_rgb_color_with_brightness(hass, mqtt_mock):
)
async def test_sending_rgb_color_with_scaled_brightness(hass, mqtt_mock):
async def test_sending_rgb_color_with_scaled_brightness(
hass, mqtt_mock_entry_with_yaml_config
):
"""Test light.turn_on with hs color sends rgb color parameters."""
assert await async_setup_component(
hass,
@ -1237,6 +1264,7 @@ async def test_sending_rgb_color_with_scaled_brightness(hass, mqtt_mock):
},
)
await hass.async_block_till_done()
mqtt_mock = await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("light.test")
assert state.state == STATE_UNKNOWN
@ -1289,7 +1317,7 @@ async def test_sending_rgb_color_with_scaled_brightness(hass, mqtt_mock):
)
async def test_sending_xy_color(hass, mqtt_mock):
async def test_sending_xy_color(hass, mqtt_mock_entry_with_yaml_config):
"""Test light.turn_on with hs color sends xy color parameters."""
assert await async_setup_component(
hass,
@ -1307,6 +1335,7 @@ async def test_sending_xy_color(hass, mqtt_mock):
},
)
await hass.async_block_till_done()
mqtt_mock = await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("light.test")
assert state.state == STATE_UNKNOWN
@ -1353,7 +1382,7 @@ async def test_sending_xy_color(hass, mqtt_mock):
)
async def test_effect(hass, mqtt_mock):
async def test_effect(hass, mqtt_mock_entry_with_yaml_config):
"""Test for effect being sent when included."""
assert await async_setup_component(
hass,
@ -1370,6 +1399,7 @@ async def test_effect(hass, mqtt_mock):
},
)
await hass.async_block_till_done()
mqtt_mock = await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("light.test")
assert state.state == STATE_UNKNOWN
@ -1415,7 +1445,7 @@ async def test_effect(hass, mqtt_mock):
assert state.attributes.get("effect") == "colorloop"
async def test_flash_short_and_long(hass, mqtt_mock):
async def test_flash_short_and_long(hass, mqtt_mock_entry_with_yaml_config):
"""Test for flash length being sent when included."""
assert await async_setup_component(
hass,
@ -1433,6 +1463,7 @@ async def test_flash_short_and_long(hass, mqtt_mock):
},
)
await hass.async_block_till_done()
mqtt_mock = await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("light.test")
assert state.state == STATE_UNKNOWN
@ -1476,7 +1507,7 @@ async def test_flash_short_and_long(hass, mqtt_mock):
assert state.state == STATE_OFF
async def test_transition(hass, mqtt_mock):
async def test_transition(hass, mqtt_mock_entry_with_yaml_config):
"""Test for transition time being sent when included."""
assert await async_setup_component(
hass,
@ -1492,6 +1523,7 @@ async def test_transition(hass, mqtt_mock):
},
)
await hass.async_block_till_done()
mqtt_mock = await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("light.test")
assert state.state == STATE_UNKNOWN
@ -1522,7 +1554,7 @@ async def test_transition(hass, mqtt_mock):
assert state.state == STATE_OFF
async def test_brightness_scale(hass, mqtt_mock):
async def test_brightness_scale(hass, mqtt_mock_entry_with_yaml_config):
"""Test for brightness scaling."""
assert await async_setup_component(
hass,
@ -1540,6 +1572,7 @@ async def test_brightness_scale(hass, mqtt_mock):
},
)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("light.test")
assert state.state == STATE_UNKNOWN
@ -1563,7 +1596,7 @@ async def test_brightness_scale(hass, mqtt_mock):
assert state.attributes.get("brightness") == 255
async def test_invalid_values(hass, mqtt_mock):
async def test_invalid_values(hass, mqtt_mock_entry_with_yaml_config):
"""Test that invalid color/brightness/white/etc. values are ignored."""
assert await async_setup_component(
hass,
@ -1584,6 +1617,7 @@ async def test_invalid_values(hass, mqtt_mock):
},
)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("light.test")
assert state.state == STATE_UNKNOWN
@ -1700,77 +1734,95 @@ async def test_invalid_values(hass, mqtt_mock):
assert state.attributes.get("color_temp") == 100
async def test_availability_when_connection_lost(hass, mqtt_mock):
async def test_availability_when_connection_lost(
hass, mqtt_mock_entry_with_yaml_config
):
"""Test availability after MQTT disconnection."""
await help_test_availability_when_connection_lost(
hass, mqtt_mock, light.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_with_yaml_config, light.DOMAIN, DEFAULT_CONFIG
)
async def test_availability_without_topic(hass, mqtt_mock):
async def test_availability_without_topic(hass, mqtt_mock_entry_with_yaml_config):
"""Test availability without defined availability topic."""
await help_test_availability_without_topic(
hass, mqtt_mock, light.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_with_yaml_config, light.DOMAIN, DEFAULT_CONFIG
)
async def test_default_availability_payload(hass, mqtt_mock):
async def test_default_availability_payload(hass, mqtt_mock_entry_with_yaml_config):
"""Test availability by default payload with defined topic."""
await help_test_default_availability_payload(
hass, mqtt_mock, light.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_with_yaml_config, light.DOMAIN, DEFAULT_CONFIG
)
async def test_custom_availability_payload(hass, mqtt_mock):
async def test_custom_availability_payload(hass, mqtt_mock_entry_with_yaml_config):
"""Test availability by custom payload with defined topic."""
await help_test_custom_availability_payload(
hass, mqtt_mock, light.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_with_yaml_config, light.DOMAIN, DEFAULT_CONFIG
)
async def test_setting_attribute_via_mqtt_json_message(hass, mqtt_mock):
async def test_setting_attribute_via_mqtt_json_message(
hass, mqtt_mock_entry_with_yaml_config
):
"""Test the setting of attribute via MQTT with JSON payload."""
await help_test_setting_attribute_via_mqtt_json_message(
hass, mqtt_mock, light.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_with_yaml_config, light.DOMAIN, DEFAULT_CONFIG
)
async def test_setting_blocked_attribute_via_mqtt_json_message(hass, mqtt_mock):
async def test_setting_blocked_attribute_via_mqtt_json_message(
hass, mqtt_mock_entry_no_yaml_config
):
"""Test the setting of attribute via MQTT with JSON payload."""
await help_test_setting_blocked_attribute_via_mqtt_json_message(
hass, mqtt_mock, light.DOMAIN, DEFAULT_CONFIG, MQTT_LIGHT_ATTRIBUTES_BLOCKED
hass,
mqtt_mock_entry_no_yaml_config,
light.DOMAIN,
DEFAULT_CONFIG,
MQTT_LIGHT_ATTRIBUTES_BLOCKED,
)
async def test_setting_attribute_with_template(hass, mqtt_mock):
async def test_setting_attribute_with_template(hass, mqtt_mock_entry_with_yaml_config):
"""Test the setting of attribute via MQTT with JSON payload."""
await help_test_setting_attribute_with_template(
hass, mqtt_mock, light.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_with_yaml_config, light.DOMAIN, DEFAULT_CONFIG
)
async def test_update_with_json_attrs_not_dict(hass, mqtt_mock, caplog):
async def test_update_with_json_attrs_not_dict(
hass, mqtt_mock_entry_with_yaml_config, caplog
):
"""Test attributes get extracted from a JSON result."""
await help_test_update_with_json_attrs_not_dict(
hass, mqtt_mock, caplog, light.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_with_yaml_config, caplog, light.DOMAIN, DEFAULT_CONFIG
)
async def test_update_with_json_attrs_bad_JSON(hass, mqtt_mock, caplog):
async def test_update_with_json_attrs_bad_JSON(
hass, mqtt_mock_entry_with_yaml_config, caplog
):
"""Test attributes get extracted from a JSON result."""
await help_test_update_with_json_attrs_bad_JSON(
hass, mqtt_mock, caplog, light.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_with_yaml_config, caplog, light.DOMAIN, DEFAULT_CONFIG
)
async def test_discovery_update_attr(hass, mqtt_mock, caplog):
async def test_discovery_update_attr(hass, mqtt_mock_entry_no_yaml_config, caplog):
"""Test update of discovered MQTTAttributes."""
await help_test_discovery_update_attr(
hass, mqtt_mock, caplog, light.DOMAIN, DEFAULT_CONFIG
hass,
mqtt_mock_entry_no_yaml_config,
caplog,
light.DOMAIN,
DEFAULT_CONFIG,
)
async def test_unique_id(hass, mqtt_mock):
async def test_unique_id(hass, mqtt_mock_entry_with_yaml_config):
"""Test unique id option only creates one light per unique_id."""
config = {
light.DOMAIN: [
@ -1792,16 +1844,24 @@ async def test_unique_id(hass, mqtt_mock):
},
]
}
await help_test_unique_id(hass, mqtt_mock, light.DOMAIN, config)
await help_test_unique_id(
hass, mqtt_mock_entry_with_yaml_config, light.DOMAIN, config
)
async def test_discovery_removal(hass, mqtt_mock, caplog):
async def test_discovery_removal(hass, mqtt_mock_entry_no_yaml_config, caplog):
"""Test removal of discovered mqtt_json lights."""
data = '{ "name": "test",' ' "schema": "json",' ' "command_topic": "test_topic" }'
await help_test_discovery_removal(hass, mqtt_mock, caplog, light.DOMAIN, data)
await help_test_discovery_removal(
hass,
mqtt_mock_entry_no_yaml_config,
caplog,
light.DOMAIN,
data,
)
async def test_discovery_update_light(hass, mqtt_mock, caplog):
async def test_discovery_update_light(hass, mqtt_mock_entry_no_yaml_config, caplog):
"""Test update of discovered light."""
config1 = {
"name": "Beer",
@ -1816,11 +1876,18 @@ async def test_discovery_update_light(hass, mqtt_mock, caplog):
"command_topic": "test_topic",
}
await help_test_discovery_update(
hass, mqtt_mock, caplog, light.DOMAIN, config1, config2
hass,
mqtt_mock_entry_no_yaml_config,
caplog,
light.DOMAIN,
config1,
config2,
)
async def test_discovery_update_unchanged_light(hass, mqtt_mock, caplog):
async def test_discovery_update_unchanged_light(
hass, mqtt_mock_entry_no_yaml_config, caplog
):
"""Test update of discovered light."""
data1 = (
'{ "name": "Beer",'
@ -1832,12 +1899,17 @@ async def test_discovery_update_unchanged_light(hass, mqtt_mock, caplog):
"homeassistant.components.mqtt.light.schema_json.MqttLightJson.discovery_update"
) as discovery_update:
await help_test_discovery_update_unchanged(
hass, mqtt_mock, caplog, light.DOMAIN, data1, discovery_update
hass,
mqtt_mock_entry_no_yaml_config,
caplog,
light.DOMAIN,
data1,
discovery_update,
)
@pytest.mark.no_fail_on_log_exception
async def test_discovery_broken(hass, mqtt_mock, caplog):
async def test_discovery_broken(hass, mqtt_mock_entry_no_yaml_config, caplog):
"""Test handling of bad discovery message."""
data1 = '{ "name": "Beer" }'
data2 = (
@ -1847,57 +1919,80 @@ async def test_discovery_broken(hass, mqtt_mock, caplog):
' "command_topic": "test_topic" }'
)
await help_test_discovery_broken(
hass, mqtt_mock, caplog, light.DOMAIN, data1, data2
hass,
mqtt_mock_entry_no_yaml_config,
caplog,
light.DOMAIN,
data1,
data2,
)
async def test_entity_device_info_with_connection(hass, mqtt_mock):
async def test_entity_device_info_with_connection(hass, mqtt_mock_entry_no_yaml_config):
"""Test MQTT light device registry integration."""
await help_test_entity_device_info_with_connection(
hass, mqtt_mock, light.DOMAIN, DEFAULT_CONFIG
hass,
mqtt_mock_entry_no_yaml_config,
light.DOMAIN,
DEFAULT_CONFIG,
)
async def test_entity_device_info_with_identifier(hass, mqtt_mock):
async def test_entity_device_info_with_identifier(hass, mqtt_mock_entry_no_yaml_config):
"""Test MQTT light device registry integration."""
await help_test_entity_device_info_with_identifier(
hass, mqtt_mock, light.DOMAIN, DEFAULT_CONFIG
hass,
mqtt_mock_entry_no_yaml_config,
light.DOMAIN,
DEFAULT_CONFIG,
)
async def test_entity_device_info_update(hass, mqtt_mock):
async def test_entity_device_info_update(hass, mqtt_mock_entry_no_yaml_config):
"""Test device registry update."""
await help_test_entity_device_info_update(
hass, mqtt_mock, light.DOMAIN, DEFAULT_CONFIG
hass,
mqtt_mock_entry_no_yaml_config,
light.DOMAIN,
DEFAULT_CONFIG,
)
async def test_entity_device_info_remove(hass, mqtt_mock):
async def test_entity_device_info_remove(hass, mqtt_mock_entry_no_yaml_config):
"""Test device registry remove."""
await help_test_entity_device_info_remove(
hass, mqtt_mock, light.DOMAIN, DEFAULT_CONFIG
hass,
mqtt_mock_entry_no_yaml_config,
light.DOMAIN,
DEFAULT_CONFIG,
)
async def test_entity_id_update_subscriptions(hass, mqtt_mock):
async def test_entity_id_update_subscriptions(hass, mqtt_mock_entry_with_yaml_config):
"""Test MQTT subscriptions are managed when entity_id is updated."""
await help_test_entity_id_update_subscriptions(
hass, mqtt_mock, light.DOMAIN, DEFAULT_CONFIG
hass,
mqtt_mock_entry_with_yaml_config,
light.DOMAIN,
DEFAULT_CONFIG,
)
async def test_entity_id_update_discovery_update(hass, mqtt_mock):
async def test_entity_id_update_discovery_update(hass, mqtt_mock_entry_no_yaml_config):
"""Test MQTT discovery update when entity_id is updated."""
await help_test_entity_id_update_discovery_update(
hass, mqtt_mock, light.DOMAIN, DEFAULT_CONFIG
hass,
mqtt_mock_entry_no_yaml_config,
light.DOMAIN,
DEFAULT_CONFIG,
)
async def test_entity_debug_info_message(hass, mqtt_mock):
async def test_entity_debug_info_message(hass, mqtt_mock_entry_no_yaml_config):
"""Test MQTT debug info."""
await help_test_entity_debug_info_message(
hass,
mqtt_mock,
mqtt_mock_entry_no_yaml_config,
light.DOMAIN,
DEFAULT_CONFIG,
light.SERVICE_TURN_ON,
@ -1906,7 +2001,7 @@ async def test_entity_debug_info_message(hass, mqtt_mock):
)
async def test_max_mireds(hass, mqtt_mock):
async def test_max_mireds(hass, mqtt_mock_entry_with_yaml_config):
"""Test setting min_mireds and max_mireds."""
config = {
light.DOMAIN: {
@ -1921,6 +2016,7 @@ async def test_max_mireds(hass, mqtt_mock):
assert await async_setup_component(hass, light.DOMAIN, config)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("light.test")
assert state.attributes.get("min_mireds") == 153
@ -1952,7 +2048,7 @@ async def test_max_mireds(hass, mqtt_mock):
)
async def test_publishing_with_custom_encoding(
hass,
mqtt_mock,
mqtt_mock_entry_with_yaml_config,
caplog,
service,
topic,
@ -1972,7 +2068,7 @@ async def test_publishing_with_custom_encoding(
await help_test_publishing_with_custom_encoding(
hass,
mqtt_mock,
mqtt_mock_entry_with_yaml_config,
caplog,
domain,
config,
@ -1986,11 +2082,13 @@ async def test_publishing_with_custom_encoding(
)
async def test_reloadable(hass, mqtt_mock, caplog, tmp_path):
async def test_reloadable(hass, mqtt_mock_entry_with_yaml_config, caplog, tmp_path):
"""Test reloading the MQTT platform."""
domain = light.DOMAIN
config = DEFAULT_CONFIG[domain]
await help_test_reloadable(hass, mqtt_mock, caplog, tmp_path, domain, config)
await help_test_reloadable(
hass, mqtt_mock_entry_with_yaml_config, caplog, tmp_path, domain, config
)
async def test_reloadable_late(hass, mqtt_client_mock, caplog, tmp_path):
@ -2013,7 +2111,14 @@ async def test_reloadable_late(hass, mqtt_client_mock, caplog, tmp_path):
],
)
async def test_encoding_subscribable_topics(
hass, mqtt_mock, caplog, topic, value, attribute, attribute_value, init_payload
hass,
mqtt_mock_entry_with_yaml_config,
caplog,
topic,
value,
attribute,
attribute_value,
init_payload,
):
"""Test handling of incoming encoded payload."""
config = copy.deepcopy(DEFAULT_CONFIG[light.DOMAIN])
@ -2028,7 +2133,7 @@ async def test_encoding_subscribable_topics(
]
await help_test_encoding_subscribable_topics(
hass,
mqtt_mock,
mqtt_mock_entry_with_yaml_config,
caplog,
light.DOMAIN,
config,

View File

@ -90,69 +90,53 @@ DEFAULT_CONFIG = {
}
async def test_setup_fails(hass, mqtt_mock):
@pytest.mark.parametrize(
"test_config",
[
({"platform": "mqtt", "schema": "template", "name": "test"},),
(
{
"platform": "mqtt",
"schema": "template",
"name": "test",
"command_topic": "test_topic",
},
),
(
{
"platform": "mqtt",
"schema": "template",
"name": "test",
"command_topic": "test_topic",
"command_on_template": "on",
},
),
(
{
"platform": "mqtt",
"schema": "template",
"name": "test",
"command_topic": "test_topic",
"command_off_template": "off",
},
),
],
)
async def test_setup_fails(hass, mqtt_mock_entry_no_yaml_config, test_config):
"""Test that setup fails with missing required configuration items."""
with assert_setup_component(0, light.DOMAIN):
with assert_setup_component(0, light.DOMAIN) as setup_config:
assert await async_setup_component(
hass,
light.DOMAIN,
{light.DOMAIN: {"platform": "mqtt", "schema": "template", "name": "test"}},
)
await hass.async_block_till_done()
assert hass.states.get("light.test") is None
with assert_setup_component(0, light.DOMAIN):
assert await async_setup_component(
hass,
light.DOMAIN,
{
light.DOMAIN: {
"platform": "mqtt",
"schema": "template",
"name": "test",
"command_topic": "test_topic",
}
},
)
await hass.async_block_till_done()
assert hass.states.get("light.test") is None
with assert_setup_component(0, light.DOMAIN):
assert await async_setup_component(
hass,
light.DOMAIN,
{
light.DOMAIN: {
"platform": "mqtt",
"schema": "template",
"name": "test",
"command_topic": "test_topic",
"command_on_template": "on",
}
},
)
await hass.async_block_till_done()
assert hass.states.get("light.test") is None
with assert_setup_component(0, light.DOMAIN):
assert await async_setup_component(
hass,
light.DOMAIN,
{
light.DOMAIN: {
"platform": "mqtt",
"schema": "template",
"name": "test",
"command_topic": "test_topic",
"command_off_template": "off",
}
},
{light.DOMAIN: test_config},
)
await hass.async_block_till_done()
await mqtt_mock_entry_no_yaml_config()
assert not setup_config[light.DOMAIN]
assert hass.states.get("light.test") is None
async def test_rgb_light(hass, mqtt_mock):
async def test_rgb_light(hass, mqtt_mock_entry_with_yaml_config):
"""Test RGB light flags brightness support."""
assert await async_setup_component(
hass,
@ -172,6 +156,7 @@ async def test_rgb_light(hass, mqtt_mock):
},
)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("light.test")
assert state.state == STATE_UNKNOWN
@ -184,7 +169,7 @@ async def test_rgb_light(hass, mqtt_mock):
assert state.attributes.get(ATTR_SUPPORTED_FEATURES) == expected_features
async def test_state_change_via_topic(hass, mqtt_mock):
async def test_state_change_via_topic(hass, mqtt_mock_entry_with_yaml_config):
"""Test state change via topic."""
with assert_setup_component(1, light.DOMAIN):
assert await async_setup_component(
@ -210,6 +195,7 @@ async def test_state_change_via_topic(hass, mqtt_mock):
},
)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("light.test")
assert state.state == STATE_UNKNOWN
@ -240,7 +226,7 @@ async def test_state_change_via_topic(hass, mqtt_mock):
async def test_state_brightness_color_effect_temp_white_change_via_topic(
hass, mqtt_mock
hass, mqtt_mock_entry_with_yaml_config
):
"""Test state, bri, color, effect, color temp, white val change."""
with assert_setup_component(1, light.DOMAIN):
@ -276,6 +262,7 @@ async def test_state_brightness_color_effect_temp_white_change_via_topic(
},
)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("light.test")
assert state.state == STATE_UNKNOWN
@ -340,7 +327,9 @@ async def test_state_brightness_color_effect_temp_white_change_via_topic(
assert light_state.attributes.get("effect") == "rainbow"
async def test_sending_mqtt_commands_and_optimistic(hass, mqtt_mock):
async def test_sending_mqtt_commands_and_optimistic(
hass, mqtt_mock_entry_with_yaml_config
):
"""Test the sending of command in optimistic mode."""
fake_state = ha.State(
"light.test",
@ -391,6 +380,7 @@ async def test_sending_mqtt_commands_and_optimistic(hass, mqtt_mock):
},
)
await hass.async_block_till_done()
mqtt_mock = await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("light.test")
assert state.state == STATE_ON
@ -495,7 +485,7 @@ async def test_sending_mqtt_commands_and_optimistic(hass, mqtt_mock):
async def test_sending_mqtt_commands_non_optimistic_brightness_template(
hass, mqtt_mock
hass, mqtt_mock_entry_with_yaml_config
):
"""Test the sending of command in optimistic mode."""
with assert_setup_component(1, light.DOMAIN):
@ -532,6 +522,7 @@ async def test_sending_mqtt_commands_non_optimistic_brightness_template(
},
)
await hass.async_block_till_done()
mqtt_mock = await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("light.test")
assert state.state == STATE_UNKNOWN
@ -626,7 +617,7 @@ async def test_sending_mqtt_commands_non_optimistic_brightness_template(
state = hass.states.get("light.test")
async def test_effect(hass, mqtt_mock):
async def test_effect(hass, mqtt_mock_entry_with_yaml_config):
"""Test effect sent over MQTT in optimistic mode."""
with assert_setup_component(1, light.DOMAIN):
assert await async_setup_component(
@ -646,6 +637,7 @@ async def test_effect(hass, mqtt_mock):
},
)
await hass.async_block_till_done()
mqtt_mock = await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("light.test")
assert state.state == STATE_UNKNOWN
@ -678,7 +670,7 @@ async def test_effect(hass, mqtt_mock):
assert state.attributes.get("effect") == "colorloop"
async def test_flash(hass, mqtt_mock):
async def test_flash(hass, mqtt_mock_entry_with_yaml_config):
"""Test flash sent over MQTT in optimistic mode."""
with assert_setup_component(1, light.DOMAIN):
assert await async_setup_component(
@ -697,6 +689,7 @@ async def test_flash(hass, mqtt_mock):
},
)
await hass.async_block_till_done()
mqtt_mock = await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("light.test")
assert state.state == STATE_UNKNOWN
@ -726,7 +719,7 @@ async def test_flash(hass, mqtt_mock):
assert state.state == STATE_ON
async def test_transition(hass, mqtt_mock):
async def test_transition(hass, mqtt_mock_entry_with_yaml_config):
"""Test for transition time being sent when included."""
with assert_setup_component(1, light.DOMAIN):
assert await async_setup_component(
@ -745,6 +738,7 @@ async def test_transition(hass, mqtt_mock):
},
)
await hass.async_block_till_done()
mqtt_mock = await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("light.test")
assert state.state == STATE_UNKNOWN
@ -767,7 +761,7 @@ async def test_transition(hass, mqtt_mock):
assert state.state == STATE_OFF
async def test_invalid_values(hass, mqtt_mock):
async def test_invalid_values(hass, mqtt_mock_entry_with_yaml_config):
"""Test that invalid values are ignored."""
with assert_setup_component(1, light.DOMAIN):
assert await async_setup_component(
@ -801,6 +795,7 @@ async def test_invalid_values(hass, mqtt_mock):
},
)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("light.test")
assert state.state == STATE_UNKNOWN
@ -867,77 +862,91 @@ async def test_invalid_values(hass, mqtt_mock):
assert state.attributes.get("effect") == "rainbow"
async def test_availability_when_connection_lost(hass, mqtt_mock):
async def test_availability_when_connection_lost(
hass, mqtt_mock_entry_with_yaml_config
):
"""Test availability after MQTT disconnection."""
await help_test_availability_when_connection_lost(
hass, mqtt_mock, light.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_with_yaml_config, light.DOMAIN, DEFAULT_CONFIG
)
async def test_availability_without_topic(hass, mqtt_mock):
async def test_availability_without_topic(hass, mqtt_mock_entry_with_yaml_config):
"""Test availability without defined availability topic."""
await help_test_availability_without_topic(
hass, mqtt_mock, light.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_with_yaml_config, light.DOMAIN, DEFAULT_CONFIG
)
async def test_default_availability_payload(hass, mqtt_mock):
async def test_default_availability_payload(hass, mqtt_mock_entry_with_yaml_config):
"""Test availability by default payload with defined topic."""
await help_test_default_availability_payload(
hass, mqtt_mock, light.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_with_yaml_config, light.DOMAIN, DEFAULT_CONFIG
)
async def test_custom_availability_payload(hass, mqtt_mock):
async def test_custom_availability_payload(hass, mqtt_mock_entry_with_yaml_config):
"""Test availability by custom payload with defined topic."""
await help_test_custom_availability_payload(
hass, mqtt_mock, light.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_with_yaml_config, light.DOMAIN, DEFAULT_CONFIG
)
async def test_setting_attribute_via_mqtt_json_message(hass, mqtt_mock):
async def test_setting_attribute_via_mqtt_json_message(
hass, mqtt_mock_entry_with_yaml_config
):
"""Test the setting of attribute via MQTT with JSON payload."""
await help_test_setting_attribute_via_mqtt_json_message(
hass, mqtt_mock, light.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_with_yaml_config, light.DOMAIN, DEFAULT_CONFIG
)
async def test_setting_blocked_attribute_via_mqtt_json_message(hass, mqtt_mock):
async def test_setting_blocked_attribute_via_mqtt_json_message(
hass, mqtt_mock_entry_no_yaml_config
):
"""Test the setting of attribute via MQTT with JSON payload."""
await help_test_setting_blocked_attribute_via_mqtt_json_message(
hass, mqtt_mock, light.DOMAIN, DEFAULT_CONFIG, MQTT_LIGHT_ATTRIBUTES_BLOCKED
hass,
mqtt_mock_entry_no_yaml_config,
light.DOMAIN,
DEFAULT_CONFIG,
MQTT_LIGHT_ATTRIBUTES_BLOCKED,
)
async def test_setting_attribute_with_template(hass, mqtt_mock):
async def test_setting_attribute_with_template(hass, mqtt_mock_entry_with_yaml_config):
"""Test the setting of attribute via MQTT with JSON payload."""
await help_test_setting_attribute_with_template(
hass, mqtt_mock, light.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_with_yaml_config, light.DOMAIN, DEFAULT_CONFIG
)
async def test_update_with_json_attrs_not_dict(hass, mqtt_mock, caplog):
async def test_update_with_json_attrs_not_dict(
hass, mqtt_mock_entry_with_yaml_config, caplog
):
"""Test attributes get extracted from a JSON result."""
await help_test_update_with_json_attrs_not_dict(
hass, mqtt_mock, caplog, light.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_with_yaml_config, caplog, light.DOMAIN, DEFAULT_CONFIG
)
async def test_update_with_json_attrs_bad_JSON(hass, mqtt_mock, caplog):
async def test_update_with_json_attrs_bad_JSON(
hass, mqtt_mock_entry_with_yaml_config, caplog
):
"""Test attributes get extracted from a JSON result."""
await help_test_update_with_json_attrs_bad_JSON(
hass, mqtt_mock, caplog, light.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_with_yaml_config, caplog, light.DOMAIN, DEFAULT_CONFIG
)
async def test_discovery_update_attr(hass, mqtt_mock, caplog):
async def test_discovery_update_attr(hass, mqtt_mock_entry_no_yaml_config, caplog):
"""Test update of discovered MQTTAttributes."""
await help_test_discovery_update_attr(
hass, mqtt_mock, caplog, light.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_no_yaml_config, caplog, light.DOMAIN, DEFAULT_CONFIG
)
async def test_unique_id(hass, mqtt_mock):
async def test_unique_id(hass, mqtt_mock_entry_with_yaml_config):
"""Test unique id option only creates one light per unique_id."""
config = {
light.DOMAIN: [
@ -961,10 +970,12 @@ async def test_unique_id(hass, mqtt_mock):
},
]
}
await help_test_unique_id(hass, mqtt_mock, light.DOMAIN, config)
await help_test_unique_id(
hass, mqtt_mock_entry_with_yaml_config, light.DOMAIN, config
)
async def test_discovery_removal(hass, mqtt_mock, caplog):
async def test_discovery_removal(hass, mqtt_mock_entry_no_yaml_config, caplog):
"""Test removal of discovered mqtt_json lights."""
data = (
'{ "name": "test",'
@ -973,10 +984,12 @@ async def test_discovery_removal(hass, mqtt_mock, caplog):
' "command_on_template": "on",'
' "command_off_template": "off"}'
)
await help_test_discovery_removal(hass, mqtt_mock, caplog, light.DOMAIN, data)
await help_test_discovery_removal(
hass, mqtt_mock_entry_no_yaml_config, caplog, light.DOMAIN, data
)
async def test_discovery_update_light(hass, mqtt_mock, caplog):
async def test_discovery_update_light(hass, mqtt_mock_entry_no_yaml_config, caplog):
"""Test update of discovered light."""
config1 = {
"name": "Beer",
@ -995,11 +1008,13 @@ async def test_discovery_update_light(hass, mqtt_mock, caplog):
"command_off_template": "off",
}
await help_test_discovery_update(
hass, mqtt_mock, caplog, light.DOMAIN, config1, config2
hass, mqtt_mock_entry_no_yaml_config, caplog, light.DOMAIN, config1, config2
)
async def test_discovery_update_unchanged_light(hass, mqtt_mock, caplog):
async def test_discovery_update_unchanged_light(
hass, mqtt_mock_entry_no_yaml_config, caplog
):
"""Test update of discovered light."""
data1 = (
'{ "name": "Beer",'
@ -1013,12 +1028,17 @@ async def test_discovery_update_unchanged_light(hass, mqtt_mock, caplog):
"homeassistant.components.mqtt.light.schema_template.MqttLightTemplate.discovery_update"
) as discovery_update:
await help_test_discovery_update_unchanged(
hass, mqtt_mock, caplog, light.DOMAIN, data1, discovery_update
hass,
mqtt_mock_entry_no_yaml_config,
caplog,
light.DOMAIN,
data1,
discovery_update,
)
@pytest.mark.no_fail_on_log_exception
async def test_discovery_broken(hass, mqtt_mock, caplog):
async def test_discovery_broken(hass, mqtt_mock_entry_no_yaml_config, caplog):
"""Test handling of bad discovery message."""
data1 = '{ "name": "Beer" }'
data2 = (
@ -1030,53 +1050,53 @@ async def test_discovery_broken(hass, mqtt_mock, caplog):
' "command_off_template": "off"}'
)
await help_test_discovery_broken(
hass, mqtt_mock, caplog, light.DOMAIN, data1, data2
hass, mqtt_mock_entry_no_yaml_config, caplog, light.DOMAIN, data1, data2
)
async def test_entity_device_info_with_connection(hass, mqtt_mock):
async def test_entity_device_info_with_connection(hass, mqtt_mock_entry_no_yaml_config):
"""Test MQTT light device registry integration."""
await help_test_entity_device_info_with_connection(
hass, mqtt_mock, light.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_no_yaml_config, light.DOMAIN, DEFAULT_CONFIG
)
async def test_entity_device_info_with_identifier(hass, mqtt_mock):
async def test_entity_device_info_with_identifier(hass, mqtt_mock_entry_no_yaml_config):
"""Test MQTT light device registry integration."""
await help_test_entity_device_info_with_identifier(
hass, mqtt_mock, light.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_no_yaml_config, light.DOMAIN, DEFAULT_CONFIG
)
async def test_entity_device_info_update(hass, mqtt_mock):
async def test_entity_device_info_update(hass, mqtt_mock_entry_no_yaml_config):
"""Test device registry update."""
await help_test_entity_device_info_update(
hass, mqtt_mock, light.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_no_yaml_config, light.DOMAIN, DEFAULT_CONFIG
)
async def test_entity_device_info_remove(hass, mqtt_mock):
async def test_entity_device_info_remove(hass, mqtt_mock_entry_no_yaml_config):
"""Test device registry remove."""
await help_test_entity_device_info_remove(
hass, mqtt_mock, light.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_no_yaml_config, light.DOMAIN, DEFAULT_CONFIG
)
async def test_entity_id_update_subscriptions(hass, mqtt_mock):
async def test_entity_id_update_subscriptions(hass, mqtt_mock_entry_with_yaml_config):
"""Test MQTT subscriptions are managed when entity_id is updated."""
await help_test_entity_id_update_subscriptions(
hass, mqtt_mock, light.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_with_yaml_config, light.DOMAIN, DEFAULT_CONFIG
)
async def test_entity_id_update_discovery_update(hass, mqtt_mock):
async def test_entity_id_update_discovery_update(hass, mqtt_mock_entry_no_yaml_config):
"""Test MQTT discovery update when entity_id is updated."""
await help_test_entity_id_update_discovery_update(
hass, mqtt_mock, light.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_no_yaml_config, light.DOMAIN, DEFAULT_CONFIG
)
async def test_entity_debug_info_message(hass, mqtt_mock):
async def test_entity_debug_info_message(hass, mqtt_mock_entry_no_yaml_config):
"""Test MQTT debug info."""
config = {
light.DOMAIN: {
@ -1090,11 +1110,15 @@ async def test_entity_debug_info_message(hass, mqtt_mock):
}
}
await help_test_entity_debug_info_message(
hass, mqtt_mock, light.DOMAIN, config, light.SERVICE_TURN_ON
hass,
mqtt_mock_entry_no_yaml_config,
light.DOMAIN,
config,
light.SERVICE_TURN_ON,
)
async def test_max_mireds(hass, mqtt_mock):
async def test_max_mireds(hass, mqtt_mock_entry_with_yaml_config):
"""Test setting min_mireds and max_mireds."""
config = {
light.DOMAIN: {
@ -1111,6 +1135,7 @@ async def test_max_mireds(hass, mqtt_mock):
assert await async_setup_component(hass, light.DOMAIN, config)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("light.test")
assert state.attributes.get("min_mireds") == 153
@ -1142,7 +1167,7 @@ async def test_max_mireds(hass, mqtt_mock):
)
async def test_publishing_with_custom_encoding(
hass,
mqtt_mock,
mqtt_mock_entry_with_yaml_config,
caplog,
service,
topic,
@ -1162,7 +1187,7 @@ async def test_publishing_with_custom_encoding(
await help_test_publishing_with_custom_encoding(
hass,
mqtt_mock,
mqtt_mock_entry_with_yaml_config,
caplog,
domain,
config,
@ -1176,11 +1201,13 @@ async def test_publishing_with_custom_encoding(
)
async def test_reloadable(hass, mqtt_mock, caplog, tmp_path):
async def test_reloadable(hass, mqtt_mock_entry_with_yaml_config, caplog, tmp_path):
"""Test reloading the MQTT platform."""
domain = light.DOMAIN
config = DEFAULT_CONFIG[domain]
await help_test_reloadable(hass, mqtt_mock, caplog, tmp_path, domain, config)
await help_test_reloadable(
hass, mqtt_mock_entry_with_yaml_config, caplog, tmp_path, domain, config
)
async def test_reloadable_late(hass, mqtt_client_mock, caplog, tmp_path):
@ -1197,14 +1224,21 @@ async def test_reloadable_late(hass, mqtt_client_mock, caplog, tmp_path):
],
)
async def test_encoding_subscribable_topics(
hass, mqtt_mock, caplog, topic, value, attribute, attribute_value, init_payload
hass,
mqtt_mock_entry_with_yaml_config,
caplog,
topic,
value,
attribute,
attribute_value,
init_payload,
):
"""Test handling of incoming encoded payload."""
config = copy.deepcopy(DEFAULT_CONFIG[light.DOMAIN])
config["state_template"] = "{{ value }}"
await help_test_encoding_subscribable_topics(
hass,
mqtt_mock,
mqtt_mock_entry_with_yaml_config,
caplog,
light.DOMAIN,
config,

View File

@ -58,7 +58,7 @@ DEFAULT_CONFIG = {
}
async def test_controlling_state_via_topic(hass, mqtt_mock):
async def test_controlling_state_via_topic(hass, mqtt_mock_entry_with_yaml_config):
"""Test the controlling state via topic."""
assert await async_setup_component(
hass,
@ -77,6 +77,7 @@ async def test_controlling_state_via_topic(hass, mqtt_mock):
},
)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("lock.test")
assert state.state is STATE_UNLOCKED
@ -94,7 +95,9 @@ async def test_controlling_state_via_topic(hass, mqtt_mock):
assert state.state is STATE_UNLOCKED
async def test_controlling_non_default_state_via_topic(hass, mqtt_mock):
async def test_controlling_non_default_state_via_topic(
hass, mqtt_mock_entry_with_yaml_config
):
"""Test the controlling state via topic."""
assert await async_setup_component(
hass,
@ -113,6 +116,7 @@ async def test_controlling_non_default_state_via_topic(hass, mqtt_mock):
},
)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("lock.test")
assert state.state is STATE_UNLOCKED
@ -129,7 +133,9 @@ async def test_controlling_non_default_state_via_topic(hass, mqtt_mock):
assert state.state is STATE_UNLOCKED
async def test_controlling_state_via_topic_and_json_message(hass, mqtt_mock):
async def test_controlling_state_via_topic_and_json_message(
hass, mqtt_mock_entry_with_yaml_config
):
"""Test the controlling state via topic and JSON message."""
assert await async_setup_component(
hass,
@ -149,6 +155,7 @@ async def test_controlling_state_via_topic_and_json_message(hass, mqtt_mock):
},
)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("lock.test")
assert state.state is STATE_UNLOCKED
@ -165,7 +172,7 @@ async def test_controlling_state_via_topic_and_json_message(hass, mqtt_mock):
async def test_controlling_non_default_state_via_topic_and_json_message(
hass, mqtt_mock
hass, mqtt_mock_entry_with_yaml_config
):
"""Test the controlling state via topic and JSON message."""
assert await async_setup_component(
@ -186,6 +193,7 @@ async def test_controlling_non_default_state_via_topic_and_json_message(
},
)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("lock.test")
assert state.state is STATE_UNLOCKED
@ -201,7 +209,9 @@ async def test_controlling_non_default_state_via_topic_and_json_message(
assert state.state is STATE_UNLOCKED
async def test_sending_mqtt_commands_and_optimistic(hass, mqtt_mock):
async def test_sending_mqtt_commands_and_optimistic(
hass, mqtt_mock_entry_with_yaml_config
):
"""Test optimistic mode without state topic."""
assert await async_setup_component(
hass,
@ -219,6 +229,7 @@ async def test_sending_mqtt_commands_and_optimistic(hass, mqtt_mock):
},
)
await hass.async_block_till_done()
mqtt_mock = await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("lock.test")
assert state.state is STATE_UNLOCKED
@ -245,7 +256,9 @@ async def test_sending_mqtt_commands_and_optimistic(hass, mqtt_mock):
assert state.attributes.get(ATTR_ASSUMED_STATE)
async def test_sending_mqtt_commands_and_explicit_optimistic(hass, mqtt_mock):
async def test_sending_mqtt_commands_and_explicit_optimistic(
hass, mqtt_mock_entry_with_yaml_config
):
"""Test optimistic mode without state topic."""
assert await async_setup_component(
hass,
@ -265,6 +278,7 @@ async def test_sending_mqtt_commands_and_explicit_optimistic(hass, mqtt_mock):
},
)
await hass.async_block_till_done()
mqtt_mock = await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("lock.test")
assert state.state is STATE_UNLOCKED
@ -291,7 +305,9 @@ async def test_sending_mqtt_commands_and_explicit_optimistic(hass, mqtt_mock):
assert state.attributes.get(ATTR_ASSUMED_STATE)
async def test_sending_mqtt_commands_support_open_and_optimistic(hass, mqtt_mock):
async def test_sending_mqtt_commands_support_open_and_optimistic(
hass, mqtt_mock_entry_with_yaml_config
):
"""Test open function of the lock without state topic."""
assert await async_setup_component(
hass,
@ -310,6 +326,7 @@ async def test_sending_mqtt_commands_support_open_and_optimistic(hass, mqtt_mock
},
)
await hass.async_block_till_done()
mqtt_mock = await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("lock.test")
assert state.state is STATE_UNLOCKED
@ -348,7 +365,7 @@ async def test_sending_mqtt_commands_support_open_and_optimistic(hass, mqtt_mock
async def test_sending_mqtt_commands_support_open_and_explicit_optimistic(
hass, mqtt_mock
hass, mqtt_mock_entry_with_yaml_config
):
"""Test open function of the lock without state topic."""
assert await async_setup_component(
@ -370,6 +387,7 @@ async def test_sending_mqtt_commands_support_open_and_explicit_optimistic(
},
)
await hass.async_block_till_done()
mqtt_mock = await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("lock.test")
assert state.state is STATE_UNLOCKED
@ -407,77 +425,91 @@ async def test_sending_mqtt_commands_support_open_and_explicit_optimistic(
assert state.attributes.get(ATTR_ASSUMED_STATE)
async def test_availability_when_connection_lost(hass, mqtt_mock):
async def test_availability_when_connection_lost(
hass, mqtt_mock_entry_with_yaml_config
):
"""Test availability after MQTT disconnection."""
await help_test_availability_when_connection_lost(
hass, mqtt_mock, LOCK_DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_with_yaml_config, LOCK_DOMAIN, DEFAULT_CONFIG
)
async def test_availability_without_topic(hass, mqtt_mock):
async def test_availability_without_topic(hass, mqtt_mock_entry_with_yaml_config):
"""Test availability without defined availability topic."""
await help_test_availability_without_topic(
hass, mqtt_mock, LOCK_DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_with_yaml_config, LOCK_DOMAIN, DEFAULT_CONFIG
)
async def test_default_availability_payload(hass, mqtt_mock):
async def test_default_availability_payload(hass, mqtt_mock_entry_with_yaml_config):
"""Test availability by default payload with defined topic."""
await help_test_default_availability_payload(
hass, mqtt_mock, LOCK_DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_with_yaml_config, LOCK_DOMAIN, DEFAULT_CONFIG
)
async def test_custom_availability_payload(hass, mqtt_mock):
async def test_custom_availability_payload(hass, mqtt_mock_entry_with_yaml_config):
"""Test availability by custom payload with defined topic."""
await help_test_custom_availability_payload(
hass, mqtt_mock, LOCK_DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_with_yaml_config, LOCK_DOMAIN, DEFAULT_CONFIG
)
async def test_setting_attribute_via_mqtt_json_message(hass, mqtt_mock):
async def test_setting_attribute_via_mqtt_json_message(
hass, mqtt_mock_entry_with_yaml_config
):
"""Test the setting of attribute via MQTT with JSON payload."""
await help_test_setting_attribute_via_mqtt_json_message(
hass, mqtt_mock, LOCK_DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_with_yaml_config, LOCK_DOMAIN, DEFAULT_CONFIG
)
async def test_setting_blocked_attribute_via_mqtt_json_message(hass, mqtt_mock):
async def test_setting_blocked_attribute_via_mqtt_json_message(
hass, mqtt_mock_entry_no_yaml_config
):
"""Test the setting of attribute via MQTT with JSON payload."""
await help_test_setting_blocked_attribute_via_mqtt_json_message(
hass, mqtt_mock, LOCK_DOMAIN, DEFAULT_CONFIG, MQTT_LOCK_ATTRIBUTES_BLOCKED
hass,
mqtt_mock_entry_no_yaml_config,
LOCK_DOMAIN,
DEFAULT_CONFIG,
MQTT_LOCK_ATTRIBUTES_BLOCKED,
)
async def test_setting_attribute_with_template(hass, mqtt_mock):
async def test_setting_attribute_with_template(hass, mqtt_mock_entry_with_yaml_config):
"""Test the setting of attribute via MQTT with JSON payload."""
await help_test_setting_attribute_with_template(
hass, mqtt_mock, LOCK_DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_with_yaml_config, LOCK_DOMAIN, DEFAULT_CONFIG
)
async def test_update_with_json_attrs_not_dict(hass, mqtt_mock, caplog):
async def test_update_with_json_attrs_not_dict(
hass, mqtt_mock_entry_with_yaml_config, caplog
):
"""Test attributes get extracted from a JSON result."""
await help_test_update_with_json_attrs_not_dict(
hass, mqtt_mock, caplog, LOCK_DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_with_yaml_config, caplog, LOCK_DOMAIN, DEFAULT_CONFIG
)
async def test_update_with_json_attrs_bad_json(hass, mqtt_mock, caplog):
async def test_update_with_json_attrs_bad_json(
hass, mqtt_mock_entry_with_yaml_config, caplog
):
"""Test attributes get extracted from a JSON result."""
await help_test_update_with_json_attrs_bad_JSON(
hass, mqtt_mock, caplog, LOCK_DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_with_yaml_config, caplog, LOCK_DOMAIN, DEFAULT_CONFIG
)
async def test_discovery_update_attr(hass, mqtt_mock, caplog):
async def test_discovery_update_attr(hass, mqtt_mock_entry_no_yaml_config, caplog):
"""Test update of discovered MQTTAttributes."""
await help_test_discovery_update_attr(
hass, mqtt_mock, caplog, LOCK_DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_no_yaml_config, caplog, LOCK_DOMAIN, DEFAULT_CONFIG
)
async def test_unique_id(hass, mqtt_mock):
async def test_unique_id(hass, mqtt_mock_entry_with_yaml_config):
"""Test unique id option only creates one lock per unique_id."""
config = {
LOCK_DOMAIN: [
@ -497,16 +529,20 @@ async def test_unique_id(hass, mqtt_mock):
},
]
}
await help_test_unique_id(hass, mqtt_mock, LOCK_DOMAIN, config)
await help_test_unique_id(
hass, mqtt_mock_entry_with_yaml_config, LOCK_DOMAIN, config
)
async def test_discovery_removal_lock(hass, mqtt_mock, caplog):
async def test_discovery_removal_lock(hass, mqtt_mock_entry_no_yaml_config, caplog):
"""Test removal of discovered lock."""
data = '{ "name": "test",' ' "command_topic": "test_topic" }'
await help_test_discovery_removal(hass, mqtt_mock, caplog, LOCK_DOMAIN, data)
await help_test_discovery_removal(
hass, mqtt_mock_entry_no_yaml_config, caplog, LOCK_DOMAIN, data
)
async def test_discovery_update_lock(hass, mqtt_mock, caplog):
async def test_discovery_update_lock(hass, mqtt_mock_entry_no_yaml_config, caplog):
"""Test update of discovered lock."""
config1 = {
"name": "Beer",
@ -521,11 +557,13 @@ async def test_discovery_update_lock(hass, mqtt_mock, caplog):
"availability_topic": "availability_topic2",
}
await help_test_discovery_update(
hass, mqtt_mock, caplog, LOCK_DOMAIN, config1, config2
hass, mqtt_mock_entry_no_yaml_config, caplog, LOCK_DOMAIN, config1, config2
)
async def test_discovery_update_unchanged_lock(hass, mqtt_mock, caplog):
async def test_discovery_update_unchanged_lock(
hass, mqtt_mock_entry_no_yaml_config, caplog
):
"""Test update of discovered lock."""
data1 = (
'{ "name": "Beer",'
@ -536,65 +574,72 @@ async def test_discovery_update_unchanged_lock(hass, mqtt_mock, caplog):
"homeassistant.components.mqtt.lock.MqttLock.discovery_update"
) as discovery_update:
await help_test_discovery_update_unchanged(
hass, mqtt_mock, caplog, LOCK_DOMAIN, data1, discovery_update
hass,
mqtt_mock_entry_no_yaml_config,
caplog,
LOCK_DOMAIN,
data1,
discovery_update,
)
@pytest.mark.no_fail_on_log_exception
async def test_discovery_broken(hass, mqtt_mock, caplog):
async def test_discovery_broken(hass, mqtt_mock_entry_no_yaml_config, caplog):
"""Test handling of bad discovery message."""
data1 = '{ "name": "Beer" }'
data2 = '{ "name": "Milk",' ' "command_topic": "test_topic" }'
await help_test_discovery_broken(hass, mqtt_mock, caplog, LOCK_DOMAIN, data1, data2)
await help_test_discovery_broken(
hass, mqtt_mock_entry_no_yaml_config, caplog, LOCK_DOMAIN, data1, data2
)
async def test_entity_device_info_with_connection(hass, mqtt_mock):
async def test_entity_device_info_with_connection(hass, mqtt_mock_entry_no_yaml_config):
"""Test MQTT lock device registry integration."""
await help_test_entity_device_info_with_connection(
hass, mqtt_mock, LOCK_DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_no_yaml_config, LOCK_DOMAIN, DEFAULT_CONFIG
)
async def test_entity_device_info_with_identifier(hass, mqtt_mock):
async def test_entity_device_info_with_identifier(hass, mqtt_mock_entry_no_yaml_config):
"""Test MQTT lock device registry integration."""
await help_test_entity_device_info_with_identifier(
hass, mqtt_mock, LOCK_DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_no_yaml_config, LOCK_DOMAIN, DEFAULT_CONFIG
)
async def test_entity_device_info_update(hass, mqtt_mock):
async def test_entity_device_info_update(hass, mqtt_mock_entry_no_yaml_config):
"""Test device registry update."""
await help_test_entity_device_info_update(
hass, mqtt_mock, LOCK_DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_no_yaml_config, LOCK_DOMAIN, DEFAULT_CONFIG
)
async def test_entity_device_info_remove(hass, mqtt_mock):
async def test_entity_device_info_remove(hass, mqtt_mock_entry_no_yaml_config):
"""Test device registry remove."""
await help_test_entity_device_info_remove(
hass, mqtt_mock, LOCK_DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_no_yaml_config, LOCK_DOMAIN, DEFAULT_CONFIG
)
async def test_entity_id_update_subscriptions(hass, mqtt_mock):
async def test_entity_id_update_subscriptions(hass, mqtt_mock_entry_with_yaml_config):
"""Test MQTT subscriptions are managed when entity_id is updated."""
await help_test_entity_id_update_subscriptions(
hass, mqtt_mock, LOCK_DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_with_yaml_config, LOCK_DOMAIN, DEFAULT_CONFIG
)
async def test_entity_id_update_discovery_update(hass, mqtt_mock):
async def test_entity_id_update_discovery_update(hass, mqtt_mock_entry_no_yaml_config):
"""Test MQTT discovery update when entity_id is updated."""
await help_test_entity_id_update_discovery_update(
hass, mqtt_mock, LOCK_DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_no_yaml_config, LOCK_DOMAIN, DEFAULT_CONFIG
)
async def test_entity_debug_info_message(hass, mqtt_mock):
async def test_entity_debug_info_message(hass, mqtt_mock_entry_no_yaml_config):
"""Test MQTT debug info."""
await help_test_entity_debug_info_message(
hass,
mqtt_mock,
mqtt_mock_entry_no_yaml_config,
LOCK_DOMAIN,
DEFAULT_CONFIG,
SERVICE_LOCK,
@ -616,7 +661,7 @@ async def test_entity_debug_info_message(hass, mqtt_mock):
)
async def test_publishing_with_custom_encoding(
hass,
mqtt_mock,
mqtt_mock_entry_with_yaml_config,
caplog,
service,
topic,
@ -630,7 +675,7 @@ async def test_publishing_with_custom_encoding(
await help_test_publishing_with_custom_encoding(
hass,
mqtt_mock,
mqtt_mock_entry_with_yaml_config,
caplog,
domain,
config,
@ -642,11 +687,13 @@ async def test_publishing_with_custom_encoding(
)
async def test_reloadable(hass, mqtt_mock, caplog, tmp_path):
async def test_reloadable(hass, mqtt_mock_entry_with_yaml_config, caplog, tmp_path):
"""Test reloading the MQTT platform."""
domain = LOCK_DOMAIN
config = DEFAULT_CONFIG[domain]
await help_test_reloadable(hass, mqtt_mock, caplog, tmp_path, domain, config)
await help_test_reloadable(
hass, mqtt_mock_entry_with_yaml_config, caplog, tmp_path, domain, config
)
async def test_reloadable_late(hass, mqtt_client_mock, caplog, tmp_path):
@ -663,12 +710,18 @@ async def test_reloadable_late(hass, mqtt_client_mock, caplog, tmp_path):
],
)
async def test_encoding_subscribable_topics(
hass, mqtt_mock, caplog, topic, value, attribute, attribute_value
hass,
mqtt_mock_entry_with_yaml_config,
caplog,
topic,
value,
attribute,
attribute_value,
):
"""Test handling of incoming encoded payload."""
await help_test_encoding_subscribable_topics(
hass,
mqtt_mock,
mqtt_mock_entry_with_yaml_config,
caplog,
LOCK_DOMAIN,
DEFAULT_CONFIG[LOCK_DOMAIN],

View File

@ -64,7 +64,7 @@ DEFAULT_CONFIG = {
}
async def test_run_number_setup(hass, mqtt_mock):
async def test_run_number_setup(hass, mqtt_mock_entry_with_yaml_config):
"""Test that it fetches the given payload."""
topic = "test/number"
await async_setup_component(
@ -82,6 +82,7 @@ async def test_run_number_setup(hass, mqtt_mock):
},
)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
async_fire_mqtt_message(hass, topic, "10")
@ -108,7 +109,7 @@ async def test_run_number_setup(hass, mqtt_mock):
assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == "my unit"
async def test_value_template(hass, mqtt_mock):
async def test_value_template(hass, mqtt_mock_entry_with_yaml_config):
"""Test that it fetches the given payload with a template."""
topic = "test/number"
await async_setup_component(
@ -125,6 +126,7 @@ async def test_value_template(hass, mqtt_mock):
},
)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
async_fire_mqtt_message(hass, topic, '{"val":10}')
@ -148,7 +150,7 @@ async def test_value_template(hass, mqtt_mock):
assert state.state == "unknown"
async def test_run_number_service_optimistic(hass, mqtt_mock):
async def test_run_number_service_optimistic(hass, mqtt_mock_entry_with_yaml_config):
"""Test that set_value service works in optimistic mode."""
topic = "test/number"
@ -170,6 +172,7 @@ async def test_run_number_service_optimistic(hass, mqtt_mock):
},
)
await hass.async_block_till_done()
mqtt_mock = await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("number.test_number")
assert state.state == "3"
@ -215,7 +218,9 @@ async def test_run_number_service_optimistic(hass, mqtt_mock):
assert state.state == "42.1"
async def test_run_number_service_optimistic_with_command_template(hass, mqtt_mock):
async def test_run_number_service_optimistic_with_command_template(
hass, mqtt_mock_entry_with_yaml_config
):
"""Test that set_value service works in optimistic mode and with a command_template."""
topic = "test/number"
@ -238,6 +243,7 @@ async def test_run_number_service_optimistic_with_command_template(hass, mqtt_mo
},
)
await hass.async_block_till_done()
mqtt_mock = await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("number.test_number")
assert state.state == "3"
@ -285,7 +291,7 @@ async def test_run_number_service_optimistic_with_command_template(hass, mqtt_mo
assert state.state == "42.1"
async def test_run_number_service(hass, mqtt_mock):
async def test_run_number_service(hass, mqtt_mock_entry_with_yaml_config):
"""Test that set_value service works in non optimistic mode."""
cmd_topic = "test/number/set"
state_topic = "test/number"
@ -303,6 +309,7 @@ async def test_run_number_service(hass, mqtt_mock):
},
)
await hass.async_block_till_done()
mqtt_mock = await mqtt_mock_entry_with_yaml_config()
async_fire_mqtt_message(hass, state_topic, "32")
state = hass.states.get("number.test_number")
@ -319,7 +326,9 @@ async def test_run_number_service(hass, mqtt_mock):
assert state.state == "32"
async def test_run_number_service_with_command_template(hass, mqtt_mock):
async def test_run_number_service_with_command_template(
hass, mqtt_mock_entry_with_yaml_config
):
"""Test that set_value service works in non optimistic mode and with a command_template."""
cmd_topic = "test/number/set"
state_topic = "test/number"
@ -338,6 +347,7 @@ async def test_run_number_service_with_command_template(hass, mqtt_mock):
},
)
await hass.async_block_till_done()
mqtt_mock = await mqtt_mock_entry_with_yaml_config()
async_fire_mqtt_message(hass, state_topic, "32")
state = hass.states.get("number.test_number")
@ -356,77 +366,91 @@ async def test_run_number_service_with_command_template(hass, mqtt_mock):
assert state.state == "32"
async def test_availability_when_connection_lost(hass, mqtt_mock):
async def test_availability_when_connection_lost(
hass, mqtt_mock_entry_with_yaml_config
):
"""Test availability after MQTT disconnection."""
await help_test_availability_when_connection_lost(
hass, mqtt_mock, number.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_with_yaml_config, number.DOMAIN, DEFAULT_CONFIG
)
async def test_availability_without_topic(hass, mqtt_mock):
async def test_availability_without_topic(hass, mqtt_mock_entry_with_yaml_config):
"""Test availability without defined availability topic."""
await help_test_availability_without_topic(
hass, mqtt_mock, number.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_with_yaml_config, number.DOMAIN, DEFAULT_CONFIG
)
async def test_default_availability_payload(hass, mqtt_mock):
async def test_default_availability_payload(hass, mqtt_mock_entry_with_yaml_config):
"""Test availability by default payload with defined topic."""
await help_test_default_availability_payload(
hass, mqtt_mock, number.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_with_yaml_config, number.DOMAIN, DEFAULT_CONFIG
)
async def test_custom_availability_payload(hass, mqtt_mock):
async def test_custom_availability_payload(hass, mqtt_mock_entry_with_yaml_config):
"""Test availability by custom payload with defined topic."""
await help_test_custom_availability_payload(
hass, mqtt_mock, number.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_with_yaml_config, number.DOMAIN, DEFAULT_CONFIG
)
async def test_setting_attribute_via_mqtt_json_message(hass, mqtt_mock):
async def test_setting_attribute_via_mqtt_json_message(
hass, mqtt_mock_entry_with_yaml_config
):
"""Test the setting of attribute via MQTT with JSON payload."""
await help_test_setting_attribute_via_mqtt_json_message(
hass, mqtt_mock, number.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_with_yaml_config, number.DOMAIN, DEFAULT_CONFIG
)
async def test_setting_blocked_attribute_via_mqtt_json_message(hass, mqtt_mock):
async def test_setting_blocked_attribute_via_mqtt_json_message(
hass, mqtt_mock_entry_no_yaml_config
):
"""Test the setting of attribute via MQTT with JSON payload."""
await help_test_setting_blocked_attribute_via_mqtt_json_message(
hass, mqtt_mock, number.DOMAIN, DEFAULT_CONFIG, MQTT_NUMBER_ATTRIBUTES_BLOCKED
hass,
mqtt_mock_entry_no_yaml_config,
number.DOMAIN,
DEFAULT_CONFIG,
MQTT_NUMBER_ATTRIBUTES_BLOCKED,
)
async def test_setting_attribute_with_template(hass, mqtt_mock):
async def test_setting_attribute_with_template(hass, mqtt_mock_entry_with_yaml_config):
"""Test the setting of attribute via MQTT with JSON payload."""
await help_test_setting_attribute_with_template(
hass, mqtt_mock, number.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_with_yaml_config, number.DOMAIN, DEFAULT_CONFIG
)
async def test_update_with_json_attrs_not_dict(hass, mqtt_mock, caplog):
async def test_update_with_json_attrs_not_dict(
hass, mqtt_mock_entry_with_yaml_config, caplog
):
"""Test attributes get extracted from a JSON result."""
await help_test_update_with_json_attrs_not_dict(
hass, mqtt_mock, caplog, number.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_with_yaml_config, caplog, number.DOMAIN, DEFAULT_CONFIG
)
async def test_update_with_json_attrs_bad_JSON(hass, mqtt_mock, caplog):
async def test_update_with_json_attrs_bad_JSON(
hass, mqtt_mock_entry_with_yaml_config, caplog
):
"""Test attributes get extracted from a JSON result."""
await help_test_update_with_json_attrs_bad_JSON(
hass, mqtt_mock, caplog, number.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_with_yaml_config, caplog, number.DOMAIN, DEFAULT_CONFIG
)
async def test_discovery_update_attr(hass, mqtt_mock, caplog):
async def test_discovery_update_attr(hass, mqtt_mock_entry_no_yaml_config, caplog):
"""Test update of discovered MQTTAttributes."""
await help_test_discovery_update_attr(
hass, mqtt_mock, caplog, number.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_no_yaml_config, caplog, number.DOMAIN, DEFAULT_CONFIG
)
async def test_unique_id(hass, mqtt_mock):
async def test_unique_id(hass, mqtt_mock_entry_with_yaml_config):
"""Test unique id option only creates one number per unique_id."""
config = {
number.DOMAIN: [
@ -446,16 +470,20 @@ async def test_unique_id(hass, mqtt_mock):
},
]
}
await help_test_unique_id(hass, mqtt_mock, number.DOMAIN, config)
await help_test_unique_id(
hass, mqtt_mock_entry_with_yaml_config, number.DOMAIN, config
)
async def test_discovery_removal_number(hass, mqtt_mock, caplog):
async def test_discovery_removal_number(hass, mqtt_mock_entry_no_yaml_config, caplog):
"""Test removal of discovered number."""
data = json.dumps(DEFAULT_CONFIG[number.DOMAIN])
await help_test_discovery_removal(hass, mqtt_mock, caplog, number.DOMAIN, data)
await help_test_discovery_removal(
hass, mqtt_mock_entry_no_yaml_config, caplog, number.DOMAIN, data
)
async def test_discovery_update_number(hass, mqtt_mock, caplog):
async def test_discovery_update_number(hass, mqtt_mock_entry_no_yaml_config, caplog):
"""Test update of discovered number."""
config1 = {
"name": "Beer",
@ -469,11 +497,13 @@ async def test_discovery_update_number(hass, mqtt_mock, caplog):
}
await help_test_discovery_update(
hass, mqtt_mock, caplog, number.DOMAIN, config1, config2
hass, mqtt_mock_entry_no_yaml_config, caplog, number.DOMAIN, config1, config2
)
async def test_discovery_update_unchanged_number(hass, mqtt_mock, caplog):
async def test_discovery_update_unchanged_number(
hass, mqtt_mock_entry_no_yaml_config, caplog
):
"""Test update of discovered number."""
data1 = (
'{ "name": "Beer", "state_topic": "test-topic", "command_topic": "test-topic"}'
@ -482,12 +512,17 @@ async def test_discovery_update_unchanged_number(hass, mqtt_mock, caplog):
"homeassistant.components.mqtt.number.MqttNumber.discovery_update"
) as discovery_update:
await help_test_discovery_update_unchanged(
hass, mqtt_mock, caplog, number.DOMAIN, data1, discovery_update
hass,
mqtt_mock_entry_no_yaml_config,
caplog,
number.DOMAIN,
data1,
discovery_update,
)
@pytest.mark.no_fail_on_log_exception
async def test_discovery_broken(hass, mqtt_mock, caplog):
async def test_discovery_broken(hass, mqtt_mock_entry_no_yaml_config, caplog):
"""Test handling of bad discovery message."""
data1 = '{ "name": "Beer" }'
data2 = (
@ -495,57 +530,57 @@ async def test_discovery_broken(hass, mqtt_mock, caplog):
)
await help_test_discovery_broken(
hass, mqtt_mock, caplog, number.DOMAIN, data1, data2
hass, mqtt_mock_entry_no_yaml_config, caplog, number.DOMAIN, data1, data2
)
async def test_entity_device_info_with_connection(hass, mqtt_mock):
async def test_entity_device_info_with_connection(hass, mqtt_mock_entry_no_yaml_config):
"""Test MQTT number device registry integration."""
await help_test_entity_device_info_with_connection(
hass, mqtt_mock, number.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_no_yaml_config, number.DOMAIN, DEFAULT_CONFIG
)
async def test_entity_device_info_with_identifier(hass, mqtt_mock):
async def test_entity_device_info_with_identifier(hass, mqtt_mock_entry_no_yaml_config):
"""Test MQTT number device registry integration."""
await help_test_entity_device_info_with_identifier(
hass, mqtt_mock, number.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_no_yaml_config, number.DOMAIN, DEFAULT_CONFIG
)
async def test_entity_device_info_update(hass, mqtt_mock):
async def test_entity_device_info_update(hass, mqtt_mock_entry_no_yaml_config):
"""Test device registry update."""
await help_test_entity_device_info_update(
hass, mqtt_mock, number.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_no_yaml_config, number.DOMAIN, DEFAULT_CONFIG
)
async def test_entity_device_info_remove(hass, mqtt_mock):
async def test_entity_device_info_remove(hass, mqtt_mock_entry_no_yaml_config):
"""Test device registry remove."""
await help_test_entity_device_info_remove(
hass, mqtt_mock, number.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_no_yaml_config, number.DOMAIN, DEFAULT_CONFIG
)
async def test_entity_id_update_subscriptions(hass, mqtt_mock):
async def test_entity_id_update_subscriptions(hass, mqtt_mock_entry_with_yaml_config):
"""Test MQTT subscriptions are managed when entity_id is updated."""
await help_test_entity_id_update_subscriptions(
hass, mqtt_mock, number.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_with_yaml_config, number.DOMAIN, DEFAULT_CONFIG
)
async def test_entity_id_update_discovery_update(hass, mqtt_mock):
async def test_entity_id_update_discovery_update(hass, mqtt_mock_entry_no_yaml_config):
"""Test MQTT discovery update when entity_id is updated."""
await help_test_entity_id_update_discovery_update(
hass, mqtt_mock, number.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_no_yaml_config, number.DOMAIN, DEFAULT_CONFIG
)
async def test_entity_debug_info_message(hass, mqtt_mock):
async def test_entity_debug_info_message(hass, mqtt_mock_entry_no_yaml_config):
"""Test MQTT debug info."""
await help_test_entity_debug_info_message(
hass,
mqtt_mock,
mqtt_mock_entry_no_yaml_config,
number.DOMAIN,
DEFAULT_CONFIG,
SERVICE_SET_VALUE,
@ -555,7 +590,7 @@ async def test_entity_debug_info_message(hass, mqtt_mock):
)
async def test_min_max_step_attributes(hass, mqtt_mock):
async def test_min_max_step_attributes(hass, mqtt_mock_entry_with_yaml_config):
"""Test min/max/step attributes."""
topic = "test/number"
await async_setup_component(
@ -574,6 +609,7 @@ async def test_min_max_step_attributes(hass, mqtt_mock):
},
)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("number.test_number")
assert state.attributes.get(ATTR_MIN) == 5
@ -581,7 +617,7 @@ async def test_min_max_step_attributes(hass, mqtt_mock):
assert state.attributes.get(ATTR_STEP) == 20
async def test_invalid_min_max_attributes(hass, caplog, mqtt_mock):
async def test_invalid_min_max_attributes(hass, caplog, mqtt_mock_entry_no_yaml_config):
"""Test invalid min/max attributes."""
topic = "test/number"
await async_setup_component(
@ -599,11 +635,14 @@ async def test_invalid_min_max_attributes(hass, caplog, mqtt_mock):
},
)
await hass.async_block_till_done()
await mqtt_mock_entry_no_yaml_config()
assert f"'{CONF_MAX}' must be > '{CONF_MIN}'" in caplog.text
async def test_mqtt_payload_not_a_number_warning(hass, caplog, mqtt_mock):
async def test_mqtt_payload_not_a_number_warning(
hass, caplog, mqtt_mock_entry_with_yaml_config
):
"""Test warning for MQTT payload which is not a number."""
topic = "test/number"
await async_setup_component(
@ -619,6 +658,7 @@ async def test_mqtt_payload_not_a_number_warning(hass, caplog, mqtt_mock):
},
)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
async_fire_mqtt_message(hass, topic, "not_a_number")
@ -627,7 +667,9 @@ async def test_mqtt_payload_not_a_number_warning(hass, caplog, mqtt_mock):
assert "Payload 'not_a_number' is not a Number" in caplog.text
async def test_mqtt_payload_out_of_range_error(hass, caplog, mqtt_mock):
async def test_mqtt_payload_out_of_range_error(
hass, caplog, mqtt_mock_entry_with_yaml_config
):
"""Test error when MQTT payload is out of min/max range."""
topic = "test/number"
await async_setup_component(
@ -645,6 +687,7 @@ async def test_mqtt_payload_out_of_range_error(hass, caplog, mqtt_mock):
},
)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
async_fire_mqtt_message(hass, topic, "115.5")
@ -669,7 +712,7 @@ async def test_mqtt_payload_out_of_range_error(hass, caplog, mqtt_mock):
)
async def test_publishing_with_custom_encoding(
hass,
mqtt_mock,
mqtt_mock_entry_with_yaml_config,
caplog,
service,
topic,
@ -683,7 +726,7 @@ async def test_publishing_with_custom_encoding(
await help_test_publishing_with_custom_encoding(
hass,
mqtt_mock,
mqtt_mock_entry_with_yaml_config,
caplog,
domain,
config,
@ -695,11 +738,13 @@ async def test_publishing_with_custom_encoding(
)
async def test_reloadable(hass, mqtt_mock, caplog, tmp_path):
async def test_reloadable(hass, mqtt_mock_entry_with_yaml_config, caplog, tmp_path):
"""Test reloading the MQTT platform."""
domain = number.DOMAIN
config = DEFAULT_CONFIG[domain]
await help_test_reloadable(hass, mqtt_mock, caplog, tmp_path, domain, config)
await help_test_reloadable(
hass, mqtt_mock_entry_with_yaml_config, caplog, tmp_path, domain, config
)
async def test_reloadable_late(hass, mqtt_client_mock, caplog, tmp_path):
@ -717,12 +762,18 @@ async def test_reloadable_late(hass, mqtt_client_mock, caplog, tmp_path):
],
)
async def test_encoding_subscribable_topics(
hass, mqtt_mock, caplog, topic, value, attribute, attribute_value
hass,
mqtt_mock_entry_with_yaml_config,
caplog,
topic,
value,
attribute,
attribute_value,
):
"""Test handling of incoming encoded payload."""
await help_test_encoding_subscribable_topics(
hass,
mqtt_mock,
mqtt_mock_entry_with_yaml_config,
caplog,
"number",
DEFAULT_CONFIG["number"],

View File

@ -34,7 +34,7 @@ DEFAULT_CONFIG = {
}
async def test_sending_mqtt_commands(hass, mqtt_mock):
async def test_sending_mqtt_commands(hass, mqtt_mock_entry_with_yaml_config):
"""Test the sending MQTT commands."""
fake_state = ha.State("scene.test", STATE_UNKNOWN)
@ -55,6 +55,7 @@ async def test_sending_mqtt_commands(hass, mqtt_mock):
},
)
await hass.async_block_till_done()
mqtt_mock = await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("scene.test")
assert state.state == STATE_UNKNOWN
@ -67,21 +68,23 @@ async def test_sending_mqtt_commands(hass, mqtt_mock):
)
async def test_availability_when_connection_lost(hass, mqtt_mock):
async def test_availability_when_connection_lost(
hass, mqtt_mock_entry_with_yaml_config
):
"""Test availability after MQTT disconnection."""
await help_test_availability_when_connection_lost(
hass, mqtt_mock, scene.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_with_yaml_config, scene.DOMAIN, DEFAULT_CONFIG
)
async def test_availability_without_topic(hass, mqtt_mock):
async def test_availability_without_topic(hass, mqtt_mock_entry_with_yaml_config):
"""Test availability without defined availability topic."""
await help_test_availability_without_topic(
hass, mqtt_mock, scene.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_with_yaml_config, scene.DOMAIN, DEFAULT_CONFIG
)
async def test_default_availability_payload(hass, mqtt_mock):
async def test_default_availability_payload(hass, mqtt_mock_entry_with_yaml_config):
"""Test availability by default payload with defined topic."""
config = {
scene.DOMAIN: {
@ -93,11 +96,17 @@ async def test_default_availability_payload(hass, mqtt_mock):
}
await help_test_default_availability_payload(
hass, mqtt_mock, scene.DOMAIN, config, True, "state-topic", "1"
hass,
mqtt_mock_entry_with_yaml_config,
scene.DOMAIN,
config,
True,
"state-topic",
"1",
)
async def test_custom_availability_payload(hass, mqtt_mock):
async def test_custom_availability_payload(hass, mqtt_mock_entry_with_yaml_config):
"""Test availability by custom payload with defined topic."""
config = {
scene.DOMAIN: {
@ -109,11 +118,17 @@ async def test_custom_availability_payload(hass, mqtt_mock):
}
await help_test_custom_availability_payload(
hass, mqtt_mock, scene.DOMAIN, config, True, "state-topic", "1"
hass,
mqtt_mock_entry_with_yaml_config,
scene.DOMAIN,
config,
True,
"state-topic",
"1",
)
async def test_unique_id(hass, mqtt_mock):
async def test_unique_id(hass, mqtt_mock_entry_with_yaml_config):
"""Test unique id option only creates one scene per unique_id."""
config = {
scene.DOMAIN: [
@ -131,16 +146,20 @@ async def test_unique_id(hass, mqtt_mock):
},
]
}
await help_test_unique_id(hass, mqtt_mock, scene.DOMAIN, config)
await help_test_unique_id(
hass, mqtt_mock_entry_with_yaml_config, scene.DOMAIN, config
)
async def test_discovery_removal_scene(hass, mqtt_mock, caplog):
async def test_discovery_removal_scene(hass, mqtt_mock_entry_no_yaml_config, caplog):
"""Test removal of discovered scene."""
data = '{ "name": "test",' ' "command_topic": "test_topic" }'
await help_test_discovery_removal(hass, mqtt_mock, caplog, scene.DOMAIN, data)
await help_test_discovery_removal(
hass, mqtt_mock_entry_no_yaml_config, caplog, scene.DOMAIN, data
)
async def test_discovery_update_payload(hass, mqtt_mock, caplog):
async def test_discovery_update_payload(hass, mqtt_mock_entry_no_yaml_config, caplog):
"""Test update of discovered scene."""
config1 = copy.deepcopy(DEFAULT_CONFIG[scene.DOMAIN])
config2 = copy.deepcopy(DEFAULT_CONFIG[scene.DOMAIN])
@ -151,7 +170,7 @@ async def test_discovery_update_payload(hass, mqtt_mock, caplog):
await help_test_discovery_update(
hass,
mqtt_mock,
mqtt_mock_entry_no_yaml_config,
caplog,
scene.DOMAIN,
config1,
@ -159,32 +178,41 @@ async def test_discovery_update_payload(hass, mqtt_mock, caplog):
)
async def test_discovery_update_unchanged_scene(hass, mqtt_mock, caplog):
async def test_discovery_update_unchanged_scene(
hass, mqtt_mock_entry_no_yaml_config, caplog
):
"""Test update of discovered scene."""
data1 = '{ "name": "Beer",' ' "command_topic": "test_topic" }'
with patch(
"homeassistant.components.mqtt.scene.MqttScene.discovery_update"
) as discovery_update:
await help_test_discovery_update_unchanged(
hass, mqtt_mock, caplog, scene.DOMAIN, data1, discovery_update
hass,
mqtt_mock_entry_no_yaml_config,
caplog,
scene.DOMAIN,
data1,
discovery_update,
)
@pytest.mark.no_fail_on_log_exception
async def test_discovery_broken(hass, mqtt_mock, caplog):
async def test_discovery_broken(hass, mqtt_mock_entry_no_yaml_config, caplog):
"""Test handling of bad discovery message."""
data1 = '{ "name": "Beer" }'
data2 = '{ "name": "Milk",' ' "command_topic": "test_topic" }'
await help_test_discovery_broken(
hass, mqtt_mock, caplog, scene.DOMAIN, data1, data2
hass, mqtt_mock_entry_no_yaml_config, caplog, scene.DOMAIN, data1, data2
)
async def test_reloadable(hass, mqtt_mock, caplog, tmp_path):
async def test_reloadable(hass, mqtt_mock_entry_with_yaml_config, caplog, tmp_path):
"""Test reloading the MQTT platform."""
domain = scene.DOMAIN
config = DEFAULT_CONFIG[domain]
await help_test_reloadable(hass, mqtt_mock, caplog, tmp_path, domain, config)
await help_test_reloadable(
hass, mqtt_mock_entry_with_yaml_config, caplog, tmp_path, domain, config
)
async def test_reloadable_late(hass, mqtt_client_mock, caplog, tmp_path):

View File

@ -59,7 +59,7 @@ DEFAULT_CONFIG = {
}
async def test_run_select_setup(hass, mqtt_mock):
async def test_run_select_setup(hass, mqtt_mock_entry_with_yaml_config):
"""Test that it fetches the given payload."""
topic = "test/select"
await async_setup_component(
@ -76,6 +76,7 @@ async def test_run_select_setup(hass, mqtt_mock):
},
)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
async_fire_mqtt_message(hass, topic, "milk")
@ -92,7 +93,7 @@ async def test_run_select_setup(hass, mqtt_mock):
assert state.state == "beer"
async def test_value_template(hass, mqtt_mock):
async def test_value_template(hass, mqtt_mock_entry_with_yaml_config):
"""Test that it fetches the given payload with a template."""
topic = "test/select"
await async_setup_component(
@ -110,6 +111,7 @@ async def test_value_template(hass, mqtt_mock):
},
)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
async_fire_mqtt_message(hass, topic, '{"val":"milk"}')
@ -133,7 +135,7 @@ async def test_value_template(hass, mqtt_mock):
assert state.state == STATE_UNKNOWN
async def test_run_select_service_optimistic(hass, mqtt_mock):
async def test_run_select_service_optimistic(hass, mqtt_mock_entry_with_yaml_config):
"""Test that set_value service works in optimistic mode."""
topic = "test/select"
@ -156,6 +158,7 @@ async def test_run_select_service_optimistic(hass, mqtt_mock):
},
)
await hass.async_block_till_done()
mqtt_mock = await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("select.test_select")
assert state.state == "milk"
@ -174,7 +177,9 @@ async def test_run_select_service_optimistic(hass, mqtt_mock):
assert state.state == "beer"
async def test_run_select_service_optimistic_with_command_template(hass, mqtt_mock):
async def test_run_select_service_optimistic_with_command_template(
hass, mqtt_mock_entry_with_yaml_config
):
"""Test that set_value service works in optimistic mode and with a command_template."""
topic = "test/select"
@ -198,6 +203,7 @@ async def test_run_select_service_optimistic_with_command_template(hass, mqtt_mo
},
)
await hass.async_block_till_done()
mqtt_mock = await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("select.test_select")
assert state.state == "milk"
@ -218,7 +224,7 @@ async def test_run_select_service_optimistic_with_command_template(hass, mqtt_mo
assert state.state == "beer"
async def test_run_select_service(hass, mqtt_mock):
async def test_run_select_service(hass, mqtt_mock_entry_with_yaml_config):
"""Test that set_value service works in non optimistic mode."""
cmd_topic = "test/select/set"
state_topic = "test/select"
@ -237,6 +243,7 @@ async def test_run_select_service(hass, mqtt_mock):
},
)
await hass.async_block_till_done()
mqtt_mock = await mqtt_mock_entry_with_yaml_config()
async_fire_mqtt_message(hass, state_topic, "beer")
state = hass.states.get("select.test_select")
@ -253,7 +260,9 @@ async def test_run_select_service(hass, mqtt_mock):
assert state.state == "beer"
async def test_run_select_service_with_command_template(hass, mqtt_mock):
async def test_run_select_service_with_command_template(
hass, mqtt_mock_entry_with_yaml_config
):
"""Test that set_value service works in non optimistic mode and with a command_template."""
cmd_topic = "test/select/set"
state_topic = "test/select"
@ -273,6 +282,7 @@ async def test_run_select_service_with_command_template(hass, mqtt_mock):
},
)
await hass.async_block_till_done()
mqtt_mock = await mqtt_mock_entry_with_yaml_config()
async_fire_mqtt_message(hass, state_topic, "beer")
state = hass.states.get("select.test_select")
@ -289,77 +299,91 @@ async def test_run_select_service_with_command_template(hass, mqtt_mock):
)
async def test_availability_when_connection_lost(hass, mqtt_mock):
async def test_availability_when_connection_lost(
hass, mqtt_mock_entry_with_yaml_config
):
"""Test availability after MQTT disconnection."""
await help_test_availability_when_connection_lost(
hass, mqtt_mock, select.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_with_yaml_config, select.DOMAIN, DEFAULT_CONFIG
)
async def test_availability_without_topic(hass, mqtt_mock):
async def test_availability_without_topic(hass, mqtt_mock_entry_with_yaml_config):
"""Test availability without defined availability topic."""
await help_test_availability_without_topic(
hass, mqtt_mock, select.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_with_yaml_config, select.DOMAIN, DEFAULT_CONFIG
)
async def test_default_availability_payload(hass, mqtt_mock):
async def test_default_availability_payload(hass, mqtt_mock_entry_with_yaml_config):
"""Test availability by default payload with defined topic."""
await help_test_default_availability_payload(
hass, mqtt_mock, select.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_with_yaml_config, select.DOMAIN, DEFAULT_CONFIG
)
async def test_custom_availability_payload(hass, mqtt_mock):
async def test_custom_availability_payload(hass, mqtt_mock_entry_with_yaml_config):
"""Test availability by custom payload with defined topic."""
await help_test_custom_availability_payload(
hass, mqtt_mock, select.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_with_yaml_config, select.DOMAIN, DEFAULT_CONFIG
)
async def test_setting_attribute_via_mqtt_json_message(hass, mqtt_mock):
async def test_setting_attribute_via_mqtt_json_message(
hass, mqtt_mock_entry_with_yaml_config
):
"""Test the setting of attribute via MQTT with JSON payload."""
await help_test_setting_attribute_via_mqtt_json_message(
hass, mqtt_mock, select.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_with_yaml_config, select.DOMAIN, DEFAULT_CONFIG
)
async def test_setting_blocked_attribute_via_mqtt_json_message(hass, mqtt_mock):
async def test_setting_blocked_attribute_via_mqtt_json_message(
hass, mqtt_mock_entry_no_yaml_config
):
"""Test the setting of attribute via MQTT with JSON payload."""
await help_test_setting_blocked_attribute_via_mqtt_json_message(
hass, mqtt_mock, select.DOMAIN, DEFAULT_CONFIG, MQTT_SELECT_ATTRIBUTES_BLOCKED
hass,
mqtt_mock_entry_no_yaml_config,
select.DOMAIN,
DEFAULT_CONFIG,
MQTT_SELECT_ATTRIBUTES_BLOCKED,
)
async def test_setting_attribute_with_template(hass, mqtt_mock):
async def test_setting_attribute_with_template(hass, mqtt_mock_entry_with_yaml_config):
"""Test the setting of attribute via MQTT with JSON payload."""
await help_test_setting_attribute_with_template(
hass, mqtt_mock, select.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_with_yaml_config, select.DOMAIN, DEFAULT_CONFIG
)
async def test_update_with_json_attrs_not_dict(hass, mqtt_mock, caplog):
async def test_update_with_json_attrs_not_dict(
hass, mqtt_mock_entry_with_yaml_config, caplog
):
"""Test attributes get extracted from a JSON result."""
await help_test_update_with_json_attrs_not_dict(
hass, mqtt_mock, caplog, select.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_with_yaml_config, caplog, select.DOMAIN, DEFAULT_CONFIG
)
async def test_update_with_json_attrs_bad_JSON(hass, mqtt_mock, caplog):
async def test_update_with_json_attrs_bad_JSON(
hass, mqtt_mock_entry_with_yaml_config, caplog
):
"""Test attributes get extracted from a JSON result."""
await help_test_update_with_json_attrs_bad_JSON(
hass, mqtt_mock, caplog, select.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_with_yaml_config, caplog, select.DOMAIN, DEFAULT_CONFIG
)
async def test_discovery_update_attr(hass, mqtt_mock, caplog):
async def test_discovery_update_attr(hass, mqtt_mock_entry_no_yaml_config, caplog):
"""Test update of discovered MQTTAttributes."""
await help_test_discovery_update_attr(
hass, mqtt_mock, caplog, select.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_no_yaml_config, caplog, select.DOMAIN, DEFAULT_CONFIG
)
async def test_unique_id(hass, mqtt_mock):
async def test_unique_id(hass, mqtt_mock_entry_with_yaml_config):
"""Test unique id option only creates one select per unique_id."""
config = {
select.DOMAIN: [
@ -381,16 +405,20 @@ async def test_unique_id(hass, mqtt_mock):
},
]
}
await help_test_unique_id(hass, mqtt_mock, select.DOMAIN, config)
await help_test_unique_id(
hass, mqtt_mock_entry_with_yaml_config, select.DOMAIN, config
)
async def test_discovery_removal_select(hass, mqtt_mock, caplog):
async def test_discovery_removal_select(hass, mqtt_mock_entry_no_yaml_config, caplog):
"""Test removal of discovered select."""
data = json.dumps(DEFAULT_CONFIG[select.DOMAIN])
await help_test_discovery_removal(hass, mqtt_mock, caplog, select.DOMAIN, data)
await help_test_discovery_removal(
hass, mqtt_mock_entry_no_yaml_config, caplog, select.DOMAIN, data
)
async def test_discovery_update_select(hass, mqtt_mock, caplog):
async def test_discovery_update_select(hass, mqtt_mock_entry_no_yaml_config, caplog):
"""Test update of discovered select."""
config1 = {
"name": "Beer",
@ -406,79 +434,86 @@ async def test_discovery_update_select(hass, mqtt_mock, caplog):
}
await help_test_discovery_update(
hass, mqtt_mock, caplog, select.DOMAIN, config1, config2
hass, mqtt_mock_entry_no_yaml_config, caplog, select.DOMAIN, config1, config2
)
async def test_discovery_update_unchanged_select(hass, mqtt_mock, caplog):
async def test_discovery_update_unchanged_select(
hass, mqtt_mock_entry_no_yaml_config, caplog
):
"""Test update of discovered select."""
data1 = '{ "name": "Beer", "state_topic": "test-topic", "command_topic": "test-topic", "options": ["milk", "beer"]}'
with patch(
"homeassistant.components.mqtt.select.MqttSelect.discovery_update"
) as discovery_update:
await help_test_discovery_update_unchanged(
hass, mqtt_mock, caplog, select.DOMAIN, data1, discovery_update
hass,
mqtt_mock_entry_no_yaml_config,
caplog,
select.DOMAIN,
data1,
discovery_update,
)
@pytest.mark.no_fail_on_log_exception
async def test_discovery_broken(hass, mqtt_mock, caplog):
async def test_discovery_broken(hass, mqtt_mock_entry_no_yaml_config, caplog):
"""Test handling of bad discovery message."""
data1 = '{ "name": "Beer" }'
data2 = '{ "name": "Milk", "state_topic": "test-topic", "command_topic": "test-topic", "options": ["milk", "beer"]}'
await help_test_discovery_broken(
hass, mqtt_mock, caplog, select.DOMAIN, data1, data2
hass, mqtt_mock_entry_no_yaml_config, caplog, select.DOMAIN, data1, data2
)
async def test_entity_device_info_with_connection(hass, mqtt_mock):
async def test_entity_device_info_with_connection(hass, mqtt_mock_entry_no_yaml_config):
"""Test MQTT select device registry integration."""
await help_test_entity_device_info_with_connection(
hass, mqtt_mock, select.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_no_yaml_config, select.DOMAIN, DEFAULT_CONFIG
)
async def test_entity_device_info_with_identifier(hass, mqtt_mock):
async def test_entity_device_info_with_identifier(hass, mqtt_mock_entry_no_yaml_config):
"""Test MQTT select device registry integration."""
await help_test_entity_device_info_with_identifier(
hass, mqtt_mock, select.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_no_yaml_config, select.DOMAIN, DEFAULT_CONFIG
)
async def test_entity_device_info_update(hass, mqtt_mock):
async def test_entity_device_info_update(hass, mqtt_mock_entry_no_yaml_config):
"""Test device registry update."""
await help_test_entity_device_info_update(
hass, mqtt_mock, select.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_no_yaml_config, select.DOMAIN, DEFAULT_CONFIG
)
async def test_entity_device_info_remove(hass, mqtt_mock):
async def test_entity_device_info_remove(hass, mqtt_mock_entry_no_yaml_config):
"""Test device registry remove."""
await help_test_entity_device_info_remove(
hass, mqtt_mock, select.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_no_yaml_config, select.DOMAIN, DEFAULT_CONFIG
)
async def test_entity_id_update_subscriptions(hass, mqtt_mock):
async def test_entity_id_update_subscriptions(hass, mqtt_mock_entry_with_yaml_config):
"""Test MQTT subscriptions are managed when entity_id is updated."""
await help_test_entity_id_update_subscriptions(
hass, mqtt_mock, select.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_with_yaml_config, select.DOMAIN, DEFAULT_CONFIG
)
async def test_entity_id_update_discovery_update(hass, mqtt_mock):
async def test_entity_id_update_discovery_update(hass, mqtt_mock_entry_no_yaml_config):
"""Test MQTT discovery update when entity_id is updated."""
await help_test_entity_id_update_discovery_update(
hass, mqtt_mock, select.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_no_yaml_config, select.DOMAIN, DEFAULT_CONFIG
)
async def test_entity_debug_info_message(hass, mqtt_mock):
async def test_entity_debug_info_message(hass, mqtt_mock_entry_no_yaml_config):
"""Test MQTT debug info."""
await help_test_entity_debug_info_message(
hass,
mqtt_mock,
mqtt_mock_entry_no_yaml_config,
select.DOMAIN,
DEFAULT_CONFIG,
select.SERVICE_SELECT_OPTION,
@ -489,7 +524,7 @@ async def test_entity_debug_info_message(hass, mqtt_mock):
@pytest.mark.parametrize("options", [["milk", "beer"], ["milk"], []])
async def test_options_attributes(hass, mqtt_mock, options):
async def test_options_attributes(hass, mqtt_mock_entry_with_yaml_config, options):
"""Test options attribute."""
topic = "test/select"
await async_setup_component(
@ -506,12 +541,15 @@ async def test_options_attributes(hass, mqtt_mock, options):
},
)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("select.test_select")
assert state.attributes.get(ATTR_OPTIONS) == options
async def test_mqtt_payload_not_an_option_warning(hass, caplog, mqtt_mock):
async def test_mqtt_payload_not_an_option_warning(
hass, caplog, mqtt_mock_entry_with_yaml_config
):
"""Test warning for MQTT payload which is not a valid option."""
topic = "test/select"
await async_setup_component(
@ -528,6 +566,7 @@ async def test_mqtt_payload_not_an_option_warning(hass, caplog, mqtt_mock):
},
)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
async_fire_mqtt_message(hass, topic, "öl")
@ -552,7 +591,14 @@ async def test_mqtt_payload_not_an_option_warning(hass, caplog, mqtt_mock):
],
)
async def test_publishing_with_custom_encoding(
hass, mqtt_mock, caplog, service, topic, parameters, payload, template
hass,
mqtt_mock_entry_with_yaml_config,
caplog,
service,
topic,
parameters,
payload,
template,
):
"""Test publishing MQTT payload with different encoding."""
domain = select.DOMAIN
@ -561,7 +607,7 @@ async def test_publishing_with_custom_encoding(
await help_test_publishing_with_custom_encoding(
hass,
mqtt_mock,
mqtt_mock_entry_with_yaml_config,
caplog,
domain,
config,
@ -573,11 +619,13 @@ async def test_publishing_with_custom_encoding(
)
async def test_reloadable(hass, mqtt_mock, caplog, tmp_path):
async def test_reloadable(hass, mqtt_mock_entry_with_yaml_config, caplog, tmp_path):
"""Test reloading the MQTT platform."""
domain = select.DOMAIN
config = DEFAULT_CONFIG[domain]
await help_test_reloadable(hass, mqtt_mock, caplog, tmp_path, domain, config)
await help_test_reloadable(
hass, mqtt_mock_entry_with_yaml_config, caplog, tmp_path, domain, config
)
async def test_reloadable_late(hass, mqtt_client_mock, caplog, tmp_path):
@ -595,14 +643,20 @@ async def test_reloadable_late(hass, mqtt_client_mock, caplog, tmp_path):
],
)
async def test_encoding_subscribable_topics(
hass, mqtt_mock, caplog, topic, value, attribute, attribute_value
hass,
mqtt_mock_entry_with_yaml_config,
caplog,
topic,
value,
attribute,
attribute_value,
):
"""Test handling of incoming encoded payload."""
config = copy.deepcopy(DEFAULT_CONFIG["select"])
config["options"] = ["milk", "beer"]
await help_test_encoding_subscribable_topics(
hass,
mqtt_mock,
mqtt_mock_entry_with_yaml_config,
caplog,
"select",
config,

View File

@ -72,7 +72,9 @@ DEFAULT_CONFIG = {
}
async def test_setting_sensor_value_via_mqtt_message(hass, mqtt_mock):
async def test_setting_sensor_value_via_mqtt_message(
hass, mqtt_mock_entry_with_yaml_config
):
"""Test the setting of the value via MQTT."""
assert await async_setup_component(
hass,
@ -87,6 +89,7 @@ async def test_setting_sensor_value_via_mqtt_message(hass, mqtt_mock):
},
)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
async_fire_mqtt_message(hass, "test-topic", "100")
state = hass.states.get("sensor.test")
@ -122,7 +125,13 @@ async def test_setting_sensor_value_via_mqtt_message(hass, mqtt_mock):
],
)
async def test_setting_sensor_native_value_handling_via_mqtt_message(
hass, mqtt_mock, caplog, device_class, native_value, state_value, log
hass,
mqtt_mock_entry_with_yaml_config,
caplog,
device_class,
native_value,
state_value,
log,
):
"""Test the setting of the value via MQTT."""
assert await async_setup_component(
@ -138,6 +147,7 @@ async def test_setting_sensor_native_value_handling_via_mqtt_message(
},
)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
async_fire_mqtt_message(hass, "test-topic", native_value)
state = hass.states.get("sensor.test")
@ -147,7 +157,9 @@ async def test_setting_sensor_native_value_handling_via_mqtt_message(
assert log == ("Invalid state message" in caplog.text)
async def test_setting_sensor_value_expires_availability_topic(hass, mqtt_mock, caplog):
async def test_setting_sensor_value_expires_availability_topic(
hass, mqtt_mock_entry_with_yaml_config, caplog
):
"""Test the expiration of the value."""
assert await async_setup_component(
hass,
@ -164,6 +176,7 @@ async def test_setting_sensor_value_expires_availability_topic(hass, mqtt_mock,
},
)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("sensor.test")
assert state.state == STATE_UNAVAILABLE
@ -174,10 +187,12 @@ async def test_setting_sensor_value_expires_availability_topic(hass, mqtt_mock,
state = hass.states.get("sensor.test")
assert state.state == STATE_UNAVAILABLE
await expires_helper(hass, mqtt_mock, caplog)
await expires_helper(hass, caplog)
async def test_setting_sensor_value_expires(hass, mqtt_mock, caplog):
async def test_setting_sensor_value_expires(
hass, mqtt_mock_entry_with_yaml_config, caplog
):
"""Test the expiration of the value."""
assert await async_setup_component(
hass,
@ -194,15 +209,16 @@ async def test_setting_sensor_value_expires(hass, mqtt_mock, caplog):
},
)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
# State should be unavailable since expire_after is defined and > 0
state = hass.states.get("sensor.test")
assert state.state == STATE_UNAVAILABLE
await expires_helper(hass, mqtt_mock, caplog)
await expires_helper(hass, caplog)
async def expires_helper(hass, mqtt_mock, caplog):
async def expires_helper(hass, caplog):
"""Run the basic expiry code."""
realnow = dt_util.utcnow()
now = datetime(realnow.year + 1, 1, 1, 1, tzinfo=dt_util.UTC)
@ -253,7 +269,9 @@ async def expires_helper(hass, mqtt_mock, caplog):
assert state.state == STATE_UNAVAILABLE
async def test_setting_sensor_value_via_mqtt_json_message(hass, mqtt_mock):
async def test_setting_sensor_value_via_mqtt_json_message(
hass, mqtt_mock_entry_with_yaml_config
):
"""Test the setting of the value via MQTT with JSON payload."""
assert await async_setup_component(
hass,
@ -269,6 +287,7 @@ async def test_setting_sensor_value_via_mqtt_json_message(hass, mqtt_mock):
},
)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
async_fire_mqtt_message(hass, "test-topic", '{ "val": "100" }')
state = hass.states.get("sensor.test")
@ -277,7 +296,7 @@ async def test_setting_sensor_value_via_mqtt_json_message(hass, mqtt_mock):
async def test_setting_sensor_value_via_mqtt_json_message_and_default_current_state(
hass, mqtt_mock
hass, mqtt_mock_entry_with_yaml_config
):
"""Test the setting of the value via MQTT with fall back to current state."""
assert await async_setup_component(
@ -294,6 +313,7 @@ async def test_setting_sensor_value_via_mqtt_json_message_and_default_current_st
},
)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
async_fire_mqtt_message(
hass, "test-topic", '{ "val": "valcontent", "par": "parcontent" }'
@ -308,7 +328,9 @@ async def test_setting_sensor_value_via_mqtt_json_message_and_default_current_st
assert state.state == "valcontent-parcontent"
async def test_setting_sensor_last_reset_via_mqtt_message(hass, mqtt_mock, caplog):
async def test_setting_sensor_last_reset_via_mqtt_message(
hass, mqtt_mock_entry_with_yaml_config, caplog
):
"""Test the setting of the last_reset property via MQTT."""
assert await async_setup_component(
hass,
@ -325,6 +347,7 @@ async def test_setting_sensor_last_reset_via_mqtt_message(hass, mqtt_mock, caplo
},
)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
async_fire_mqtt_message(hass, "last-reset-topic", "2020-01-02 08:11:00")
state = hass.states.get("sensor.test")
@ -338,7 +361,7 @@ async def test_setting_sensor_last_reset_via_mqtt_message(hass, mqtt_mock, caplo
@pytest.mark.parametrize("datestring", ["2020-21-02 08:11:00", "Hello there!"])
async def test_setting_sensor_bad_last_reset_via_mqtt_message(
hass, caplog, datestring, mqtt_mock
hass, caplog, datestring, mqtt_mock_entry_with_yaml_config
):
"""Test the setting of the last_reset property via MQTT."""
assert await async_setup_component(
@ -356,6 +379,7 @@ async def test_setting_sensor_bad_last_reset_via_mqtt_message(
},
)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
async_fire_mqtt_message(hass, "last-reset-topic", datestring)
state = hass.states.get("sensor.test")
@ -364,7 +388,7 @@ async def test_setting_sensor_bad_last_reset_via_mqtt_message(
async def test_setting_sensor_empty_last_reset_via_mqtt_message(
hass, caplog, mqtt_mock
hass, caplog, mqtt_mock_entry_with_yaml_config
):
"""Test the setting of the last_reset property via MQTT."""
assert await async_setup_component(
@ -382,6 +406,7 @@ async def test_setting_sensor_empty_last_reset_via_mqtt_message(
},
)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
async_fire_mqtt_message(hass, "last-reset-topic", "")
state = hass.states.get("sensor.test")
@ -389,7 +414,9 @@ async def test_setting_sensor_empty_last_reset_via_mqtt_message(
assert "Ignoring empty last_reset message" in caplog.text
async def test_setting_sensor_last_reset_via_mqtt_json_message(hass, mqtt_mock):
async def test_setting_sensor_last_reset_via_mqtt_json_message(
hass, mqtt_mock_entry_with_yaml_config
):
"""Test the setting of the value via MQTT with JSON payload."""
assert await async_setup_component(
hass,
@ -407,6 +434,7 @@ async def test_setting_sensor_last_reset_via_mqtt_json_message(hass, mqtt_mock):
},
)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
async_fire_mqtt_message(
hass, "last-reset-topic", '{ "last_reset": "2020-01-02 08:11:00" }'
@ -417,7 +445,7 @@ async def test_setting_sensor_last_reset_via_mqtt_json_message(hass, mqtt_mock):
@pytest.mark.parametrize("extra", [{}, {"last_reset_topic": "test-topic"}])
async def test_setting_sensor_last_reset_via_mqtt_json_message_2(
hass, mqtt_mock, caplog, extra
hass, mqtt_mock_entry_with_yaml_config, caplog, extra
):
"""Test the setting of the value via MQTT with JSON payload."""
assert await async_setup_component(
@ -439,6 +467,7 @@ async def test_setting_sensor_last_reset_via_mqtt_json_message_2(
},
)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
async_fire_mqtt_message(
hass,
@ -455,7 +484,7 @@ async def test_setting_sensor_last_reset_via_mqtt_json_message_2(
)
async def test_force_update_disabled(hass, mqtt_mock):
async def test_force_update_disabled(hass, mqtt_mock_entry_with_yaml_config):
"""Test force update option."""
assert await async_setup_component(
hass,
@ -470,6 +499,7 @@ async def test_force_update_disabled(hass, mqtt_mock):
},
)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
events = []
@ -488,7 +518,7 @@ async def test_force_update_disabled(hass, mqtt_mock):
assert len(events) == 1
async def test_force_update_enabled(hass, mqtt_mock):
async def test_force_update_enabled(hass, mqtt_mock_entry_with_yaml_config):
"""Test force update option."""
assert await async_setup_component(
hass,
@ -504,6 +534,7 @@ async def test_force_update_enabled(hass, mqtt_mock):
},
)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
events = []
@ -522,70 +553,80 @@ async def test_force_update_enabled(hass, mqtt_mock):
assert len(events) == 2
async def test_availability_when_connection_lost(hass, mqtt_mock):
async def test_availability_when_connection_lost(
hass, mqtt_mock_entry_with_yaml_config
):
"""Test availability after MQTT disconnection."""
await help_test_availability_when_connection_lost(
hass, mqtt_mock, sensor.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_with_yaml_config, sensor.DOMAIN, DEFAULT_CONFIG
)
async def test_availability_without_topic(hass, mqtt_mock):
async def test_availability_without_topic(hass, mqtt_mock_entry_with_yaml_config):
"""Test availability without defined availability topic."""
await help_test_availability_without_topic(
hass, mqtt_mock, sensor.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_with_yaml_config, sensor.DOMAIN, DEFAULT_CONFIG
)
async def test_default_availability_payload(hass, mqtt_mock):
async def test_default_availability_payload(hass, mqtt_mock_entry_with_yaml_config):
"""Test availability by default payload with defined topic."""
await help_test_default_availability_payload(
hass, mqtt_mock, sensor.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_with_yaml_config, sensor.DOMAIN, DEFAULT_CONFIG
)
async def test_default_availability_list_payload(hass, mqtt_mock):
async def test_default_availability_list_payload(
hass, mqtt_mock_entry_with_yaml_config
):
"""Test availability by default payload with defined topic."""
await help_test_default_availability_list_payload(
hass, mqtt_mock, sensor.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_with_yaml_config, sensor.DOMAIN, DEFAULT_CONFIG
)
async def test_default_availability_list_payload_all(hass, mqtt_mock):
async def test_default_availability_list_payload_all(
hass, mqtt_mock_entry_with_yaml_config
):
"""Test availability by default payload with defined topic."""
await help_test_default_availability_list_payload_all(
hass, mqtt_mock, sensor.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_with_yaml_config, sensor.DOMAIN, DEFAULT_CONFIG
)
async def test_default_availability_list_payload_any(hass, mqtt_mock):
async def test_default_availability_list_payload_any(
hass, mqtt_mock_entry_with_yaml_config
):
"""Test availability by default payload with defined topic."""
await help_test_default_availability_list_payload_any(
hass, mqtt_mock, sensor.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_with_yaml_config, sensor.DOMAIN, DEFAULT_CONFIG
)
async def test_default_availability_list_single(hass, mqtt_mock, caplog):
async def test_default_availability_list_single(
hass, mqtt_mock_entry_no_yaml_config, caplog
):
"""Test availability list and availability_topic are mutually exclusive."""
await help_test_default_availability_list_single(
hass, mqtt_mock, caplog, sensor.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_no_yaml_config, caplog, sensor.DOMAIN, DEFAULT_CONFIG
)
async def test_custom_availability_payload(hass, mqtt_mock):
async def test_custom_availability_payload(hass, mqtt_mock_entry_with_yaml_config):
"""Test availability by custom payload with defined topic."""
await help_test_custom_availability_payload(
hass, mqtt_mock, sensor.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_with_yaml_config, sensor.DOMAIN, DEFAULT_CONFIG
)
async def test_discovery_update_availability(hass, mqtt_mock):
async def test_discovery_update_availability(hass, mqtt_mock_entry_no_yaml_config):
"""Test availability discovery update."""
await help_test_discovery_update_availability(
hass, mqtt_mock, sensor.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_no_yaml_config, sensor.DOMAIN, DEFAULT_CONFIG
)
async def test_invalid_device_class(hass, mqtt_mock):
async def test_invalid_device_class(hass, mqtt_mock_entry_no_yaml_config):
"""Test device_class option with invalid value."""
assert await async_setup_component(
hass,
@ -600,12 +641,13 @@ async def test_invalid_device_class(hass, mqtt_mock):
},
)
await hass.async_block_till_done()
await mqtt_mock_entry_no_yaml_config()
state = hass.states.get("sensor.test")
assert state is None
async def test_valid_device_class(hass, mqtt_mock):
async def test_valid_device_class(hass, mqtt_mock_entry_with_yaml_config):
"""Test device_class option with valid values."""
assert await async_setup_component(
hass,
@ -623,6 +665,7 @@ async def test_valid_device_class(hass, mqtt_mock):
},
)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("sensor.test_1")
assert state.attributes["device_class"] == "temperature"
@ -630,7 +673,7 @@ async def test_valid_device_class(hass, mqtt_mock):
assert "device_class" not in state.attributes
async def test_invalid_state_class(hass, mqtt_mock):
async def test_invalid_state_class(hass, mqtt_mock_entry_no_yaml_config):
"""Test state_class option with invalid value."""
assert await async_setup_component(
hass,
@ -645,12 +688,13 @@ async def test_invalid_state_class(hass, mqtt_mock):
},
)
await hass.async_block_till_done()
await mqtt_mock_entry_no_yaml_config()
state = hass.states.get("sensor.test")
assert state is None
async def test_valid_state_class(hass, mqtt_mock):
async def test_valid_state_class(hass, mqtt_mock_entry_with_yaml_config):
"""Test state_class option with valid values."""
assert await async_setup_component(
hass,
@ -668,6 +712,7 @@ async def test_valid_state_class(hass, mqtt_mock):
},
)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("sensor.test_1")
assert state.attributes["state_class"] == "measurement"
@ -675,49 +720,61 @@ async def test_valid_state_class(hass, mqtt_mock):
assert "state_class" not in state.attributes
async def test_setting_attribute_via_mqtt_json_message(hass, mqtt_mock):
async def test_setting_attribute_via_mqtt_json_message(
hass, mqtt_mock_entry_with_yaml_config
):
"""Test the setting of attribute via MQTT with JSON payload."""
await help_test_setting_attribute_via_mqtt_json_message(
hass, mqtt_mock, sensor.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_with_yaml_config, sensor.DOMAIN, DEFAULT_CONFIG
)
async def test_setting_blocked_attribute_via_mqtt_json_message(hass, mqtt_mock):
async def test_setting_blocked_attribute_via_mqtt_json_message(
hass, mqtt_mock_entry_no_yaml_config
):
"""Test the setting of attribute via MQTT with JSON payload."""
await help_test_setting_blocked_attribute_via_mqtt_json_message(
hass, mqtt_mock, sensor.DOMAIN, DEFAULT_CONFIG, MQTT_SENSOR_ATTRIBUTES_BLOCKED
hass,
mqtt_mock_entry_no_yaml_config,
sensor.DOMAIN,
DEFAULT_CONFIG,
MQTT_SENSOR_ATTRIBUTES_BLOCKED,
)
async def test_setting_attribute_with_template(hass, mqtt_mock):
async def test_setting_attribute_with_template(hass, mqtt_mock_entry_with_yaml_config):
"""Test the setting of attribute via MQTT with JSON payload."""
await help_test_setting_attribute_with_template(
hass, mqtt_mock, sensor.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_with_yaml_config, sensor.DOMAIN, DEFAULT_CONFIG
)
async def test_update_with_json_attrs_not_dict(hass, mqtt_mock, caplog):
async def test_update_with_json_attrs_not_dict(
hass, mqtt_mock_entry_with_yaml_config, caplog
):
"""Test attributes get extracted from a JSON result."""
await help_test_update_with_json_attrs_not_dict(
hass, mqtt_mock, caplog, sensor.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_with_yaml_config, caplog, sensor.DOMAIN, DEFAULT_CONFIG
)
async def test_update_with_json_attrs_bad_JSON(hass, mqtt_mock, caplog):
async def test_update_with_json_attrs_bad_JSON(
hass, mqtt_mock_entry_with_yaml_config, caplog
):
"""Test attributes get extracted from a JSON result."""
await help_test_update_with_json_attrs_bad_JSON(
hass, mqtt_mock, caplog, sensor.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_with_yaml_config, caplog, sensor.DOMAIN, DEFAULT_CONFIG
)
async def test_discovery_update_attr(hass, mqtt_mock, caplog):
async def test_discovery_update_attr(hass, mqtt_mock_entry_no_yaml_config, caplog):
"""Test update of discovered MQTTAttributes."""
await help_test_discovery_update_attr(
hass, mqtt_mock, caplog, sensor.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_no_yaml_config, caplog, sensor.DOMAIN, DEFAULT_CONFIG
)
async def test_unique_id(hass, mqtt_mock):
async def test_unique_id(hass, mqtt_mock_entry_with_yaml_config):
"""Test unique id option only creates one sensor per unique_id."""
config = {
sensor.DOMAIN: [
@ -735,16 +792,22 @@ async def test_unique_id(hass, mqtt_mock):
},
]
}
await help_test_unique_id(hass, mqtt_mock, sensor.DOMAIN, config)
await help_test_unique_id(
hass, mqtt_mock_entry_with_yaml_config, sensor.DOMAIN, config
)
async def test_discovery_removal_sensor(hass, mqtt_mock, caplog):
async def test_discovery_removal_sensor(hass, mqtt_mock_entry_no_yaml_config, caplog):
"""Test removal of discovered sensor."""
data = '{ "name": "test", "state_topic": "test_topic" }'
await help_test_discovery_removal(hass, mqtt_mock, caplog, sensor.DOMAIN, data)
await help_test_discovery_removal(
hass, mqtt_mock_entry_no_yaml_config, caplog, sensor.DOMAIN, data
)
async def test_discovery_update_sensor_topic_template(hass, mqtt_mock, caplog):
async def test_discovery_update_sensor_topic_template(
hass, mqtt_mock_entry_no_yaml_config, caplog
):
"""Test update of discovered sensor."""
config = {"name": "test", "state_topic": "test_topic"}
config1 = copy.deepcopy(config)
@ -767,7 +830,7 @@ async def test_discovery_update_sensor_topic_template(hass, mqtt_mock, caplog):
await help_test_discovery_update(
hass,
mqtt_mock,
mqtt_mock_entry_no_yaml_config,
caplog,
sensor.DOMAIN,
config1,
@ -777,7 +840,9 @@ async def test_discovery_update_sensor_topic_template(hass, mqtt_mock, caplog):
)
async def test_discovery_update_sensor_template(hass, mqtt_mock, caplog):
async def test_discovery_update_sensor_template(
hass, mqtt_mock_entry_no_yaml_config, caplog
):
"""Test update of discovered sensor."""
config = {"name": "test", "state_topic": "test_topic"}
config1 = copy.deepcopy(config)
@ -798,7 +863,7 @@ async def test_discovery_update_sensor_template(hass, mqtt_mock, caplog):
await help_test_discovery_update(
hass,
mqtt_mock,
mqtt_mock_entry_no_yaml_config,
caplog,
sensor.DOMAIN,
config1,
@ -808,71 +873,79 @@ async def test_discovery_update_sensor_template(hass, mqtt_mock, caplog):
)
async def test_discovery_update_unchanged_sensor(hass, mqtt_mock, caplog):
async def test_discovery_update_unchanged_sensor(
hass, mqtt_mock_entry_no_yaml_config, caplog
):
"""Test update of discovered sensor."""
data1 = '{ "name": "Beer", "state_topic": "test_topic" }'
with patch(
"homeassistant.components.mqtt.sensor.MqttSensor.discovery_update"
) as discovery_update:
await help_test_discovery_update_unchanged(
hass, mqtt_mock, caplog, sensor.DOMAIN, data1, discovery_update
hass,
mqtt_mock_entry_no_yaml_config,
caplog,
sensor.DOMAIN,
data1,
discovery_update,
)
@pytest.mark.no_fail_on_log_exception
async def test_discovery_broken(hass, mqtt_mock, caplog):
async def test_discovery_broken(hass, mqtt_mock_entry_no_yaml_config, caplog):
"""Test handling of bad discovery message."""
data1 = '{ "name": "Beer", "state_topic": "test_topic#" }'
data2 = '{ "name": "Milk", "state_topic": "test_topic" }'
await help_test_discovery_broken(
hass, mqtt_mock, caplog, sensor.DOMAIN, data1, data2
hass, mqtt_mock_entry_no_yaml_config, caplog, sensor.DOMAIN, data1, data2
)
async def test_entity_device_info_with_connection(hass, mqtt_mock):
async def test_entity_device_info_with_connection(hass, mqtt_mock_entry_no_yaml_config):
"""Test MQTT sensor device registry integration."""
await help_test_entity_device_info_with_connection(
hass, mqtt_mock, sensor.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_no_yaml_config, sensor.DOMAIN, DEFAULT_CONFIG
)
async def test_entity_device_info_with_identifier(hass, mqtt_mock):
async def test_entity_device_info_with_identifier(hass, mqtt_mock_entry_no_yaml_config):
"""Test MQTT sensor device registry integration."""
await help_test_entity_device_info_with_identifier(
hass, mqtt_mock, sensor.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_no_yaml_config, sensor.DOMAIN, DEFAULT_CONFIG
)
async def test_entity_device_info_update(hass, mqtt_mock):
async def test_entity_device_info_update(hass, mqtt_mock_entry_no_yaml_config):
"""Test device registry update."""
await help_test_entity_device_info_update(
hass, mqtt_mock, sensor.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_no_yaml_config, sensor.DOMAIN, DEFAULT_CONFIG
)
async def test_entity_device_info_remove(hass, mqtt_mock):
async def test_entity_device_info_remove(hass, mqtt_mock_entry_no_yaml_config):
"""Test device registry remove."""
await help_test_entity_device_info_remove(
hass, mqtt_mock, sensor.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_no_yaml_config, sensor.DOMAIN, DEFAULT_CONFIG
)
async def test_entity_id_update_subscriptions(hass, mqtt_mock):
async def test_entity_id_update_subscriptions(hass, mqtt_mock_entry_with_yaml_config):
"""Test MQTT subscriptions are managed when entity_id is updated."""
await help_test_entity_id_update_subscriptions(
hass, mqtt_mock, sensor.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_with_yaml_config, sensor.DOMAIN, DEFAULT_CONFIG
)
async def test_entity_id_update_discovery_update(hass, mqtt_mock):
async def test_entity_id_update_discovery_update(hass, mqtt_mock_entry_no_yaml_config):
"""Test MQTT discovery update when entity_id is updated."""
await help_test_entity_id_update_discovery_update(
hass, mqtt_mock, sensor.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_no_yaml_config, sensor.DOMAIN, DEFAULT_CONFIG
)
async def test_entity_device_info_with_hub(hass, mqtt_mock):
async def test_entity_device_info_with_hub(hass, mqtt_mock_entry_no_yaml_config):
"""Test MQTT sensor device registry integration."""
await mqtt_mock_entry_no_yaml_config()
registry = dr.async_get(hass)
hub = registry.async_get_or_create(
config_entry_id="123",
@ -899,53 +972,57 @@ async def test_entity_device_info_with_hub(hass, mqtt_mock):
assert device.via_device_id == hub.id
async def test_entity_debug_info(hass, mqtt_mock):
async def test_entity_debug_info(hass, mqtt_mock_entry_no_yaml_config):
"""Test MQTT sensor debug info."""
await help_test_entity_debug_info(hass, mqtt_mock, sensor.DOMAIN, DEFAULT_CONFIG)
await help_test_entity_debug_info(
hass, mqtt_mock_entry_no_yaml_config, sensor.DOMAIN, DEFAULT_CONFIG
)
async def test_entity_debug_info_max_messages(hass, mqtt_mock):
async def test_entity_debug_info_max_messages(hass, mqtt_mock_entry_no_yaml_config):
"""Test MQTT sensor debug info."""
await help_test_entity_debug_info_max_messages(
hass, mqtt_mock, sensor.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_no_yaml_config, sensor.DOMAIN, DEFAULT_CONFIG
)
async def test_entity_debug_info_message(hass, mqtt_mock):
async def test_entity_debug_info_message(hass, mqtt_mock_entry_no_yaml_config):
"""Test MQTT debug info."""
await help_test_entity_debug_info_message(
hass, mqtt_mock, sensor.DOMAIN, DEFAULT_CONFIG, None
hass, mqtt_mock_entry_no_yaml_config, sensor.DOMAIN, DEFAULT_CONFIG, None
)
async def test_entity_debug_info_remove(hass, mqtt_mock):
async def test_entity_debug_info_remove(hass, mqtt_mock_entry_no_yaml_config):
"""Test MQTT sensor debug info."""
await help_test_entity_debug_info_remove(
hass, mqtt_mock, sensor.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_no_yaml_config, sensor.DOMAIN, DEFAULT_CONFIG
)
async def test_entity_debug_info_update_entity_id(hass, mqtt_mock):
async def test_entity_debug_info_update_entity_id(hass, mqtt_mock_entry_no_yaml_config):
"""Test MQTT sensor debug info."""
await help_test_entity_debug_info_update_entity_id(
hass, mqtt_mock, sensor.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_no_yaml_config, sensor.DOMAIN, DEFAULT_CONFIG
)
async def test_entity_disabled_by_default(hass, mqtt_mock):
async def test_entity_disabled_by_default(hass, mqtt_mock_entry_no_yaml_config):
"""Test entity disabled by default."""
await help_test_entity_disabled_by_default(
hass, mqtt_mock, sensor.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_no_yaml_config, sensor.DOMAIN, DEFAULT_CONFIG
)
@pytest.mark.no_fail_on_log_exception
async def test_entity_category(hass, mqtt_mock):
async def test_entity_category(hass, mqtt_mock_entry_no_yaml_config):
"""Test entity category."""
await help_test_entity_category(hass, mqtt_mock, sensor.DOMAIN, DEFAULT_CONFIG)
await help_test_entity_category(
hass, mqtt_mock_entry_no_yaml_config, sensor.DOMAIN, DEFAULT_CONFIG
)
async def test_value_template_with_entity_id(hass, mqtt_mock):
async def test_value_template_with_entity_id(hass, mqtt_mock_entry_with_yaml_config):
"""Test the access to attributes in value_template via the entity_id."""
assert await async_setup_component(
hass,
@ -966,6 +1043,7 @@ async def test_value_template_with_entity_id(hass, mqtt_mock):
},
)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
async_fire_mqtt_message(hass, "test-topic", "100")
state = hass.states.get("sensor.test")
@ -973,11 +1051,13 @@ async def test_value_template_with_entity_id(hass, mqtt_mock):
assert state.state == "101"
async def test_reloadable(hass, mqtt_mock, caplog, tmp_path):
async def test_reloadable(hass, mqtt_mock_entry_with_yaml_config, caplog, tmp_path):
"""Test reloading the MQTT platform."""
domain = sensor.DOMAIN
config = DEFAULT_CONFIG[domain]
await help_test_reloadable(hass, mqtt_mock, caplog, tmp_path, domain, config)
await help_test_reloadable(
hass, mqtt_mock_entry_with_yaml_config, caplog, tmp_path, domain, config
)
async def test_reloadable_late(hass, mqtt_client_mock, caplog, tmp_path):
@ -988,7 +1068,7 @@ async def test_reloadable_late(hass, mqtt_client_mock, caplog, tmp_path):
async def test_cleanup_triggers_and_restoring_state(
hass, mqtt_mock, caplog, tmp_path, freezer
hass, mqtt_mock_entry_with_yaml_config, caplog, tmp_path, freezer
):
"""Test cleanup old triggers at reloading and restoring the state."""
domain = sensor.DOMAIN
@ -1014,6 +1094,7 @@ async def test_cleanup_triggers_and_restoring_state(
{domain: [config1, config2]},
)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
async_fire_mqtt_message(hass, "test-topic1", "100")
state = hass.states.get("sensor.test1")
assert state.state == "38" # 100 °F -> 38 °C
@ -1025,7 +1106,7 @@ async def test_cleanup_triggers_and_restoring_state(
freezer.move_to("2022-02-02 12:01:10+01:00")
await help_test_reload_with_config(
hass, caplog, tmp_path, domain, [config1, config2]
hass, caplog, tmp_path, {domain: [config1, config2]}
)
await hass.async_block_till_done()
@ -1053,7 +1134,7 @@ async def test_cleanup_triggers_and_restoring_state(
async def test_skip_restoring_state_with_over_due_expire_trigger(
hass, mqtt_mock, caplog, freezer
hass, mqtt_mock_entry_with_yaml_config, caplog, freezer
):
"""Test restoring a state with over due expire timer."""
@ -1081,6 +1162,7 @@ async def test_skip_restoring_state_with_over_due_expire_trigger(
):
assert await async_setup_component(hass, domain, {domain: config3})
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
assert "Skip state recovery after reload for sensor.test3" in caplog.text
@ -1092,12 +1174,18 @@ async def test_skip_restoring_state_with_over_due_expire_trigger(
],
)
async def test_encoding_subscribable_topics(
hass, mqtt_mock, caplog, topic, value, attribute, attribute_value
hass,
mqtt_mock_entry_with_yaml_config,
caplog,
topic,
value,
attribute,
attribute_value,
):
"""Test handling of incoming encoded payload."""
await help_test_encoding_subscribable_topics(
hass,
mqtt_mock,
mqtt_mock_entry_with_yaml_config,
caplog,
sensor.DOMAIN,
DEFAULT_CONFIG[sensor.DOMAIN],

View File

@ -70,7 +70,7 @@ async def async_turn_off(hass, entity_id=ENTITY_MATCH_ALL) -> None:
await hass.services.async_call(siren.DOMAIN, SERVICE_TURN_OFF, data, blocking=True)
async def test_controlling_state_via_topic(hass, mqtt_mock):
async def test_controlling_state_via_topic(hass, mqtt_mock_entry_with_yaml_config):
"""Test the controlling state via topic."""
assert await async_setup_component(
hass,
@ -87,6 +87,7 @@ async def test_controlling_state_via_topic(hass, mqtt_mock):
},
)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("siren.test")
assert state.state == STATE_UNKNOWN
@ -103,7 +104,9 @@ async def test_controlling_state_via_topic(hass, mqtt_mock):
assert state.state == STATE_OFF
async def test_sending_mqtt_commands_and_optimistic(hass, mqtt_mock):
async def test_sending_mqtt_commands_and_optimistic(
hass, mqtt_mock_entry_with_yaml_config
):
"""Test the sending MQTT commands in optimistic mode."""
assert await async_setup_component(
hass,
@ -120,6 +123,7 @@ async def test_sending_mqtt_commands_and_optimistic(hass, mqtt_mock):
},
)
await hass.async_block_till_done()
mqtt_mock = await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("siren.test")
assert state.state == STATE_OFF
@ -143,7 +147,9 @@ async def test_sending_mqtt_commands_and_optimistic(hass, mqtt_mock):
assert state.state == STATE_OFF
async def test_controlling_state_via_topic_and_json_message(hass, mqtt_mock, caplog):
async def test_controlling_state_via_topic_and_json_message(
hass, mqtt_mock_entry_with_yaml_config, caplog
):
"""Test the controlling state via topic and JSON message."""
assert await async_setup_component(
hass,
@ -161,6 +167,7 @@ async def test_controlling_state_via_topic_and_json_message(hass, mqtt_mock, cap
},
)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("siren.test")
assert state.state == STATE_UNKNOWN
@ -181,7 +188,7 @@ async def test_controlling_state_via_topic_and_json_message(hass, mqtt_mock, cap
async def test_controlling_state_and_attributes_with_json_message_without_template(
hass, mqtt_mock, caplog
hass, mqtt_mock_entry_with_yaml_config, caplog
):
"""Test the controlling state via topic and JSON message without a value template."""
assert await async_setup_component(
@ -200,6 +207,7 @@ async def test_controlling_state_and_attributes_with_json_message_without_templa
},
)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("siren.test")
assert state.state == STATE_UNKNOWN
@ -262,7 +270,9 @@ async def test_controlling_state_and_attributes_with_json_message_without_templa
)
async def test_filtering_not_supported_attributes_optimistic(hass, mqtt_mock):
async def test_filtering_not_supported_attributes_optimistic(
hass, mqtt_mock_entry_with_yaml_config
):
"""Test setting attributes with support flags optimistic."""
config = {
"platform": "mqtt",
@ -285,6 +295,7 @@ async def test_filtering_not_supported_attributes_optimistic(hass, mqtt_mock):
{siren.DOMAIN: [config1, config2, config3]},
)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
state1 = hass.states.get("siren.test1")
assert state1.state == STATE_OFF
@ -345,7 +356,9 @@ async def test_filtering_not_supported_attributes_optimistic(hass, mqtt_mock):
assert state3.attributes.get(siren.ATTR_VOLUME_LEVEL) == 0.88
async def test_filtering_not_supported_attributes_via_state(hass, mqtt_mock):
async def test_filtering_not_supported_attributes_via_state(
hass, mqtt_mock_entry_with_yaml_config
):
"""Test setting attributes with support flags via state."""
config = {
"platform": "mqtt",
@ -371,6 +384,7 @@ async def test_filtering_not_supported_attributes_via_state(hass, mqtt_mock):
{siren.DOMAIN: [config1, config2, config3]},
)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
state1 = hass.states.get("siren.test1")
assert state1.state == STATE_UNKNOWN
@ -422,21 +436,23 @@ async def test_filtering_not_supported_attributes_via_state(hass, mqtt_mock):
assert state3.attributes.get(siren.ATTR_VOLUME_LEVEL) == 0.88
async def test_availability_when_connection_lost(hass, mqtt_mock):
async def test_availability_when_connection_lost(
hass, mqtt_mock_entry_with_yaml_config
):
"""Test availability after MQTT disconnection."""
await help_test_availability_when_connection_lost(
hass, mqtt_mock, siren.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_with_yaml_config, siren.DOMAIN, DEFAULT_CONFIG
)
async def test_availability_without_topic(hass, mqtt_mock):
async def test_availability_without_topic(hass, mqtt_mock_entry_with_yaml_config):
"""Test availability without defined availability topic."""
await help_test_availability_without_topic(
hass, mqtt_mock, siren.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_with_yaml_config, siren.DOMAIN, DEFAULT_CONFIG
)
async def test_default_availability_payload(hass, mqtt_mock):
async def test_default_availability_payload(hass, mqtt_mock_entry_with_yaml_config):
"""Test availability by default payload with defined topic."""
config = {
siren.DOMAIN: {
@ -450,11 +466,17 @@ async def test_default_availability_payload(hass, mqtt_mock):
}
await help_test_default_availability_payload(
hass, mqtt_mock, siren.DOMAIN, config, True, "state-topic", "1"
hass,
mqtt_mock_entry_with_yaml_config,
siren.DOMAIN,
config,
True,
"state-topic",
"1",
)
async def test_custom_availability_payload(hass, mqtt_mock):
async def test_custom_availability_payload(hass, mqtt_mock_entry_with_yaml_config):
"""Test availability by custom payload with defined topic."""
config = {
siren.DOMAIN: {
@ -468,11 +490,17 @@ async def test_custom_availability_payload(hass, mqtt_mock):
}
await help_test_custom_availability_payload(
hass, mqtt_mock, siren.DOMAIN, config, True, "state-topic", "1"
hass,
mqtt_mock_entry_with_yaml_config,
siren.DOMAIN,
config,
True,
"state-topic",
"1",
)
async def test_custom_state_payload(hass, mqtt_mock):
async def test_custom_state_payload(hass, mqtt_mock_entry_with_yaml_config):
"""Test the state payload."""
assert await async_setup_component(
hass,
@ -491,6 +519,7 @@ async def test_custom_state_payload(hass, mqtt_mock):
},
)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("siren.test")
assert state.state == STATE_UNKNOWN
@ -507,49 +536,57 @@ async def test_custom_state_payload(hass, mqtt_mock):
assert state.state == STATE_OFF
async def test_setting_attribute_via_mqtt_json_message(hass, mqtt_mock):
async def test_setting_attribute_via_mqtt_json_message(
hass, mqtt_mock_entry_with_yaml_config
):
"""Test the setting of attribute via MQTT with JSON payload."""
await help_test_setting_attribute_via_mqtt_json_message(
hass, mqtt_mock, siren.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_with_yaml_config, siren.DOMAIN, DEFAULT_CONFIG
)
async def test_setting_blocked_attribute_via_mqtt_json_message(hass, mqtt_mock):
async def test_setting_blocked_attribute_via_mqtt_json_message(
hass, mqtt_mock_entry_no_yaml_config
):
"""Test the setting of attribute via MQTT with JSON payload."""
await help_test_setting_blocked_attribute_via_mqtt_json_message(
hass, mqtt_mock, siren.DOMAIN, DEFAULT_CONFIG, {}
hass, mqtt_mock_entry_no_yaml_config, siren.DOMAIN, DEFAULT_CONFIG, {}
)
async def test_setting_attribute_with_template(hass, mqtt_mock):
async def test_setting_attribute_with_template(hass, mqtt_mock_entry_with_yaml_config):
"""Test the setting of attribute via MQTT with JSON payload."""
await help_test_setting_attribute_with_template(
hass, mqtt_mock, siren.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_with_yaml_config, siren.DOMAIN, DEFAULT_CONFIG
)
async def test_update_with_json_attrs_not_dict(hass, mqtt_mock, caplog):
async def test_update_with_json_attrs_not_dict(
hass, mqtt_mock_entry_with_yaml_config, caplog
):
"""Test attributes get extracted from a JSON result."""
await help_test_update_with_json_attrs_not_dict(
hass, mqtt_mock, caplog, siren.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_with_yaml_config, caplog, siren.DOMAIN, DEFAULT_CONFIG
)
async def test_update_with_json_attrs_bad_JSON(hass, mqtt_mock, caplog):
async def test_update_with_json_attrs_bad_JSON(
hass, mqtt_mock_entry_with_yaml_config, caplog
):
"""Test attributes get extracted from a JSON result."""
await help_test_update_with_json_attrs_bad_JSON(
hass, mqtt_mock, caplog, siren.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_with_yaml_config, caplog, siren.DOMAIN, DEFAULT_CONFIG
)
async def test_discovery_update_attr(hass, mqtt_mock, caplog):
async def test_discovery_update_attr(hass, mqtt_mock_entry_no_yaml_config, caplog):
"""Test update of discovered MQTTAttributes."""
await help_test_discovery_update_attr(
hass, mqtt_mock, caplog, siren.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_no_yaml_config, caplog, siren.DOMAIN, DEFAULT_CONFIG
)
async def test_unique_id(hass, mqtt_mock):
async def test_unique_id(hass, mqtt_mock_entry_with_yaml_config):
"""Test unique id option only creates one siren per unique_id."""
config = {
siren.DOMAIN: [
@ -569,20 +606,26 @@ async def test_unique_id(hass, mqtt_mock):
},
]
}
await help_test_unique_id(hass, mqtt_mock, siren.DOMAIN, config)
await help_test_unique_id(
hass, mqtt_mock_entry_with_yaml_config, siren.DOMAIN, config
)
async def test_discovery_removal_siren(hass, mqtt_mock, caplog):
async def test_discovery_removal_siren(hass, mqtt_mock_entry_no_yaml_config, caplog):
"""Test removal of discovered siren."""
data = (
'{ "name": "test",'
' "state_topic": "test_topic",'
' "command_topic": "test_topic" }'
)
await help_test_discovery_removal(hass, mqtt_mock, caplog, siren.DOMAIN, data)
await help_test_discovery_removal(
hass, mqtt_mock_entry_no_yaml_config, caplog, siren.DOMAIN, data
)
async def test_discovery_update_siren_topic_template(hass, mqtt_mock, caplog):
async def test_discovery_update_siren_topic_template(
hass, mqtt_mock_entry_no_yaml_config, caplog
):
"""Test update of discovered siren."""
config1 = copy.deepcopy(DEFAULT_CONFIG[siren.DOMAIN])
config2 = copy.deepcopy(DEFAULT_CONFIG[siren.DOMAIN])
@ -607,7 +650,7 @@ async def test_discovery_update_siren_topic_template(hass, mqtt_mock, caplog):
await help_test_discovery_update(
hass,
mqtt_mock,
mqtt_mock_entry_no_yaml_config,
caplog,
siren.DOMAIN,
config1,
@ -617,7 +660,9 @@ async def test_discovery_update_siren_topic_template(hass, mqtt_mock, caplog):
)
async def test_discovery_update_siren_template(hass, mqtt_mock, caplog):
async def test_discovery_update_siren_template(
hass, mqtt_mock_entry_no_yaml_config, caplog
):
"""Test update of discovered siren."""
config1 = copy.deepcopy(DEFAULT_CONFIG[siren.DOMAIN])
config2 = copy.deepcopy(DEFAULT_CONFIG[siren.DOMAIN])
@ -640,7 +685,7 @@ async def test_discovery_update_siren_template(hass, mqtt_mock, caplog):
await help_test_discovery_update(
hass,
mqtt_mock,
mqtt_mock_entry_no_yaml_config,
caplog,
siren.DOMAIN,
config1,
@ -650,7 +695,7 @@ async def test_discovery_update_siren_template(hass, mqtt_mock, caplog):
)
async def test_command_templates(hass, mqtt_mock, caplog):
async def test_command_templates(hass, mqtt_mock_entry_with_yaml_config, caplog):
"""Test siren with command templates optimistic."""
config1 = copy.deepcopy(DEFAULT_CONFIG[siren.DOMAIN])
config1["name"] = "Beer"
@ -669,6 +714,7 @@ async def test_command_templates(hass, mqtt_mock, caplog):
{siren.DOMAIN: [config1, config2]},
)
await hass.async_block_till_done()
mqtt_mock = await mqtt_mock_entry_with_yaml_config()
state1 = hass.states.get("siren.beer")
assert state1.state == STATE_OFF
@ -729,7 +775,9 @@ async def test_command_templates(hass, mqtt_mock, caplog):
mqtt_mock.reset_mock()
async def test_discovery_update_unchanged_siren(hass, mqtt_mock, caplog):
async def test_discovery_update_unchanged_siren(
hass, mqtt_mock_entry_no_yaml_config, caplog
):
"""Test update of discovered siren."""
data1 = (
'{ "name": "Beer",'
@ -741,12 +789,17 @@ async def test_discovery_update_unchanged_siren(hass, mqtt_mock, caplog):
"homeassistant.components.mqtt.siren.MqttSiren.discovery_update"
) as discovery_update:
await help_test_discovery_update_unchanged(
hass, mqtt_mock, caplog, siren.DOMAIN, data1, discovery_update
hass,
mqtt_mock_entry_no_yaml_config,
caplog,
siren.DOMAIN,
data1,
discovery_update,
)
@pytest.mark.no_fail_on_log_exception
async def test_discovery_broken(hass, mqtt_mock, caplog):
async def test_discovery_broken(hass, mqtt_mock_entry_no_yaml_config, caplog):
"""Test handling of bad discovery message."""
data1 = '{ "name": "Beer" }'
data2 = (
@ -755,57 +808,57 @@ async def test_discovery_broken(hass, mqtt_mock, caplog):
' "command_topic": "test_topic" }'
)
await help_test_discovery_broken(
hass, mqtt_mock, caplog, siren.DOMAIN, data1, data2
hass, mqtt_mock_entry_no_yaml_config, caplog, siren.DOMAIN, data1, data2
)
async def test_entity_device_info_with_connection(hass, mqtt_mock):
async def test_entity_device_info_with_connection(hass, mqtt_mock_entry_no_yaml_config):
"""Test MQTT siren device registry integration."""
await help_test_entity_device_info_with_connection(
hass, mqtt_mock, siren.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_no_yaml_config, siren.DOMAIN, DEFAULT_CONFIG
)
async def test_entity_device_info_with_identifier(hass, mqtt_mock):
async def test_entity_device_info_with_identifier(hass, mqtt_mock_entry_no_yaml_config):
"""Test MQTT siren device registry integration."""
await help_test_entity_device_info_with_identifier(
hass, mqtt_mock, siren.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_no_yaml_config, siren.DOMAIN, DEFAULT_CONFIG
)
async def test_entity_device_info_update(hass, mqtt_mock):
async def test_entity_device_info_update(hass, mqtt_mock_entry_no_yaml_config):
"""Test device registry update."""
await help_test_entity_device_info_update(
hass, mqtt_mock, siren.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_no_yaml_config, siren.DOMAIN, DEFAULT_CONFIG
)
async def test_entity_device_info_remove(hass, mqtt_mock):
async def test_entity_device_info_remove(hass, mqtt_mock_entry_no_yaml_config):
"""Test device registry remove."""
await help_test_entity_device_info_remove(
hass, mqtt_mock, siren.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_no_yaml_config, siren.DOMAIN, DEFAULT_CONFIG
)
async def test_entity_id_update_subscriptions(hass, mqtt_mock):
async def test_entity_id_update_subscriptions(hass, mqtt_mock_entry_with_yaml_config):
"""Test MQTT subscriptions are managed when entity_id is updated."""
await help_test_entity_id_update_subscriptions(
hass, mqtt_mock, siren.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_with_yaml_config, siren.DOMAIN, DEFAULT_CONFIG
)
async def test_entity_id_update_discovery_update(hass, mqtt_mock):
async def test_entity_id_update_discovery_update(hass, mqtt_mock_entry_no_yaml_config):
"""Test MQTT discovery update when entity_id is updated."""
await help_test_entity_id_update_discovery_update(
hass, mqtt_mock, siren.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_no_yaml_config, siren.DOMAIN, DEFAULT_CONFIG
)
async def test_entity_debug_info_message(hass, mqtt_mock):
async def test_entity_debug_info_message(hass, mqtt_mock_entry_no_yaml_config):
"""Test MQTT debug info."""
await help_test_entity_debug_info_message(
hass,
mqtt_mock,
mqtt_mock_entry_no_yaml_config,
siren.DOMAIN,
DEFAULT_CONFIG,
siren.SERVICE_TURN_ON,
@ -834,7 +887,7 @@ async def test_entity_debug_info_message(hass, mqtt_mock):
)
async def test_publishing_with_custom_encoding(
hass,
mqtt_mock,
mqtt_mock_entry_with_yaml_config,
caplog,
service,
topic,
@ -849,7 +902,7 @@ async def test_publishing_with_custom_encoding(
await help_test_publishing_with_custom_encoding(
hass,
mqtt_mock,
mqtt_mock_entry_with_yaml_config,
caplog,
domain,
config,
@ -861,11 +914,13 @@ async def test_publishing_with_custom_encoding(
)
async def test_reloadable(hass, mqtt_mock, caplog, tmp_path):
async def test_reloadable(hass, mqtt_mock_entry_with_yaml_config, caplog, tmp_path):
"""Test reloading the MQTT platform."""
domain = siren.DOMAIN
config = DEFAULT_CONFIG[domain]
await help_test_reloadable(hass, mqtt_mock, caplog, tmp_path, domain, config)
await help_test_reloadable(
hass, mqtt_mock_entry_with_yaml_config, caplog, tmp_path, domain, config
)
async def test_reloadable_late(hass, mqtt_client_mock, caplog, tmp_path):
@ -882,12 +937,18 @@ async def test_reloadable_late(hass, mqtt_client_mock, caplog, tmp_path):
],
)
async def test_encoding_subscribable_topics(
hass, mqtt_mock, caplog, topic, value, attribute, attribute_value
hass,
mqtt_mock_entry_with_yaml_config,
caplog,
topic,
value,
attribute,
attribute_value,
):
"""Test handling of incoming encoded payload."""
await help_test_encoding_subscribable_topics(
hass,
mqtt_mock,
mqtt_mock_entry_with_yaml_config,
caplog,
siren.DOMAIN,
DEFAULT_CONFIG[siren.DOMAIN],

View File

@ -6,7 +6,7 @@ from unittest.mock import patch
import pytest
from homeassistant.components import vacuum
from homeassistant.components.mqtt import CONF_COMMAND_TOPIC, CONF_STATE_TOPIC
from homeassistant.components.mqtt.const import CONF_COMMAND_TOPIC, CONF_STATE_TOPIC
from homeassistant.components.mqtt.vacuum import CONF_SCHEMA, schema_state as mqttvacuum
from homeassistant.components.mqtt.vacuum.const import MQTT_VACUUM_ATTRIBUTES_BLOCKED
from homeassistant.components.mqtt.vacuum.schema import services_to_strings
@ -87,12 +87,13 @@ DEFAULT_CONFIG_2 = {
}
async def test_default_supported_features(hass, mqtt_mock):
async def test_default_supported_features(hass, mqtt_mock_entry_with_yaml_config):
"""Test that the correct supported features."""
assert await async_setup_component(
hass, vacuum.DOMAIN, {vacuum.DOMAIN: DEFAULT_CONFIG}
)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
entity = hass.states.get("vacuum.mqtttest")
entity_features = entity.attributes.get(mqttvacuum.CONF_SUPPORTED_FEATURES, 0)
assert sorted(services_to_strings(entity_features, SERVICE_TO_STRING)) == sorted(
@ -100,7 +101,7 @@ async def test_default_supported_features(hass, mqtt_mock):
)
async def test_all_commands(hass, mqtt_mock):
async def test_all_commands(hass, mqtt_mock_entry_with_yaml_config):
"""Test simple commands send to the vacuum."""
config = deepcopy(DEFAULT_CONFIG)
config[mqttvacuum.CONF_SUPPORTED_FEATURES] = services_to_strings(
@ -109,6 +110,7 @@ async def test_all_commands(hass, mqtt_mock):
assert await async_setup_component(hass, vacuum.DOMAIN, {vacuum.DOMAIN: config})
await hass.async_block_till_done()
mqtt_mock = await mqtt_mock_entry_with_yaml_config()
await hass.services.async_call(
DOMAIN, SERVICE_START, {"entity_id": ENTITY_MATCH_ALL}, blocking=True
@ -171,7 +173,9 @@ async def test_all_commands(hass, mqtt_mock):
}
async def test_commands_without_supported_features(hass, mqtt_mock):
async def test_commands_without_supported_features(
hass, mqtt_mock_entry_with_yaml_config
):
"""Test commands which are not supported by the vacuum."""
config = deepcopy(DEFAULT_CONFIG)
services = mqttvacuum.STRING_TO_SERVICE["status"]
@ -181,6 +185,7 @@ async def test_commands_without_supported_features(hass, mqtt_mock):
assert await async_setup_component(hass, vacuum.DOMAIN, {vacuum.DOMAIN: config})
await hass.async_block_till_done()
mqtt_mock = await mqtt_mock_entry_with_yaml_config()
await hass.services.async_call(
DOMAIN, SERVICE_START, {"entity_id": ENTITY_MATCH_ALL}, blocking=True
@ -228,7 +233,7 @@ async def test_commands_without_supported_features(hass, mqtt_mock):
mqtt_mock.async_publish.assert_not_called()
async def test_status(hass, mqtt_mock):
async def test_status(hass, mqtt_mock_entry_with_yaml_config):
"""Test status updates from the vacuum."""
config = deepcopy(DEFAULT_CONFIG)
config[mqttvacuum.CONF_SUPPORTED_FEATURES] = services_to_strings(
@ -237,6 +242,7 @@ async def test_status(hass, mqtt_mock):
assert await async_setup_component(hass, vacuum.DOMAIN, {vacuum.DOMAIN: config})
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("vacuum.mqtttest")
assert state.state == STATE_UNKNOWN
@ -272,7 +278,7 @@ async def test_status(hass, mqtt_mock):
assert state.state == STATE_UNKNOWN
async def test_no_fan_vacuum(hass, mqtt_mock):
async def test_no_fan_vacuum(hass, mqtt_mock_entry_with_yaml_config):
"""Test status updates from the vacuum when fan is not supported."""
config = deepcopy(DEFAULT_CONFIG)
del config[mqttvacuum.CONF_FAN_SPEED_LIST]
@ -282,6 +288,7 @@ async def test_no_fan_vacuum(hass, mqtt_mock):
assert await async_setup_component(hass, vacuum.DOMAIN, {vacuum.DOMAIN: config})
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
message = """{
"battery_level": 54,
@ -323,7 +330,7 @@ async def test_no_fan_vacuum(hass, mqtt_mock):
@pytest.mark.no_fail_on_log_exception
async def test_status_invalid_json(hass, mqtt_mock):
async def test_status_invalid_json(hass, mqtt_mock_entry_with_yaml_config):
"""Test to make sure nothing breaks if the vacuum sends bad JSON."""
config = deepcopy(DEFAULT_CONFIG)
config[mqttvacuum.CONF_SUPPORTED_FEATURES] = services_to_strings(
@ -332,83 +339,98 @@ async def test_status_invalid_json(hass, mqtt_mock):
assert await async_setup_component(hass, vacuum.DOMAIN, {vacuum.DOMAIN: config})
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
async_fire_mqtt_message(hass, "vacuum/state", '{"asdfasas false}')
state = hass.states.get("vacuum.mqtttest")
assert state.state == STATE_UNKNOWN
async def test_availability_when_connection_lost(hass, mqtt_mock):
async def test_availability_when_connection_lost(
hass, mqtt_mock_entry_with_yaml_config
):
"""Test availability after MQTT disconnection."""
await help_test_availability_when_connection_lost(
hass, mqtt_mock, vacuum.DOMAIN, DEFAULT_CONFIG_2
hass, mqtt_mock_entry_with_yaml_config, vacuum.DOMAIN, DEFAULT_CONFIG_2
)
async def test_availability_without_topic(hass, mqtt_mock):
async def test_availability_without_topic(hass, mqtt_mock_entry_with_yaml_config):
"""Test availability without defined availability topic."""
await help_test_availability_without_topic(
hass, mqtt_mock, vacuum.DOMAIN, DEFAULT_CONFIG_2
hass, mqtt_mock_entry_with_yaml_config, vacuum.DOMAIN, DEFAULT_CONFIG_2
)
async def test_default_availability_payload(hass, mqtt_mock):
async def test_default_availability_payload(hass, mqtt_mock_entry_with_yaml_config):
"""Test availability by default payload with defined topic."""
await help_test_default_availability_payload(
hass, mqtt_mock, vacuum.DOMAIN, DEFAULT_CONFIG_2
hass, mqtt_mock_entry_with_yaml_config, vacuum.DOMAIN, DEFAULT_CONFIG_2
)
async def test_custom_availability_payload(hass, mqtt_mock):
async def test_custom_availability_payload(hass, mqtt_mock_entry_with_yaml_config):
"""Test availability by custom payload with defined topic."""
await help_test_custom_availability_payload(
hass, mqtt_mock, vacuum.DOMAIN, DEFAULT_CONFIG_2
hass, mqtt_mock_entry_with_yaml_config, vacuum.DOMAIN, DEFAULT_CONFIG_2
)
async def test_setting_attribute_via_mqtt_json_message(hass, mqtt_mock):
async def test_setting_attribute_via_mqtt_json_message(
hass, mqtt_mock_entry_with_yaml_config
):
"""Test the setting of attribute via MQTT with JSON payload."""
await help_test_setting_attribute_via_mqtt_json_message(
hass, mqtt_mock, vacuum.DOMAIN, DEFAULT_CONFIG_2
hass, mqtt_mock_entry_with_yaml_config, vacuum.DOMAIN, DEFAULT_CONFIG_2
)
async def test_setting_blocked_attribute_via_mqtt_json_message(hass, mqtt_mock):
async def test_setting_blocked_attribute_via_mqtt_json_message(
hass, mqtt_mock_entry_no_yaml_config
):
"""Test the setting of attribute via MQTT with JSON payload."""
await help_test_setting_blocked_attribute_via_mqtt_json_message(
hass, mqtt_mock, vacuum.DOMAIN, DEFAULT_CONFIG_2, MQTT_VACUUM_ATTRIBUTES_BLOCKED
hass,
mqtt_mock_entry_no_yaml_config,
vacuum.DOMAIN,
DEFAULT_CONFIG_2,
MQTT_VACUUM_ATTRIBUTES_BLOCKED,
)
async def test_setting_attribute_with_template(hass, mqtt_mock):
async def test_setting_attribute_with_template(hass, mqtt_mock_entry_with_yaml_config):
"""Test the setting of attribute via MQTT with JSON payload."""
await help_test_setting_attribute_with_template(
hass, mqtt_mock, vacuum.DOMAIN, DEFAULT_CONFIG_2
hass, mqtt_mock_entry_with_yaml_config, vacuum.DOMAIN, DEFAULT_CONFIG_2
)
async def test_update_with_json_attrs_not_dict(hass, mqtt_mock, caplog):
async def test_update_with_json_attrs_not_dict(
hass, mqtt_mock_entry_with_yaml_config, caplog
):
"""Test attributes get extracted from a JSON result."""
await help_test_update_with_json_attrs_not_dict(
hass, mqtt_mock, caplog, vacuum.DOMAIN, DEFAULT_CONFIG_2
hass, mqtt_mock_entry_with_yaml_config, caplog, vacuum.DOMAIN, DEFAULT_CONFIG_2
)
async def test_update_with_json_attrs_bad_json(hass, mqtt_mock, caplog):
async def test_update_with_json_attrs_bad_json(
hass, mqtt_mock_entry_with_yaml_config, caplog
):
"""Test attributes get extracted from a JSON result."""
await help_test_update_with_json_attrs_bad_JSON(
hass, mqtt_mock, caplog, vacuum.DOMAIN, DEFAULT_CONFIG_2
hass, mqtt_mock_entry_with_yaml_config, caplog, vacuum.DOMAIN, DEFAULT_CONFIG_2
)
async def test_discovery_update_attr(hass, mqtt_mock, caplog):
async def test_discovery_update_attr(hass, mqtt_mock_entry_no_yaml_config, caplog):
"""Test update of discovered MQTTAttributes."""
await help_test_discovery_update_attr(
hass, mqtt_mock, caplog, vacuum.DOMAIN, DEFAULT_CONFIG_2
hass, mqtt_mock_entry_no_yaml_config, caplog, vacuum.DOMAIN, DEFAULT_CONFIG_2
)
async def test_unique_id(hass, mqtt_mock):
async def test_unique_id(hass, mqtt_mock_entry_with_yaml_config):
"""Test unique id option only creates one vacuum per unique_id."""
config = {
vacuum.DOMAIN: [
@ -428,92 +450,103 @@ async def test_unique_id(hass, mqtt_mock):
},
]
}
await help_test_unique_id(hass, mqtt_mock, vacuum.DOMAIN, config)
await help_test_unique_id(
hass, mqtt_mock_entry_with_yaml_config, vacuum.DOMAIN, config
)
async def test_discovery_removal_vacuum(hass, mqtt_mock, caplog):
async def test_discovery_removal_vacuum(hass, mqtt_mock_entry_no_yaml_config, caplog):
"""Test removal of discovered vacuum."""
data = '{ "schema": "state", "name": "test", "command_topic": "test_topic"}'
await help_test_discovery_removal(hass, mqtt_mock, caplog, vacuum.DOMAIN, data)
await help_test_discovery_removal(
hass, mqtt_mock_entry_no_yaml_config, caplog, vacuum.DOMAIN, data
)
async def test_discovery_update_vacuum(hass, mqtt_mock, caplog):
async def test_discovery_update_vacuum(hass, mqtt_mock_entry_no_yaml_config, caplog):
"""Test update of discovered vacuum."""
config1 = {"schema": "state", "name": "Beer", "command_topic": "test_topic"}
config2 = {"schema": "state", "name": "Milk", "command_topic": "test_topic"}
await help_test_discovery_update(
hass, mqtt_mock, caplog, vacuum.DOMAIN, config1, config2
hass, mqtt_mock_entry_no_yaml_config, caplog, vacuum.DOMAIN, config1, config2
)
async def test_discovery_update_unchanged_vacuum(hass, mqtt_mock, caplog):
async def test_discovery_update_unchanged_vacuum(
hass, mqtt_mock_entry_no_yaml_config, caplog
):
"""Test update of discovered vacuum."""
data1 = '{ "schema": "state", "name": "Beer", "command_topic": "test_topic"}'
with patch(
"homeassistant.components.mqtt.vacuum.schema_state.MqttStateVacuum.discovery_update"
) as discovery_update:
await help_test_discovery_update_unchanged(
hass, mqtt_mock, caplog, vacuum.DOMAIN, data1, discovery_update
hass,
mqtt_mock_entry_no_yaml_config,
caplog,
vacuum.DOMAIN,
data1,
discovery_update,
)
@pytest.mark.no_fail_on_log_exception
async def test_discovery_broken(hass, mqtt_mock, caplog):
async def test_discovery_broken(hass, mqtt_mock_entry_no_yaml_config, caplog):
"""Test handling of bad discovery message."""
data1 = '{ "schema": "state", "name": "Beer", "command_topic": "test_topic#"}'
data2 = '{ "schema": "state", "name": "Milk", "command_topic": "test_topic"}'
await help_test_discovery_broken(
hass, mqtt_mock, caplog, vacuum.DOMAIN, data1, data2
hass, mqtt_mock_entry_no_yaml_config, caplog, vacuum.DOMAIN, data1, data2
)
async def test_entity_device_info_with_connection(hass, mqtt_mock):
async def test_entity_device_info_with_connection(hass, mqtt_mock_entry_no_yaml_config):
"""Test MQTT vacuum device registry integration."""
await help_test_entity_device_info_with_connection(
hass, mqtt_mock, vacuum.DOMAIN, DEFAULT_CONFIG_2
hass, mqtt_mock_entry_no_yaml_config, vacuum.DOMAIN, DEFAULT_CONFIG_2
)
async def test_entity_device_info_with_identifier(hass, mqtt_mock):
async def test_entity_device_info_with_identifier(hass, mqtt_mock_entry_no_yaml_config):
"""Test MQTT vacuum device registry integration."""
await help_test_entity_device_info_with_identifier(
hass, mqtt_mock, vacuum.DOMAIN, DEFAULT_CONFIG_2
hass, mqtt_mock_entry_no_yaml_config, vacuum.DOMAIN, DEFAULT_CONFIG_2
)
async def test_entity_device_info_update(hass, mqtt_mock):
async def test_entity_device_info_update(hass, mqtt_mock_entry_no_yaml_config):
"""Test device registry update."""
await help_test_entity_device_info_update(
hass, mqtt_mock, vacuum.DOMAIN, DEFAULT_CONFIG_2
hass, mqtt_mock_entry_no_yaml_config, vacuum.DOMAIN, DEFAULT_CONFIG_2
)
async def test_entity_device_info_remove(hass, mqtt_mock):
async def test_entity_device_info_remove(hass, mqtt_mock_entry_no_yaml_config):
"""Test device registry remove."""
await help_test_entity_device_info_remove(
hass, mqtt_mock, vacuum.DOMAIN, DEFAULT_CONFIG_2
hass, mqtt_mock_entry_no_yaml_config, vacuum.DOMAIN, DEFAULT_CONFIG_2
)
async def test_entity_id_update_subscriptions(hass, mqtt_mock):
async def test_entity_id_update_subscriptions(hass, mqtt_mock_entry_with_yaml_config):
"""Test MQTT subscriptions are managed when entity_id is updated."""
await help_test_entity_id_update_subscriptions(
hass, mqtt_mock, vacuum.DOMAIN, DEFAULT_CONFIG_2
hass, mqtt_mock_entry_with_yaml_config, vacuum.DOMAIN, DEFAULT_CONFIG_2
)
async def test_entity_id_update_discovery_update(hass, mqtt_mock):
async def test_entity_id_update_discovery_update(hass, mqtt_mock_entry_no_yaml_config):
"""Test MQTT discovery update when entity_id is updated."""
await help_test_entity_id_update_discovery_update(
hass, mqtt_mock, vacuum.DOMAIN, DEFAULT_CONFIG_2
hass, mqtt_mock_entry_no_yaml_config, vacuum.DOMAIN, DEFAULT_CONFIG_2
)
async def test_entity_debug_info_message(hass, mqtt_mock):
async def test_entity_debug_info_message(hass, mqtt_mock_entry_no_yaml_config):
"""Test MQTT debug info."""
await help_test_entity_debug_info_message(
hass,
mqtt_mock,
mqtt_mock_entry_no_yaml_config,
vacuum.DOMAIN,
DEFAULT_CONFIG_2,
vacuum.SERVICE_START,
@ -564,7 +597,7 @@ async def test_entity_debug_info_message(hass, mqtt_mock):
)
async def test_publishing_with_custom_encoding(
hass,
mqtt_mock,
mqtt_mock_entry_with_yaml_config,
caplog,
service,
topic,
@ -590,7 +623,7 @@ async def test_publishing_with_custom_encoding(
await help_test_publishing_with_custom_encoding(
hass,
mqtt_mock,
mqtt_mock_entry_with_yaml_config,
caplog,
domain,
config,
@ -602,11 +635,13 @@ async def test_publishing_with_custom_encoding(
)
async def test_reloadable(hass, mqtt_mock, caplog, tmp_path):
async def test_reloadable(hass, mqtt_mock_entry_with_yaml_config, caplog, tmp_path):
"""Test reloading the MQTT platform."""
domain = vacuum.DOMAIN
config = DEFAULT_CONFIG
await help_test_reloadable(hass, mqtt_mock, caplog, tmp_path, domain, config)
await help_test_reloadable(
hass, mqtt_mock_entry_with_yaml_config, caplog, tmp_path, domain, config
)
async def test_reloadable_late(hass, mqtt_client_mock, caplog, tmp_path):
@ -634,12 +669,18 @@ async def test_reloadable_late(hass, mqtt_client_mock, caplog, tmp_path):
],
)
async def test_encoding_subscribable_topics(
hass, mqtt_mock, caplog, topic, value, attribute, attribute_value
hass,
mqtt_mock_entry_with_yaml_config,
caplog,
topic,
value,
attribute,
attribute_value,
):
"""Test handling of incoming encoded payload."""
await help_test_encoding_subscribable_topics(
hass,
mqtt_mock,
mqtt_mock_entry_with_yaml_config,
caplog,
vacuum.DOMAIN,
DEFAULT_CONFIG,

View File

@ -11,8 +11,9 @@ from homeassistant.core import callback
from tests.common import async_fire_mqtt_message
async def test_subscribe_topics(hass, mqtt_mock, caplog):
async def test_subscribe_topics(hass, mqtt_mock_entry_no_yaml_config, caplog):
"""Test subscription to topics."""
await mqtt_mock_entry_no_yaml_config()
calls1 = []
@callback
@ -59,8 +60,9 @@ async def test_subscribe_topics(hass, mqtt_mock, caplog):
assert len(calls2) == 1
async def test_modify_topics(hass, mqtt_mock, caplog):
async def test_modify_topics(hass, mqtt_mock_entry_no_yaml_config, caplog):
"""Test modification of topics."""
await mqtt_mock_entry_no_yaml_config()
calls1 = []
@callback
@ -121,8 +123,9 @@ async def test_modify_topics(hass, mqtt_mock, caplog):
assert len(calls2) == 1
async def test_qos_encoding_default(hass, mqtt_mock, caplog):
async def test_qos_encoding_default(hass, mqtt_mock_entry_no_yaml_config, caplog):
"""Test default qos and encoding."""
mqtt_mock = await mqtt_mock_entry_no_yaml_config()
@callback
def msg_callback(*args):
@ -136,11 +139,12 @@ async def test_qos_encoding_default(hass, mqtt_mock, caplog):
{"test_topic1": {"topic": "test-topic1", "msg_callback": msg_callback}},
)
await async_subscribe_topics(hass, sub_state)
mqtt_mock.async_subscribe.assert_called_once_with("test-topic1", ANY, 0, "utf-8")
mqtt_mock.async_subscribe.assert_called_with("test-topic1", ANY, 0, "utf-8")
async def test_qos_encoding_custom(hass, mqtt_mock, caplog):
async def test_qos_encoding_custom(hass, mqtt_mock_entry_no_yaml_config, caplog):
"""Test custom qos and encoding."""
mqtt_mock = await mqtt_mock_entry_no_yaml_config()
@callback
def msg_callback(*args):
@ -161,11 +165,12 @@ async def test_qos_encoding_custom(hass, mqtt_mock, caplog):
},
)
await async_subscribe_topics(hass, sub_state)
mqtt_mock.async_subscribe.assert_called_once_with("test-topic1", ANY, 1, "utf-16")
mqtt_mock.async_subscribe.assert_called_with("test-topic1", ANY, 1, "utf-16")
async def test_no_change(hass, mqtt_mock, caplog):
async def test_no_change(hass, mqtt_mock_entry_no_yaml_config, caplog):
"""Test subscription to topics without change."""
mqtt_mock = await mqtt_mock_entry_no_yaml_config()
calls = []

View File

@ -53,7 +53,7 @@ DEFAULT_CONFIG = {
}
async def test_controlling_state_via_topic(hass, mqtt_mock):
async def test_controlling_state_via_topic(hass, mqtt_mock_entry_with_yaml_config):
"""Test the controlling state via topic."""
assert await async_setup_component(
hass,
@ -71,6 +71,7 @@ async def test_controlling_state_via_topic(hass, mqtt_mock):
},
)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("switch.test")
assert state.state == STATE_UNKNOWN
@ -93,7 +94,9 @@ async def test_controlling_state_via_topic(hass, mqtt_mock):
assert state.state == STATE_UNKNOWN
async def test_sending_mqtt_commands_and_optimistic(hass, mqtt_mock):
async def test_sending_mqtt_commands_and_optimistic(
hass, mqtt_mock_entry_with_yaml_config
):
"""Test the sending MQTT commands in optimistic mode."""
fake_state = ha.State("switch.test", "on")
@ -116,6 +119,7 @@ async def test_sending_mqtt_commands_and_optimistic(hass, mqtt_mock):
},
)
await hass.async_block_till_done()
mqtt_mock = await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("switch.test")
assert state.state == STATE_ON
@ -139,7 +143,9 @@ async def test_sending_mqtt_commands_and_optimistic(hass, mqtt_mock):
assert state.state == STATE_OFF
async def test_sending_inital_state_and_optimistic(hass, mqtt_mock):
async def test_sending_inital_state_and_optimistic(
hass, mqtt_mock_entry_with_yaml_config
):
"""Test the initial state in optimistic mode."""
assert await async_setup_component(
hass,
@ -153,13 +159,16 @@ async def test_sending_inital_state_and_optimistic(hass, mqtt_mock):
},
)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("switch.test")
assert state.state == STATE_UNKNOWN
assert state.attributes.get(ATTR_ASSUMED_STATE)
async def test_controlling_state_via_topic_and_json_message(hass, mqtt_mock):
async def test_controlling_state_via_topic_and_json_message(
hass, mqtt_mock_entry_with_yaml_config
):
"""Test the controlling state via topic and JSON message."""
assert await async_setup_component(
hass,
@ -177,6 +186,7 @@ async def test_controlling_state_via_topic_and_json_message(hass, mqtt_mock):
},
)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("switch.test")
assert state.state == STATE_UNKNOWN
@ -197,21 +207,23 @@ async def test_controlling_state_via_topic_and_json_message(hass, mqtt_mock):
assert state.state == STATE_UNKNOWN
async def test_availability_when_connection_lost(hass, mqtt_mock):
async def test_availability_when_connection_lost(
hass, mqtt_mock_entry_with_yaml_config
):
"""Test availability after MQTT disconnection."""
await help_test_availability_when_connection_lost(
hass, mqtt_mock, switch.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_with_yaml_config, switch.DOMAIN, DEFAULT_CONFIG
)
async def test_availability_without_topic(hass, mqtt_mock):
async def test_availability_without_topic(hass, mqtt_mock_entry_with_yaml_config):
"""Test availability without defined availability topic."""
await help_test_availability_without_topic(
hass, mqtt_mock, switch.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_with_yaml_config, switch.DOMAIN, DEFAULT_CONFIG
)
async def test_default_availability_payload(hass, mqtt_mock):
async def test_default_availability_payload(hass, mqtt_mock_entry_with_yaml_config):
"""Test availability by default payload with defined topic."""
config = {
switch.DOMAIN: {
@ -225,11 +237,17 @@ async def test_default_availability_payload(hass, mqtt_mock):
}
await help_test_default_availability_payload(
hass, mqtt_mock, switch.DOMAIN, config, True, "state-topic", "1"
hass,
mqtt_mock_entry_with_yaml_config,
switch.DOMAIN,
config,
True,
"state-topic",
"1",
)
async def test_custom_availability_payload(hass, mqtt_mock):
async def test_custom_availability_payload(hass, mqtt_mock_entry_with_yaml_config):
"""Test availability by custom payload with defined topic."""
config = {
switch.DOMAIN: {
@ -243,11 +261,17 @@ async def test_custom_availability_payload(hass, mqtt_mock):
}
await help_test_custom_availability_payload(
hass, mqtt_mock, switch.DOMAIN, config, True, "state-topic", "1"
hass,
mqtt_mock_entry_with_yaml_config,
switch.DOMAIN,
config,
True,
"state-topic",
"1",
)
async def test_custom_state_payload(hass, mqtt_mock):
async def test_custom_state_payload(hass, mqtt_mock_entry_with_yaml_config):
"""Test the state payload."""
assert await async_setup_component(
hass,
@ -266,6 +290,7 @@ async def test_custom_state_payload(hass, mqtt_mock):
},
)
await hass.async_block_till_done()
await mqtt_mock_entry_with_yaml_config()
state = hass.states.get("switch.test")
assert state.state == STATE_UNKNOWN
@ -282,49 +307,57 @@ async def test_custom_state_payload(hass, mqtt_mock):
assert state.state == STATE_OFF
async def test_setting_attribute_via_mqtt_json_message(hass, mqtt_mock):
async def test_setting_attribute_via_mqtt_json_message(
hass, mqtt_mock_entry_with_yaml_config
):
"""Test the setting of attribute via MQTT with JSON payload."""
await help_test_setting_attribute_via_mqtt_json_message(
hass, mqtt_mock, switch.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_with_yaml_config, switch.DOMAIN, DEFAULT_CONFIG
)
async def test_setting_blocked_attribute_via_mqtt_json_message(hass, mqtt_mock):
async def test_setting_blocked_attribute_via_mqtt_json_message(
hass, mqtt_mock_entry_no_yaml_config
):
"""Test the setting of attribute via MQTT with JSON payload."""
await help_test_setting_blocked_attribute_via_mqtt_json_message(
hass, mqtt_mock, switch.DOMAIN, DEFAULT_CONFIG, {}
hass, mqtt_mock_entry_no_yaml_config, switch.DOMAIN, DEFAULT_CONFIG, {}
)
async def test_setting_attribute_with_template(hass, mqtt_mock):
async def test_setting_attribute_with_template(hass, mqtt_mock_entry_with_yaml_config):
"""Test the setting of attribute via MQTT with JSON payload."""
await help_test_setting_attribute_with_template(
hass, mqtt_mock, switch.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_with_yaml_config, switch.DOMAIN, DEFAULT_CONFIG
)
async def test_update_with_json_attrs_not_dict(hass, mqtt_mock, caplog):
async def test_update_with_json_attrs_not_dict(
hass, mqtt_mock_entry_with_yaml_config, caplog
):
"""Test attributes get extracted from a JSON result."""
await help_test_update_with_json_attrs_not_dict(
hass, mqtt_mock, caplog, switch.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_with_yaml_config, caplog, switch.DOMAIN, DEFAULT_CONFIG
)
async def test_update_with_json_attrs_bad_JSON(hass, mqtt_mock, caplog):
async def test_update_with_json_attrs_bad_JSON(
hass, mqtt_mock_entry_with_yaml_config, caplog
):
"""Test attributes get extracted from a JSON result."""
await help_test_update_with_json_attrs_bad_JSON(
hass, mqtt_mock, caplog, switch.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_with_yaml_config, caplog, switch.DOMAIN, DEFAULT_CONFIG
)
async def test_discovery_update_attr(hass, mqtt_mock, caplog):
async def test_discovery_update_attr(hass, mqtt_mock_entry_no_yaml_config, caplog):
"""Test update of discovered MQTTAttributes."""
await help_test_discovery_update_attr(
hass, mqtt_mock, caplog, switch.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_no_yaml_config, caplog, switch.DOMAIN, DEFAULT_CONFIG
)
async def test_unique_id(hass, mqtt_mock):
async def test_unique_id(hass, mqtt_mock_entry_with_yaml_config):
"""Test unique id option only creates one switch per unique_id."""
config = {
switch.DOMAIN: [
@ -344,20 +377,26 @@ async def test_unique_id(hass, mqtt_mock):
},
]
}
await help_test_unique_id(hass, mqtt_mock, switch.DOMAIN, config)
await help_test_unique_id(
hass, mqtt_mock_entry_with_yaml_config, switch.DOMAIN, config
)
async def test_discovery_removal_switch(hass, mqtt_mock, caplog):
async def test_discovery_removal_switch(hass, mqtt_mock_entry_no_yaml_config, caplog):
"""Test removal of discovered switch."""
data = (
'{ "name": "test",'
' "state_topic": "test_topic",'
' "command_topic": "test_topic" }'
)
await help_test_discovery_removal(hass, mqtt_mock, caplog, switch.DOMAIN, data)
await help_test_discovery_removal(
hass, mqtt_mock_entry_no_yaml_config, caplog, switch.DOMAIN, data
)
async def test_discovery_update_switch_topic_template(hass, mqtt_mock, caplog):
async def test_discovery_update_switch_topic_template(
hass, mqtt_mock_entry_no_yaml_config, caplog
):
"""Test update of discovered switch."""
config1 = copy.deepcopy(DEFAULT_CONFIG[switch.DOMAIN])
config2 = copy.deepcopy(DEFAULT_CONFIG[switch.DOMAIN])
@ -382,7 +421,7 @@ async def test_discovery_update_switch_topic_template(hass, mqtt_mock, caplog):
await help_test_discovery_update(
hass,
mqtt_mock,
mqtt_mock_entry_no_yaml_config,
caplog,
switch.DOMAIN,
config1,
@ -392,7 +431,9 @@ async def test_discovery_update_switch_topic_template(hass, mqtt_mock, caplog):
)
async def test_discovery_update_switch_template(hass, mqtt_mock, caplog):
async def test_discovery_update_switch_template(
hass, mqtt_mock_entry_no_yaml_config, caplog
):
"""Test update of discovered switch."""
config1 = copy.deepcopy(DEFAULT_CONFIG[switch.DOMAIN])
config2 = copy.deepcopy(DEFAULT_CONFIG[switch.DOMAIN])
@ -415,7 +456,7 @@ async def test_discovery_update_switch_template(hass, mqtt_mock, caplog):
await help_test_discovery_update(
hass,
mqtt_mock,
mqtt_mock_entry_no_yaml_config,
caplog,
switch.DOMAIN,
config1,
@ -425,7 +466,9 @@ async def test_discovery_update_switch_template(hass, mqtt_mock, caplog):
)
async def test_discovery_update_unchanged_switch(hass, mqtt_mock, caplog):
async def test_discovery_update_unchanged_switch(
hass, mqtt_mock_entry_no_yaml_config, caplog
):
"""Test update of discovered switch."""
data1 = (
'{ "name": "Beer",'
@ -437,12 +480,17 @@ async def test_discovery_update_unchanged_switch(hass, mqtt_mock, caplog):
"homeassistant.components.mqtt.switch.MqttSwitch.discovery_update"
) as discovery_update:
await help_test_discovery_update_unchanged(
hass, mqtt_mock, caplog, switch.DOMAIN, data1, discovery_update
hass,
mqtt_mock_entry_no_yaml_config,
caplog,
switch.DOMAIN,
data1,
discovery_update,
)
@pytest.mark.no_fail_on_log_exception
async def test_discovery_broken(hass, mqtt_mock, caplog):
async def test_discovery_broken(hass, mqtt_mock_entry_no_yaml_config, caplog):
"""Test handling of bad discovery message."""
data1 = '{ "name": "Beer" }'
data2 = (
@ -451,56 +499,60 @@ async def test_discovery_broken(hass, mqtt_mock, caplog):
' "command_topic": "test_topic" }'
)
await help_test_discovery_broken(
hass, mqtt_mock, caplog, switch.DOMAIN, data1, data2
hass, mqtt_mock_entry_no_yaml_config, caplog, switch.DOMAIN, data1, data2
)
async def test_entity_device_info_with_connection(hass, mqtt_mock):
async def test_entity_device_info_with_connection(hass, mqtt_mock_entry_no_yaml_config):
"""Test MQTT switch device registry integration."""
await help_test_entity_device_info_with_connection(
hass, mqtt_mock, switch.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_no_yaml_config, switch.DOMAIN, DEFAULT_CONFIG
)
async def test_entity_device_info_with_identifier(hass, mqtt_mock):
async def test_entity_device_info_with_identifier(hass, mqtt_mock_entry_no_yaml_config):
"""Test MQTT switch device registry integration."""
await help_test_entity_device_info_with_identifier(
hass, mqtt_mock, switch.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_no_yaml_config, switch.DOMAIN, DEFAULT_CONFIG
)
async def test_entity_device_info_update(hass, mqtt_mock):
async def test_entity_device_info_update(hass, mqtt_mock_entry_no_yaml_config):
"""Test device registry update."""
await help_test_entity_device_info_update(
hass, mqtt_mock, switch.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_no_yaml_config, switch.DOMAIN, DEFAULT_CONFIG
)
async def test_entity_device_info_remove(hass, mqtt_mock):
async def test_entity_device_info_remove(hass, mqtt_mock_entry_no_yaml_config):
"""Test device registry remove."""
await help_test_entity_device_info_remove(
hass, mqtt_mock, switch.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_no_yaml_config, switch.DOMAIN, DEFAULT_CONFIG
)
async def test_entity_id_update_subscriptions(hass, mqtt_mock):
async def test_entity_id_update_subscriptions(hass, mqtt_mock_entry_with_yaml_config):
"""Test MQTT subscriptions are managed when entity_id is updated."""
await help_test_entity_id_update_subscriptions(
hass, mqtt_mock, switch.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_with_yaml_config, switch.DOMAIN, DEFAULT_CONFIG
)
async def test_entity_id_update_discovery_update(hass, mqtt_mock):
async def test_entity_id_update_discovery_update(hass, mqtt_mock_entry_no_yaml_config):
"""Test MQTT discovery update when entity_id is updated."""
await help_test_entity_id_update_discovery_update(
hass, mqtt_mock, switch.DOMAIN, DEFAULT_CONFIG
hass, mqtt_mock_entry_no_yaml_config, switch.DOMAIN, DEFAULT_CONFIG
)
async def test_entity_debug_info_message(hass, mqtt_mock):
async def test_entity_debug_info_message(hass, mqtt_mock_entry_no_yaml_config):
"""Test MQTT debug info."""
await help_test_entity_debug_info_message(
hass, mqtt_mock, switch.DOMAIN, DEFAULT_CONFIG, switch.SERVICE_TURN_ON
hass,
mqtt_mock_entry_no_yaml_config,
switch.DOMAIN,
DEFAULT_CONFIG,
switch.SERVICE_TURN_ON,
)
@ -525,7 +577,7 @@ async def test_entity_debug_info_message(hass, mqtt_mock):
)
async def test_publishing_with_custom_encoding(
hass,
mqtt_mock,
mqtt_mock_entry_with_yaml_config,
caplog,
service,
topic,
@ -539,7 +591,7 @@ async def test_publishing_with_custom_encoding(
await help_test_publishing_with_custom_encoding(
hass,
mqtt_mock,
mqtt_mock_entry_with_yaml_config,
caplog,
domain,
config,
@ -551,11 +603,13 @@ async def test_publishing_with_custom_encoding(
)
async def test_reloadable(hass, mqtt_mock, caplog, tmp_path):
async def test_reloadable(hass, mqtt_mock_entry_with_yaml_config, caplog, tmp_path):
"""Test reloading the MQTT platform."""
domain = switch.DOMAIN
config = DEFAULT_CONFIG[domain]
await help_test_reloadable(hass, mqtt_mock, caplog, tmp_path, domain, config)
await help_test_reloadable(
hass, mqtt_mock_entry_with_yaml_config, caplog, tmp_path, domain, config
)
async def test_reloadable_late(hass, mqtt_client_mock, caplog, tmp_path):
@ -572,12 +626,18 @@ async def test_reloadable_late(hass, mqtt_client_mock, caplog, tmp_path):
],
)
async def test_encoding_subscribable_topics(
hass, mqtt_mock, caplog, topic, value, attribute, attribute_value
hass,
mqtt_mock_entry_with_yaml_config,
caplog,
topic,
value,
attribute,
attribute_value,
):
"""Test handling of incoming encoded payload."""
await help_test_encoding_subscribable_topics(
hass,
mqtt_mock,
mqtt_mock_entry_with_yaml_config,
caplog,
switch.DOMAIN,
DEFAULT_CONFIG[switch.DOMAIN],

Some files were not shown because too many files have changed in this diff Show More