Compare commits

...

29 Commits

Author SHA1 Message Date
Franck Nijhof 30d8bf4231 2026.6.2 (#173397) 2026-06-09 22:13:22 +02:00
Triggs 5436d8af9b Bump codecov/codecov-action from v6.0.1 to v7.0.0 (#173232)
Co-authored-by: Franck Nijhof <git@frenck.dev>
2026-06-09 19:26:01 +00:00
epenet 88adf39ef3 Use explicit DOMAIN import in mqtt tests (#173093) 2026-06-09 19:20:12 +00:00
Franck Nijhof 14b14bddf1 Bump version to 2026.6.2 2026-06-09 18:41:21 +00:00
Michael Hansen 3c4a30be6b Only allow specific protocols with ffmpeg in Wyoming satellite announce (#173381)
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-06-09 18:34:34 +00:00
Joost Lekkerkerker 2988eb4b19 Set Zinvolt max output to 2kW if unlocked (#173367) 2026-06-09 18:34:32 +00:00
Nikolai Rahimi 00eef14558 Bump mitsubishi-comfort to 0.3.1 (#173362) 2026-06-09 18:34:30 +00:00
Joost Lekkerkerker d02516dd09 Handle unavailable Zinvolt devices better (#173359) 2026-06-09 18:34:28 +00:00
Jan Bouwhuis aabb6b3d04 Fix reload fails when MQTT entry is not set up (#173335)
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Franck Nijhof <git@frenck.dev>
2026-06-09 18:34:26 +00:00
tronikos 50c2c7c4bc Bump opower to 0.18.4 (#173323) 2026-06-09 18:34:24 +00:00
Joakim Plate e81dd426bb Ensure we provide strings to vol.In for philips js (#173313) 2026-06-09 18:34:22 +00:00
Michael Hansen c4c569c181 Mitigate TTS ResultStream leak in pipeline (#173290) 2026-06-09 18:34:20 +00:00
Simone Chemelli 6182426132 Bump renault-api to 0.5.12 (#173289) 2026-06-09 18:34:18 +00:00
Martin Hjelmare a073cc4f7d Fix homeassistant hardware unique id migration (#173258) 2026-06-09 18:34:16 +00:00
Mark Purcell 07ddc08d84 Bump pydaikin to 2.18.1 (#173249) 2026-06-09 18:34:14 +00:00
Bram Kragten 17673dcf55 Update frontend to 20260527.5 (#173236) 2026-06-09 18:34:12 +00:00
starkillerOG a864bc1c80 Adjust ONVIF event fallbacks for battery cameras (#173214)
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-06-09 18:34:10 +00:00
Shay Levy a15d80daa2 Fix Shelly virtual component unit retrieval (#173183) 2026-06-09 18:34:08 +00:00
Joost Lekkerkerker e123b29258 Have Plugwise handle unavailable temperature measurements (#173173) 2026-06-09 18:34:06 +00:00
J. Nick Koston 5669a7b602 Wait for Shelly bluetooth proxy connection at startup (#173165) 2026-06-09 18:34:05 +00:00
J. Nick Koston fe358a4a1f Wait for ESPHome bluetooth proxy connection at startup (#173164) 2026-06-09 18:34:03 +00:00
mvn23 3a93d6370b Ensure opentherm_gw boiler and thermostat manufacturers are strings (#173162) 2026-06-09 18:34:01 +00:00
Bouwe Westerdijk 89576f01e6 Bump plugwise to v1.11.4 (#173147) 2026-06-09 18:33:59 +00:00
tronikos f51895b0c9 Bump opower to 0.18.3 (#173141) 2026-06-09 18:30:18 +00:00
Joakim Plate d0dcbfadaa Switch to active scanner for gardena (#173062) 2026-06-09 18:30:16 +00:00
Simone Chemelli 5e0d3627c2 Improve and complete exception handling for Alexa Devices (#173053) 2026-06-09 18:30:14 +00:00
Diogo Gomes 80c90732a3 Bump pytrydan to v1.0.1 (#173047) 2026-06-09 18:30:12 +00:00
Yardian Support 16eca3909a Bump pyyardian to 1.4.0 (#173020)
Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>
2026-06-09 18:30:10 +00:00
peteS-UK 1b471da31f Update PARALLEL_UPDATES to 0 for Squeezebox platforms (#172906) 2026-06-09 18:30:08 +00:00
112 changed files with 2087 additions and 1154 deletions
+3 -3
View File
@@ -1326,7 +1326,7 @@ jobs:
pattern: coverage-*
- name: Upload coverage to Codecov
if: needs.info.outputs.test_full_suite == 'true'
uses: codecov/codecov-action@e79a6962e0d4c0c17b229090214935d2e33f8354 # v6.0.1
uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # v7.0.0
with:
fail_ci_if_error: true
flags: full-suite
@@ -1485,7 +1485,7 @@ jobs:
pattern: coverage-*
- name: Upload coverage to Codecov
if: needs.info.outputs.test_full_suite == 'false'
uses: codecov/codecov-action@e79a6962e0d4c0c17b229090214935d2e33f8354 # v6.0.1
uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # v7.0.0
with:
fail_ci_if_error: true
token: ${{ secrets.CODECOV_TOKEN }} # zizmor: ignore[secrets-outside-env]
@@ -1513,7 +1513,7 @@ jobs:
with:
pattern: test-results-*
- name: Upload test results to Codecov
uses: codecov/codecov-action@e79a6962e0d4c0c17b229090214935d2e33f8354 # v6.0.1
uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # v7.0.0
with:
report_type: test_results
fail_ci_if_error: true
@@ -6,7 +6,7 @@ from homeassistant.helpers.entity import EntityDescription
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
from homeassistant.util import slugify
from .coordinator import AmazonConfigEntry, AmazonDevicesCoordinator
from .coordinator import AmazonConfigEntry, AmazonDevicesCoordinator, alexa_api_call
from .entity import AmazonServiceEntity
# Coordinator is used to centralize the data updates
@@ -49,4 +49,5 @@ class AmazonRoutineButton(AmazonServiceEntity, ButtonEntity):
async def async_press(self) -> None:
"""Handle button press action."""
await self.coordinator.api.call_routine(self._routine)
async with alexa_api_call(self.coordinator):
await self.coordinator.api.call_routine(self._routine)
@@ -1,5 +1,7 @@
"""Support for Alexa Devices."""
from collections.abc import AsyncGenerator
from contextlib import asynccontextmanager
from datetime import timedelta
from aioamazondevices.api import AmazonEchoApi
@@ -19,7 +21,11 @@ from aiohttp import ClientSession
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_PASSWORD, CONF_USERNAME, Platform
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import ConfigEntryAuthFailed, ConfigEntryNotReady
from homeassistant.exceptions import (
ConfigEntryAuthFailed,
ConfigEntryNotReady,
HomeAssistantError,
)
from homeassistant.helpers import device_registry as dr, entity_registry as er
from homeassistant.helpers.debounce import Debouncer
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
@@ -29,6 +35,65 @@ from .const import _LOGGER, CONF_LOGIN_DATA, DOMAIN
SCAN_INTERVAL = 300
@asynccontextmanager
async def alexa_api_call(
coordinator: DataUpdateCoordinator | None = None,
) -> AsyncGenerator[None]:
"""Handle common Alexa API exceptions as HomeAssistantError."""
try:
yield
except CannotAuthenticate as err:
if coordinator:
coordinator.last_update_success = False
raise HomeAssistantError(
translation_domain=DOMAIN,
translation_key="invalid_auth",
translation_placeholders={"error": repr(err)},
) from err
except CannotConnect as err:
if coordinator:
coordinator.last_update_success = False
raise HomeAssistantError(
translation_domain=DOMAIN,
translation_key="cannot_connect_with_error",
translation_placeholders={"error": repr(err)},
) from err
except (CannotRetrieveData, ValueError) as err:
if coordinator:
coordinator.last_update_success = False
raise HomeAssistantError(
translation_domain=DOMAIN,
translation_key="cannot_retrieve_data_with_error",
translation_placeholders={"error": repr(err)},
) from err
@asynccontextmanager
async def alexa_config_entry_errors() -> AsyncGenerator[None]:
"""Handle common Alexa API exceptions as ConfigEntry errors."""
try:
yield
except CannotAuthenticate as err:
raise ConfigEntryAuthFailed(
translation_domain=DOMAIN,
translation_key="invalid_auth",
translation_placeholders={"error": repr(err)},
) from err
except (CannotConnect, TimeoutError) as err:
raise ConfigEntryNotReady(
translation_domain=DOMAIN,
translation_key="cannot_connect_with_error",
translation_placeholders={"error": repr(err)},
) from err
except (CannotRetrieveData, ValueError, KeyError, StopIteration) as err:
raise ConfigEntryNotReady(
translation_domain=DOMAIN,
translation_key="cannot_retrieve_data_with_error",
translation_placeholders={"error": repr(err)},
) from err
type AmazonConfigEntry = ConfigEntry[AmazonDevicesCoordinator]
@@ -113,6 +178,12 @@ class AmazonDevicesCoordinator(DataUpdateCoordinator[dict[str, AmazonDevice]]):
translation_key="invalid_auth",
translation_placeholders={"error": repr(err)},
) from err
except ValueError as err:
raise UpdateFailed(
translation_domain=DOMAIN,
translation_key="cannot_retrieve_data_with_error",
translation_placeholders={"error": repr(err)},
) from err
else:
current_devices = set(data.keys())
if stale_devices := self.previous_devices - current_devices:
@@ -169,26 +240,8 @@ class AmazonDevicesCoordinator(DataUpdateCoordinator[dict[str, AmazonDevice]]):
async def sync_history_state(self) -> None:
"""Sync history state."""
try:
async with alexa_config_entry_errors():
self._vocal_records = await self.api.sync_history_state()
except CannotAuthenticate as e:
raise ConfigEntryAuthFailed(
translation_domain=DOMAIN,
translation_key="invalid_auth",
translation_placeholders={"error": repr(e)},
) from e
except CannotConnect as e:
raise ConfigEntryNotReady(
translation_domain=DOMAIN,
translation_key="cannot_connect_with_error",
translation_placeholders={"error": repr(e)},
) from e
except BaseException as e:
raise ConfigEntryNotReady(
translation_domain=DOMAIN,
translation_key="cannot_retrieve_data_with_error",
translation_placeholders={"error": repr(e)},
) from e
async def history_state_event_handler(
self, vocal_records: dict[str, AmazonVocalRecord]
@@ -204,26 +257,8 @@ class AmazonDevicesCoordinator(DataUpdateCoordinator[dict[str, AmazonDevice]]):
async def sync_media_state(self) -> None:
"""Sync media state."""
try:
async with alexa_config_entry_errors():
await self.api.sync_media_state()
except CannotAuthenticate as err:
raise ConfigEntryAuthFailed(
translation_domain=DOMAIN,
translation_key="invalid_auth",
translation_placeholders={"error": repr(err)},
) from err
except (CannotConnect, TimeoutError) as err:
raise ConfigEntryNotReady(
translation_domain=DOMAIN,
translation_key="cannot_connect_with_error",
translation_placeholders={"error": repr(err)},
) from err
except (CannotRetrieveData, ValueError) as err:
raise ConfigEntryNotReady(
translation_domain=DOMAIN,
translation_key="cannot_retrieve_data_with_error",
translation_placeholders={"error": repr(err)},
) from err
async def media_state_event_handler(
self, media_state: dict[str, AmazonMediaState]
@@ -22,9 +22,8 @@ from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
from .const import _LOGGER
from .coordinator import AmazonConfigEntry, AmazonDevicesCoordinator
from .coordinator import AmazonConfigEntry, AmazonDevicesCoordinator, alexa_api_call
from .entity import AmazonEntity
from .utils import alexa_api_call
PARALLEL_UPDATES = 1
@@ -216,16 +215,15 @@ class AlexaDevicesMediaPlayer(AmazonEntity, MediaPlayerEntity):
provider = media_type.value if isinstance(media_type, MediaType) else media_type
await self.async_call_alexa_music(media_id, provider)
@alexa_api_call
async def async_call_alexa_music(
self, search_phrase: str, provider_id: str
) -> None:
"""Call alexa music."""
await self.coordinator.api.call_alexa_music(
self.device, search_phrase, provider_id
)
async with alexa_api_call(self.coordinator):
await self.coordinator.api.call_alexa_music(
self.device, search_phrase, provider_id
)
@alexa_api_call
async def async_set_device_volume(self, volume: int) -> None:
"""Set the device volume."""
_LOGGER.debug(
@@ -233,7 +231,8 @@ class AlexaDevicesMediaPlayer(AmazonEntity, MediaPlayerEntity):
self.device.serial_number,
volume,
)
await self.coordinator.api.set_device_volume(self.device, volume)
async with alexa_api_call(self.coordinator):
await self.coordinator.api.set_device_volume(self.device, volume)
async def async_set_volume_level(self, volume: float) -> None:
"""Set the volume level (0.0 to 1.0)."""
@@ -263,12 +262,12 @@ class AlexaDevicesMediaPlayer(AmazonEntity, MediaPlayerEntity):
await self.async_set_volume_level(target_volume / 100)
self._prev_volume = None
@alexa_api_call
async def _send_media_command(self, command: AmazonMediaControls) -> None:
_LOGGER.debug(
"Sending media command '%s' to %s", command, self.device.serial_number
)
await self.coordinator.api.send_media_command(self.device, command)
async with alexa_api_call(self.coordinator):
await self.coordinator.api.send_media_command(self.device, command)
async def async_media_stop(self) -> None:
"""Send stop command."""
@@ -12,9 +12,8 @@ from homeassistant.components.notify import NotifyEntity, NotifyEntityDescriptio
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
from .coordinator import AmazonConfigEntry
from .coordinator import AmazonConfigEntry, alexa_api_call
from .entity import AmazonEntity
from .utils import alexa_api_call
PARALLEL_UPDATES = 1
@@ -80,10 +79,11 @@ class AmazonNotifyEntity(AmazonEntity, NotifyEntity):
entity_description: AmazonNotifyEntityDescription
@alexa_api_call
async def async_send_message(
self, message: str, title: str | None = None, **kwargs: Any
) -> None:
"""Send a message."""
await self.entity_description.method(self.coordinator.api, self.device, message)
async with alexa_api_call(self.coordinator):
await self.entity_description.method(
self.coordinator.api, self.device, message
)
@@ -11,7 +11,7 @@ from homeassistant.exceptions import ServiceValidationError
from homeassistant.helpers import config_validation as cv, device_registry as dr
from .const import DOMAIN, INFO_SKILLS_MAPPING
from .coordinator import AmazonConfigEntry
from .coordinator import AmazonConfigEntry, alexa_api_call
ATTR_TEXT_COMMAND = "text_command"
ATTR_SOUND = "sound"
@@ -85,13 +85,15 @@ async def _async_execute_action(call: ServiceCall, attribute: str) -> None:
translation_key="invalid_sound_value",
translation_placeholders={"sound": value},
)
await coordinator.api.call_alexa_sound(
coordinator.data[device.serial_number], value
)
async with alexa_api_call():
await coordinator.api.call_alexa_sound(
coordinator.data[device.serial_number], value
)
elif attribute == ATTR_TEXT_COMMAND:
await coordinator.api.call_alexa_text_command(
coordinator.data[device.serial_number], value
)
async with alexa_api_call():
await coordinator.api.call_alexa_text_command(
coordinator.data[device.serial_number], value
)
elif attribute == ATTR_INFO_SKILL:
info_skill = INFO_SKILLS_MAPPING.get(value)
if info_skill not in ALEXA_INFO_SKILLS:
@@ -100,9 +102,10 @@ async def _async_execute_action(call: ServiceCall, attribute: str) -> None:
translation_key="invalid_info_skill_value",
translation_placeholders={"info_skill": value},
)
await coordinator.api.call_alexa_info_skill(
coordinator.data[device.serial_number], info_skill
)
async with alexa_api_call():
await coordinator.api.call_alexa_info_skill(
coordinator.data[device.serial_number], info_skill
)
async def async_send_sound_notification(call: ServiceCall) -> None:
@@ -14,13 +14,9 @@ from homeassistant.components.switch import (
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
from .coordinator import AmazonConfigEntry
from .coordinator import AmazonConfigEntry, alexa_api_call
from .entity import AmazonEntity
from .utils import (
alexa_api_call,
async_remove_dnd_from_virtual_group,
async_update_unique_id,
)
from .utils import async_remove_dnd_from_virtual_group, async_update_unique_id
PARALLEL_UPDATES = 1
@@ -90,7 +86,6 @@ class AmazonSwitchEntity(AmazonEntity, SwitchEntity):
entity_description: AmazonSwitchEntityDescription
@alexa_api_call
async def _switch_set_state(self, state: bool) -> None:
"""Set desired switch state."""
method = getattr(self.coordinator.api, self.entity_description.method)
@@ -98,7 +93,8 @@ class AmazonSwitchEntity(AmazonEntity, SwitchEntity):
if TYPE_CHECKING:
assert method is not None
await method(self.device, state)
async with alexa_api_call(self.coordinator):
await method(self.device, state)
self.coordinator.data[self.device.serial_number].sensors[
self.entity_description.key
].value = state
@@ -1,54 +1,19 @@
"""Utils for Alexa Devices."""
from collections.abc import Awaitable, Callable, Coroutine
from functools import wraps
from typing import Any, Concatenate
from aioamazondevices.const.devices import SPEAKER_GROUP_FAMILY
from aioamazondevices.const.schedules import (
NOTIFICATION_ALARM,
NOTIFICATION_REMINDER,
NOTIFICATION_TIMER,
)
from aioamazondevices.exceptions import CannotConnect, CannotRetrieveData
from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN
from homeassistant.components.switch import DOMAIN as SWITCH_DOMAIN
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import HomeAssistantError
import homeassistant.helpers.entity_registry as er
from .const import _LOGGER, DOMAIN
from .coordinator import AmazonDevicesCoordinator
from .entity import AmazonEntity
def alexa_api_call[_T: AmazonEntity, **_P](
func: Callable[Concatenate[_T, _P], Awaitable[None]],
) -> Callable[Concatenate[_T, _P], Coroutine[Any, Any, None]]:
"""Catch Alexa API call exceptions."""
@wraps(func)
async def cmd_wrapper(self: _T, *args: _P.args, **kwargs: _P.kwargs) -> None:
"""Wrap all command methods."""
try:
await func(self, *args, **kwargs)
except CannotConnect as err:
self.coordinator.last_update_success = False
raise HomeAssistantError(
translation_domain=DOMAIN,
translation_key="cannot_connect_with_error",
translation_placeholders={"error": repr(err)},
) from err
except CannotRetrieveData as err:
self.coordinator.last_update_success = False
raise HomeAssistantError(
translation_domain=DOMAIN,
translation_key="cannot_retrieve_data_with_error",
translation_placeholders={"error": repr(err)},
) from err
return cmd_wrapper
async def async_update_unique_id(
@@ -1816,6 +1816,11 @@ class PipelineInput:
await self.run.text_to_speech(tts_input)
except PipelineError as err:
if self.run.tts_stream:
# Clean up TTS stream
self.run.tts_stream.delete()
self.run.tts_stream = None
self.run.process_event(
PipelineEvent(
PipelineEventType.ERROR,
@@ -1885,15 +1890,17 @@ class PipelineInput:
):
prepare_tasks.append(self.run.prepare_recognize_intent(self.session))
if prepare_tasks:
await asyncio.gather(*prepare_tasks)
# Do TTS prepare separately so we don't create a ResultStream if the
# pipeline is invalid.
if (
start_stage_index
<= PIPELINE_STAGE_ORDER.index(PipelineStage.TTS)
<= end_stage_index
):
prepare_tasks.append(self.run.prepare_text_to_speech())
if prepare_tasks:
await asyncio.gather(*prepare_tasks)
await self.run.prepare_text_to_speech()
class PipelinePreferred(CollectionError):
@@ -7,6 +7,6 @@
"integration_type": "device",
"iot_class": "local_polling",
"loggers": ["pydaikin"],
"requirements": ["pydaikin==2.17.2"],
"requirements": ["pydaikin==2.18.1"],
"zeroconf": ["_dkapi._tcp.local."]
}
@@ -166,6 +166,8 @@ class RuntimeEntryData:
)
loaded_platforms: set[Platform] = field(default_factory=set)
platform_load_lock: asyncio.Lock = field(default_factory=asyncio.Lock)
# Set once the first connection has finished scanner setup or teardown.
first_connect_done: asyncio.Event = field(default_factory=asyncio.Event)
_storage_contents: StoreData | None = None
_pending_storage: Callable[[], StoreData] | None = None
assist_pipeline_update_callbacks: list[CALLBACK_TYPE] = field(default_factory=list)
+22 -1
View File
@@ -1,11 +1,12 @@
"""Manager for esphome devices."""
import asyncio
import base64
from functools import partial
import logging
import secrets
import struct
from typing import TYPE_CHECKING, Any, NamedTuple
from typing import TYPE_CHECKING, Any, Final, NamedTuple
from aioesphomeapi import (
APIClient,
@@ -106,6 +107,9 @@ if TYPE_CHECKING:
_LOGGER = logging.getLogger(__name__)
# Max time to wait at startup for a BLE proxy to register its scanner.
STARTUP_SCANNER_WAIT: Final = 3.0
LOG_LEVEL_TO_LOGGER = {
LogLevel.LOG_LEVEL_NONE: logging.DEBUG,
LogLevel.LOG_LEVEL_ERROR: logging.ERROR,
@@ -677,6 +681,8 @@ class ESPHomeManager:
hass, device_info.bluetooth_mac_address or device_info.mac_address
)
entry_data.first_connect_done.set()
if device_info.voice_assistant_feature_flags_compat(api_version) and (
Platform.ASSIST_SATELLITE not in entry_data.loaded_platforms
):
@@ -988,6 +994,21 @@ class ESPHomeManager:
await reconnect_logic.start()
# Wait for a cached BLE proxy to register its scanner before finishing setup.
if (
device_info := entry_data.device_info
) is not None and device_info.bluetooth_proxy_feature_flags_compat(
entry_data.api_version
):
try:
async with asyncio.timeout(STARTUP_SCANNER_WAIT):
await entry_data.first_connect_done.wait()
except TimeoutError:
_LOGGER.debug(
"%s: Timed out waiting for Bluetooth scanner to register",
self.host,
)
@callback
def _async_setup_device_registry(
@@ -21,5 +21,5 @@
"integration_type": "system",
"preview_features": { "winter_mode": {} },
"quality_scale": "internal",
"requirements": ["home-assistant-frontend==20260527.4"]
"requirements": ["home-assistant-frontend==20260527.5"]
}
@@ -1,11 +1,13 @@
"""The Gardena Bluetooth integration."""
from contextlib import suppress
import logging
from bleak.backends.device import BLEDevice
from gardena_bluetooth.client import CachedConnection, Client
from gardena_bluetooth.const import ProductType
from gardena_bluetooth.scan import async_get_manufacturer_data
from gardena_bluetooth.const import ScanService
from gardena_bluetooth.parse import ManufacturerData, ProductType
from habluetooth import BluetoothServiceInfoBleak
from homeassistant.components import bluetooth
from homeassistant.const import CONF_ADDRESS, Platform
@@ -30,6 +32,64 @@ PLATFORMS: list[Platform] = [
]
LOGGER = logging.getLogger(__name__)
DISCONNECT_DELAY = 5
PRODUCTS_SCAN_TIMEOUT = 10
PRODUCT_TYPE_TIMEOUT = 30
async def async_get_product_type(hass: HomeAssistant, address: str) -> ProductType:
"""Get a product type for the given address."""
data = ManufacturerData()
def _data_callback(info: BluetoothServiceInfoBleak) -> bool:
LOGGER.debug("Processing advertisement from %s: %s", info.address, info)
if info.device.address != address:
return False
data.update(info.manufacturer_data.get(ManufacturerData.company, b""))
return data.product_type is not ProductType.UNKNOWN
with suppress(TimeoutError):
await bluetooth.async_process_advertisements(
hass,
_data_callback,
bluetooth.BluetoothCallbackMatcher(
address=address, manufacturer_id=ManufacturerData.company
),
mode=bluetooth.BluetoothScanningMode.ACTIVE,
timeout=PRODUCT_TYPE_TIMEOUT,
)
return data.product_type
async def async_get_products(hass: HomeAssistant) -> dict[str, ManufacturerData]:
"""Get all products that are currently advertising."""
products: dict[str, ManufacturerData] = {}
def _data_callback(info: BluetoothServiceInfoBleak) -> bool:
LOGGER.debug("Processing advertisement from %s: %s", info.address, info)
if ScanService not in info.service_uuids:
return False
raw = info.manufacturer_data.get(ManufacturerData.company, b"")
if (data := products.get(info.device.address)) is None:
data = ManufacturerData()
products[info.device.address] = data
data.update(raw)
return False
with suppress(TimeoutError):
await bluetooth.async_process_advertisements(
hass,
_data_callback,
bluetooth.BluetoothCallbackMatcher(
manufacturer_id=ManufacturerData.company
),
mode=bluetooth.BluetoothScanningMode.ACTIVE,
timeout=PRODUCTS_SCAN_TIMEOUT,
)
return products
def get_connection(hass: HomeAssistant, address: str) -> CachedConnection:
@@ -53,12 +113,7 @@ async def async_setup_entry(
address = entry.data[CONF_ADDRESS]
try:
mfg_data = await async_get_manufacturer_data({address})
except TimeoutError as exc:
raise ConfigEntryNotReady("Unable to find product type") from exc
product_type = mfg_data[address].product_type
product_type = await async_get_product_type(hass, address)
if product_type is ProductType.UNKNOWN:
raise ConfigEntryNotReady("Unable to find product type")
@@ -4,21 +4,17 @@ import logging
from typing import Any
from gardena_bluetooth.client import Client
from gardena_bluetooth.const import PRODUCT_NAMES, DeviceInformation, ScanService
from gardena_bluetooth.const import PRODUCT_NAMES, DeviceInformation
from gardena_bluetooth.exceptions import CharacteristicNotFound, CommunicationFailure
from gardena_bluetooth.parse import ManufacturerData, ProductType
from gardena_bluetooth.scan import async_get_manufacturer_data
from gardena_bluetooth.parse import ProductType
import voluptuous as vol
from homeassistant.components.bluetooth import (
BluetoothServiceInfo,
async_discovered_service_info,
)
from homeassistant.components.bluetooth import BluetoothServiceInfo
from homeassistant.config_entries import ConfigFlow, ConfigFlowResult
from homeassistant.const import CONF_ADDRESS
from homeassistant.data_entry_flow import AbortFlow
from . import get_connection
from . import async_get_product_type, async_get_products, get_connection
from .const import DOMAIN
_LOGGER = logging.getLogger(__name__)
@@ -33,17 +29,6 @@ _SUPPORTED_PRODUCT_TYPES = {
}
def _is_supported(discovery_info: BluetoothServiceInfo):
"""Check if device is supported."""
if ScanService not in discovery_info.service_uuids:
return False
if discovery_info.manufacturer_data.get(ManufacturerData.company) is None:
_LOGGER.debug("Missing manufacturer data: %s", discovery_info)
return False
return True
class GardenaBluetoothConfigFlow(ConfigFlow, domain=DOMAIN):
"""Handle a config flow for Gardena Bluetooth."""
@@ -75,8 +60,7 @@ class GardenaBluetoothConfigFlow(ConfigFlow, domain=DOMAIN):
) -> ConfigFlowResult:
"""Handle the bluetooth discovery step."""
_LOGGER.debug("Discovered device: %s", discovery_info)
data = await async_get_manufacturer_data({discovery_info.address})
product_type = data[discovery_info.address].product_type
product_type = await async_get_product_type(self.hass, discovery_info.address)
if product_type not in _SUPPORTED_PRODUCT_TYPES:
return self.async_abort(reason="no_devices_found")
@@ -117,22 +101,16 @@ class GardenaBluetoothConfigFlow(ConfigFlow, domain=DOMAIN):
self._abort_if_unique_id_configured()
return await self.async_step_confirm()
current_addresses = self._async_current_ids(include_ignore=False)
candidates = set()
for discovery_info in async_discovered_service_info(self.hass):
address = discovery_info.address
if address in current_addresses or not _is_supported(discovery_info):
continue
candidates.add(address)
data = await async_get_manufacturer_data(candidates)
for address, mfg_data in data.items():
if mfg_data.product_type not in _SUPPORTED_PRODUCT_TYPES:
continue
self.devices[address] = PRODUCT_NAMES[mfg_data.product_type]
current = self._async_current_ids(include_ignore=False)
devices = await async_get_products(self.hass)
# Keep selection sorted by address to ensure stable tests
self.devices = dict(sorted(self.devices.items(), key=lambda x: x[0]))
self.devices = {
address: PRODUCT_NAMES[data.product_type]
for address in sorted(devices)
if address not in current
and (data := devices[address]).product_type in _SUPPORTED_PRODUCT_TYPES
}
if not self.devices:
return self.async_abort(reason="no_devices_found")
@@ -135,7 +135,24 @@ async def async_migrate_entry(
)
if canonical.entry_id != config_entry.entry_id:
# The canonical entry's migration will remove this duplicate.
if canonical.minor_version < 2:
# The canonical entry has not been migrated yet and its
# migration will remove this duplicate.
return False
# The canonical entry is already fully migrated and will not run
# a migration that removes this duplicate, so remove it here. The
# entry can't remove itself while its setup lock is held, so
# schedule the removal instead.
_LOGGER.debug(
"Removing duplicate config entry %s for serial %s in favor of %s",
config_entry.entry_id,
serial_number,
canonical.entry_id,
)
hass.async_create_task(
hass.config_entries.async_remove(config_entry.entry_id)
)
return False
for duplicate in duplicates:
@@ -239,7 +239,24 @@ async def async_migrate_entry(
)
if canonical.entry_id != config_entry.entry_id:
# The canonical entry's migration will remove this duplicate.
if canonical.minor_version < 5:
# The canonical entry has not been migrated yet and its
# migration will remove this duplicate.
return False
# The canonical entry is already fully migrated and will not run
# a migration that removes this duplicate, so remove it here. The
# entry can't remove itself while its setup lock is held, so
# schedule the removal instead.
_LOGGER.warning(
"Removing duplicate config entry %s for serial %s in favor of %s",
config_entry.entry_id,
serial_number,
canonical.entry_id,
)
hass.async_create_task(
hass.config_entries.async_remove(config_entry.entry_id)
)
return False
for duplicate in duplicates:
@@ -8,5 +8,5 @@
"integration_type": "hub",
"iot_class": "local_polling",
"quality_scale": "bronze",
"requirements": ["mitsubishi-comfort==0.3.0"]
"requirements": ["mitsubishi-comfort==0.3.1"]
}
@@ -412,6 +412,12 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
async def _reload_config(call: ServiceCall) -> None:
"""Reload the platforms."""
if not mqtt_config_entry_enabled(hass):
_LOGGER.debug(
"Skipped reloading MQTT integration, "
"the MQTT config entry is not enabled"
)
return
entry: ConfigEntry = next(iter(hass.config_entries.async_entries(DOMAIN)))
mqtt_data = hass.data[DATA_MQTT]
@@ -159,11 +159,14 @@ class OpenThermGatewayHub:
_LOGGER.debug("Received report: %s", status)
async_dispatcher_send(self.hass, self.update_signal, status)
boiler_manufacturer = status[OpenThermDataSource.BOILER].get(
gw_vars.DATA_SLAVE_MEMBERID
)
dev_reg.async_update_device(
boiler_device.id,
manufacturer=status[OpenThermDataSource.BOILER].get(
gw_vars.DATA_SLAVE_MEMBERID
),
manufacturer=str(boiler_manufacturer)
if boiler_manufacturer is not None
else None,
model_id=status[OpenThermDataSource.BOILER].get(
gw_vars.DATA_SLAVE_PRODUCT_TYPE
),
@@ -175,11 +178,14 @@ class OpenThermGatewayHub:
),
)
thermostat_manufacturer = status[OpenThermDataSource.THERMOSTAT].get(
gw_vars.DATA_MASTER_MEMBERID
)
dev_reg.async_update_device(
thermostat_device.id,
manufacturer=status[OpenThermDataSource.THERMOSTAT].get(
gw_vars.DATA_MASTER_MEMBERID
),
manufacturer=str(thermostat_manufacturer)
if thermostat_manufacturer is not None
else None,
model_id=status[OpenThermDataSource.THERMOSTAT].get(
gw_vars.DATA_MASTER_PRODUCT_TYPE
),
@@ -9,5 +9,5 @@
"iot_class": "cloud_polling",
"loggers": ["opower"],
"quality_scale": "platinum",
"requirements": ["opower==0.18.2"]
"requirements": ["opower==0.18.4"]
}
@@ -45,8 +45,8 @@ USER_SCHEMA = vol.Schema(
): str,
vol.Required(
CONF_API_VERSION,
default=1,
): vol.In([1, 5, 6]),
default="1",
): vol.In(["1", "5", "6"]),
}
)
@@ -223,7 +223,7 @@ class PhilipsJSConfigFlow(ConfigFlow, domain=DOMAIN):
self._current = user_input
try:
await self._async_attempt_prepare(
user_input[CONF_HOST], user_input[CONF_API_VERSION], False
user_input[CONF_HOST], int(user_input[CONF_API_VERSION]), False
)
except GeneralFailure as exc:
LOGGER.error(exc)
+2 -2
View File
@@ -155,9 +155,9 @@ class PlugwiseClimateEntity(PlugwiseEntity, ClimateEntity, RestoreEntity):
)
@property
def current_temperature(self) -> float:
def current_temperature(self) -> float | None:
"""Return the current temperature."""
return self.device["sensors"]["temperature"]
return self.device["sensors"].get("temperature")
@property
def target_temperature(self) -> float:
@@ -8,6 +8,6 @@
"iot_class": "local_polling",
"loggers": ["plugwise"],
"quality_scale": "platinum",
"requirements": ["plugwise==1.11.3"],
"requirements": ["plugwise==1.11.4"],
"zeroconf": ["_plugwise._tcp.local."]
}
@@ -8,5 +8,5 @@
"iot_class": "cloud_polling",
"loggers": ["renault_api"],
"quality_scale": "silver",
"requirements": ["renault-api==0.5.11"]
"requirements": ["renault-api==0.5.12"]
}
+14 -9
View File
@@ -369,7 +369,11 @@ class ReolinkHost:
)
# start long polling if ONVIF push failed immediately
if not self._onvif_push_supported and not self._api.baichuan.privacy_mode():
if (
self._onvif_long_poll_supported
and not self._onvif_push_supported
and not self._api.baichuan.privacy_mode()
):
_LOGGER.debug(
"Camera model %s does not support ONVIF push,"
" using ONVIF long polling instead",
@@ -378,14 +382,8 @@ class ReolinkHost:
try:
await self._async_start_long_polling(initial=True)
except NotSupportedError:
_LOGGER.debug(
"Camera model %s does not support ONVIF long"
" polling, using fast polling instead",
self._api.model,
)
self._onvif_long_poll_supported = False
await self._api.unsubscribe()
await self._async_poll_all_motion()
else:
self._cancel_long_poll_check = async_call_later(
self._hass,
@@ -393,6 +391,13 @@ class ReolinkHost:
self._async_check_onvif_long_poll,
)
if not self._onvif_long_poll_supported:
_LOGGER.debug(
"Camera model %s does not support ONVIF push and long polling, using fast polling instead",
self._api.model,
)
await self._async_poll_all_motion()
self._cancel_tcp_push_check = None
async def _async_check_onvif(self, *_: Any) -> None:
@@ -822,7 +827,7 @@ class ReolinkHost:
return
try:
if self._api.session_active:
if self._api.session_active and not self._api.baichuan.privacy_mode():
await self._api.get_motion_state_all_ch()
except ReolinkError as err:
if not self._fast_poll_error:
@@ -834,7 +839,7 @@ class ReolinkHost:
)
self._fast_poll_error = True
else:
if self._api.session_active:
if self._api.session_active and not self._api.baichuan.privacy_mode():
self._fast_poll_error = False
finally:
# schedule next poll
@@ -1,5 +1,6 @@
"""The Shelly integration."""
import asyncio
from functools import partial
from typing import Final
@@ -73,6 +74,7 @@ from .utils import (
get_http_port,
get_rpc_scripts_event_types,
get_ws_context,
is_rpc_ble_scanner_supported,
remove_empty_sub_devices,
remove_stale_blu_trv_devices,
)
@@ -114,6 +116,9 @@ COAP_SCHEMA: Final = vol.Schema(
)
CONFIG_SCHEMA: Final = vol.Schema({DOMAIN: COAP_SCHEMA}, extra=vol.ALLOW_EXTRA)
# Max time to wait at startup for a BLE proxy to register its scanner.
STARTUP_SCANNER_WAIT: Final = 3.0
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
"""Set up the Shelly component."""
@@ -365,6 +370,21 @@ async def _async_setup_rpc_entry(hass: HomeAssistant, entry: ShellyConfigEntry)
runtime_data.rpc = ShellyRpcCoordinator(hass, entry, device)
runtime_data.rpc.async_setup()
if (
is_rpc_ble_scanner_supported(entry)
and entry.options.get(CONF_BLE_SCANNER_MODE, BLEScannerMode.DISABLED)
!= BLEScannerMode.DISABLED
):
# Wait for the proxy to register its scanner before finishing setup.
try:
async with asyncio.timeout(STARTUP_SCANNER_WAIT):
await runtime_data.rpc.ble_scanner_setup_done.wait()
except TimeoutError:
LOGGER.debug(
"%s: Timed out waiting for BLE scanner to register", entry.title
)
runtime_data.rpc_poll = ShellyRpcPollingCoordinator(hass, entry, device)
await hass.config_entries.async_forward_entry_setups(
entry, runtime_data.platforms
+24 -19
View File
@@ -521,6 +521,8 @@ class ShellyRpcCoordinator(ShellyCoordinatorBase[RpcDevice]):
super().__init__(hass, entry, device, update_interval)
self.connected = False
# Set once BLE scanner setup has been attempted after connecting.
self.ble_scanner_setup_done = asyncio.Event()
self._disconnected_callbacks: list[CALLBACK_TYPE] = []
self._connection_lock = asyncio.Lock()
self._event_listeners: list[Callable[[dict[str, Any]], None]] = []
@@ -759,27 +761,30 @@ class ShellyRpcCoordinator(ShellyCoordinatorBase[RpcDevice]):
async def _async_connect_ble_scanner(self) -> None:
"""Connect BLE scanner."""
ble_scanner_mode = self.config_entry.options.get(
CONF_BLE_SCANNER_MODE, BLEScannerMode.DISABLED
)
if ble_scanner_mode == BLEScannerMode.DISABLED and self.connected:
await async_stop_scanner(self.device)
async_remove_scanner(self.hass, self.bluetooth_source)
return
if await async_ensure_ble_enabled(self.device):
# BLE enable required a reboot, don't bother connecting
# the scanner since it will be disconnected anyway
LOGGER.debug(
"Device %s BLE enable required a reboot, skipping scanner connect",
self.name,
try:
ble_scanner_mode = self.config_entry.options.get(
CONF_BLE_SCANNER_MODE, BLEScannerMode.DISABLED
)
return
assert self.device_id is not None
self._disconnected_callbacks.append(
await async_connect_scanner(
self.hass, self, ble_scanner_mode, self.device_id
if ble_scanner_mode == BLEScannerMode.DISABLED and self.connected:
await async_stop_scanner(self.device)
async_remove_scanner(self.hass, self.bluetooth_source)
return
if await async_ensure_ble_enabled(self.device):
# BLE enable required a reboot, don't bother connecting
# the scanner since it will be disconnected anyway
LOGGER.debug(
"Device %s BLE enable required a reboot, skipping scanner connect",
self.name,
)
return
assert self.device_id is not None
self._disconnected_callbacks.append(
await async_connect_scanner(
self.hass, self, ble_scanner_mode, self.device_id
)
)
)
finally:
self.ble_scanner_setup_done.set()
@callback
def _async_handle_rpc_device_online(self) -> None:
+2 -2
View File
@@ -663,9 +663,9 @@ def is_view_for_platform(config: dict[str, Any], key: str, platform: str) -> boo
def get_virtual_component_unit(config: dict[str, Any]) -> str | None:
"""Return the unit of a virtual component.
If the unit is not set, the device sends an empty string
If the unit is not set, the device sends an empty string or the key may be absent.
"""
unit = config["meta"]["ui"]["unit"]
unit = config["meta"]["ui"].get("unit")
return DEVICE_UNIT_MAP.get(unit, unit) if unit else None
@@ -74,7 +74,7 @@ ATTR_QUERY_RESULT = "query_result"
_LOGGER = logging.getLogger(__name__)
PARALLEL_UPDATES = 1
PARALLEL_UPDATES = 0
ATTR_OTHER_PLAYER = "other_player"
@@ -22,7 +22,7 @@ from .entity import SqueezeboxEntity
_LOGGER = logging.getLogger(__name__)
PARALLEL_UPDATES = 1
PARALLEL_UPDATES = 0
async def async_setup_entry(
+9
View File
@@ -613,6 +613,10 @@ class ResultStream:
async for chunk in converted_audio:
yield chunk
def delete(self) -> None:
"""Remove the result stream from the manager."""
self._manager.async_delete_result_stream(self.token)
def _hash_options(options: dict) -> str:
"""Hashes an options dictionary."""
@@ -809,6 +813,11 @@ class SpeechManager:
stream.last_used = monotonic()
return stream
@callback
def async_delete_result_stream(self, token: str) -> None:
"""Delete a result stream given a token."""
self.token_to_stream.pop(token, None)
@callback
def async_create_result_stream(
self,
+3 -3
View File
@@ -1,6 +1,6 @@
"""Diagnostics support for V2C."""
from typing import TYPE_CHECKING, Any
from typing import TYPE_CHECKING, Any, cast
from homeassistant.components.diagnostics import async_redact_data
from homeassistant.const import CONF_HOST
@@ -21,11 +21,11 @@ async def async_get_config_entry_diagnostics(
assert coordinator.evse
coordinator_data = coordinator.evse.data
evse_raw_data = coordinator.evse.raw_data
evse_raw_data = cast(dict[str, Any], coordinator.evse.raw_data)
return {
"config_entry": async_redact_data(entry.as_dict(), TO_REDACT),
"data": str(coordinator_data),
"raw_data": evse_raw_data["content"].decode("utf-8"), # type: ignore[attr-defined]
"raw_data": evse_raw_data["content"].decode("utf-8"),
"host_status": evse_raw_data["status_code"],
}
+1 -1
View File
@@ -6,5 +6,5 @@
"documentation": "https://www.home-assistant.io/integrations/v2c",
"integration_type": "device",
"iot_class": "local_polling",
"requirements": ["pytrydan==1.0.0"]
"requirements": ["pytrydan==1.0.1"]
}
@@ -348,6 +348,8 @@ class WyomingAssistSatellite(WyomingSatelliteEntity, AssistSatelliteEntity):
# Use ffmpeg to convert to raw PCM audio with the appropriate format
proc = await asyncio.create_subprocess_exec(
self._ffmpeg_manager.binary,
"-protocol_whitelist",
"http,https,file,tcp,tls",
"-i",
announcement.media_id,
"-f",
@@ -6,5 +6,5 @@
"documentation": "https://www.home-assistant.io/integrations/yardian",
"integration_type": "device",
"iot_class": "local_polling",
"requirements": ["pyyardian==1.3.3"]
"requirements": ["pyyardian==1.4.0"]
}
@@ -30,7 +30,7 @@ POINT_ENTITIES = {
class ZinvoltBatteryStateDescription(BinarySensorEntityDescription):
"""Binary sensor description for Zinvolt battery state."""
is_on_fn: Callable[[ZinvoltData], bool]
is_on_fn: Callable[[ZinvoltData], bool | None]
SENSORS: tuple[ZinvoltBatteryStateDescription, ...] = (
@@ -84,7 +84,7 @@ class ZinvoltBatteryStateBinarySensor(ZinvoltEntity, BinarySensorEntity):
)
@property
def is_on(self) -> bool:
def is_on(self) -> bool | None:
"""Return the state of the binary sensor."""
return self.entity_description.is_on_fn(self.coordinator.data)
+10 -1
View File
@@ -1,6 +1,6 @@
"""Base entity for Zinvolt integration."""
from zinvolt.models import Unit
from zinvolt.models import OnlineStatus, Unit
from homeassistant.const import ATTR_VIA_DEVICE
from homeassistant.helpers.device_registry import DeviceInfo
@@ -25,6 +25,15 @@ class ZinvoltEntity(CoordinatorEntity[ZinvoltDeviceCoordinator]):
serial_number=coordinator.data.battery.serial_number,
)
@property
def available(self) -> bool:
"""Return if the entity is available."""
return (
super().available
and self.coordinator.data.battery.current_power.online_status
is OnlineStatus.ONLINE
)
class ZinvoltUnitEntity(ZinvoltEntity):
"""Base entity for Zinvolt units."""
@@ -8,5 +8,5 @@
"iot_class": "cloud_polling",
"loggers": ["zinvolt"],
"quality_scale": "bronze",
"requirements": ["zinvolt==0.4.3"]
"requirements": ["zinvolt==1.0.0"]
}
+5 -1
View File
@@ -34,7 +34,11 @@ NUMBERS: tuple[ZinvoltBatteryStateDescription, ...] = (
entity_category=EntityCategory.CONFIG,
device_class=NumberDeviceClass.POWER,
native_unit_of_measurement=UnitOfPower.WATT,
value_fn=lambda state: state.battery.global_settings.max_output,
value_fn=lambda state: (
2000
if state.battery.global_settings.max_output_unlocked
else state.battery.global_settings.max_output
),
set_value_fn=lambda client, battery_id, value: client.set_max_output(
battery_id, value
),
+9 -3
View File
@@ -21,7 +21,7 @@ from .entity import ZinvoltEntity
class ZinvoltBatteryStateDescription(SensorEntityDescription):
"""Sensor description for Zinvolt battery state."""
value_fn: Callable[[ZinvoltData], float]
value_fn: Callable[[ZinvoltData], float | None]
SENSORS: tuple[ZinvoltBatteryStateDescription, ...] = (
@@ -37,7 +37,13 @@ SENSORS: tuple[ZinvoltBatteryStateDescription, ...] = (
device_class=SensorDeviceClass.POWER,
state_class=SensorStateClass.MEASUREMENT,
native_unit_of_measurement=UnitOfPower.WATT,
value_fn=lambda state: 0 - state.battery.current_power.power_socket_output,
value_fn=(
lambda state: (
None
if state.battery.current_power.power_socket_output is None
else 0 - state.battery.current_power.power_socket_output
)
),
),
)
@@ -74,6 +80,6 @@ class ZinvoltBatteryStateSensor(ZinvoltEntity, SensorEntity):
)
@property
def native_value(self) -> float:
def native_value(self) -> float | None:
"""Return the state of the sensor."""
return self.entity_description.value_fn(self.coordinator.data)
+1 -1
View File
@@ -15,7 +15,7 @@ if TYPE_CHECKING:
APPLICATION_NAME: Final = "HomeAssistant"
MAJOR_VERSION: Final = 2026
MINOR_VERSION: Final = 6
PATCH_VERSION: Final = "1"
PATCH_VERSION: Final = "2"
__short_version__: Final = f"{MAJOR_VERSION}.{MINOR_VERSION}"
__version__: Final = f"{__short_version__}.{PATCH_VERSION}"
REQUIRED_PYTHON_VER: Final[tuple[int, int, int]] = (3, 14, 2)
+1 -1
View File
@@ -39,7 +39,7 @@ habluetooth==6.8.1
hass-nabucasa==2.2.0
hassil==3.5.0
home-assistant-bluetooth==2.0.0
home-assistant-frontend==20260527.4
home-assistant-frontend==20260527.5
home-assistant-intents==2026.6.1
httpx==0.28.1
ifaddr==0.2.0
+1 -1
View File
@@ -5,7 +5,7 @@ To update, run python3 -m script.hassfest
from typing import Final
FRONTEND_VERSION: Final[str] = "20260527.4"
FRONTEND_VERSION: Final[str] = "20260527.5"
MDI_ICONS: Final[set[str]] = {
"ab-testing",
+1 -1
View File
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
[project]
name = "homeassistant"
version = "2026.6.1"
version = "2026.6.2"
license = "Apache-2.0"
license-files = ["LICENSE*", "homeassistant/backports/LICENSE*"]
description = "Open-source home automation platform running on Python 3."
+9 -9
View File
@@ -1266,7 +1266,7 @@ hole==0.9.0
holidays==0.98
# homeassistant.components.frontend
home-assistant-frontend==20260527.4
home-assistant-frontend==20260527.5
# homeassistant.components.conversation
home-assistant-intents==2026.6.1
@@ -1577,7 +1577,7 @@ millheater==0.14.1
minio==7.1.12
# homeassistant.components.mitsubishi_comfort
mitsubishi-comfort==0.3.0
mitsubishi-comfort==0.3.1
# homeassistant.components.moat
moat-ble==0.1.1
@@ -1776,7 +1776,7 @@ openwrt-luci-rpc==1.1.17
openwrt-ubus-rpc==0.0.2
# homeassistant.components.opower
opower==0.18.2
opower==0.18.4
# homeassistant.components.oralb
oralb-ble==1.1.0
@@ -1843,7 +1843,7 @@ plexauth==0.0.6
plexwebsocket==0.0.14
# homeassistant.components.plugwise
plugwise==1.11.3
plugwise==1.11.4
# homeassistant.components.serial_pm
pmsensor==0.4
@@ -2081,7 +2081,7 @@ pycsspeechtts==1.0.8
pycync==0.5.0
# homeassistant.components.daikin
pydaikin==2.17.2
pydaikin==2.18.1
# homeassistant.components.danfoss_air
pydanfossair==0.1.0
@@ -2773,7 +2773,7 @@ pytradfri[async]==9.0.1
pytrafikverket==1.1.1
# homeassistant.components.v2c
pytrydan==1.0.0
pytrydan==1.0.1
# homeassistant.components.uptimerobot
pyuptimerobot==25.0.0
@@ -2824,7 +2824,7 @@ pyws66i==1.1
pyxeoma==1.4.2
# homeassistant.components.yardian
pyyardian==1.3.3
pyyardian==1.4.0
# homeassistant.components.qrcode
pyzbar==0.1.9
@@ -2872,7 +2872,7 @@ refoss-ha==1.2.5
regenmaschine==2024.03.0
# homeassistant.components.renault
renault-api==0.5.11
renault-api==0.5.12
# homeassistant.components.renson
renson-endura-delta==1.7.2
@@ -3451,7 +3451,7 @@ zhong-hong-hvac==1.0.13
ziggo-mediabox-xl==1.1.0
# homeassistant.components.zinvolt
zinvolt==0.4.3
zinvolt==1.0.0
# homeassistant.components.zoneminder
zm-py==0.5.4
@@ -91,6 +91,48 @@ async def test_coordinator_load_previous_devices_from_registry(
assert coordinator.previous_devices == {TEST_DEVICE_1_SN}
@pytest.mark.parametrize(
("side_effect", "expected_state"),
[
pytest.param(
CannotConnect,
ConfigEntryState.SETUP_RETRY,
id="cannot_connect",
),
pytest.param(
CannotRetrieveData,
ConfigEntryState.SETUP_RETRY,
id="cannot_retrieve_data",
),
pytest.param(
CannotAuthenticate,
ConfigEntryState.SETUP_ERROR,
id="cannot_authenticate",
),
pytest.param(
ValueError,
ConfigEntryState.SETUP_RETRY,
id="value_error",
),
],
)
async def test_async_update_data_errors(
hass: HomeAssistant,
mock_amazon_devices_client: AsyncMock,
mock_config_entry: MockConfigEntry,
side_effect: type[Exception],
expected_state: ConfigEntryState,
) -> None:
"""Test _async_update_data error handling."""
mock_amazon_devices_client.get_devices_data.side_effect = side_effect
mock_config_entry.add_to_hass(hass)
await hass.config_entries.async_setup(mock_config_entry.entry_id)
await hass.async_block_till_done()
assert mock_config_entry.state is expected_state
@pytest.mark.parametrize(
("side_effect", "expected_state"),
[
+30 -4
View File
@@ -3,7 +3,11 @@
from unittest.mock import AsyncMock
from aioamazondevices.const.devices import SPEAKER_GROUP_FAMILY
from aioamazondevices.exceptions import CannotConnect, CannotRetrieveData
from aioamazondevices.exceptions import (
CannotAuthenticate,
CannotConnect,
CannotRetrieveData,
)
import pytest
from homeassistant.components.alexa_devices.const import DOMAIN
@@ -25,15 +29,37 @@ ENTITY_ID = "switch.echo_test_do_not_disturb"
@pytest.mark.parametrize(
("side_effect", "key", "error"),
[
(CannotConnect, "cannot_connect_with_error", "CannotConnect()"),
(CannotRetrieveData, "cannot_retrieve_data_with_error", "CannotRetrieveData()"),
pytest.param(
CannotAuthenticate,
"invalid_auth",
"CannotAuthenticate()",
id="cannot_authenticate",
),
pytest.param(
CannotConnect,
"cannot_connect_with_error",
"CannotConnect()",
id="cannot_connect",
),
pytest.param(
CannotRetrieveData,
"cannot_retrieve_data_with_error",
"CannotRetrieveData()",
id="cannot_retrieve_data",
),
pytest.param(
ValueError,
"cannot_retrieve_data_with_error",
"ValueError()",
id="value_error",
),
],
)
async def test_alexa_api_call_exceptions(
hass: HomeAssistant,
mock_amazon_devices_client: AsyncMock,
mock_config_entry: MockConfigEntry,
side_effect: Exception,
side_effect: type[Exception],
key: str,
error: str,
) -> None:
@@ -2274,3 +2274,86 @@ async def test_stt_vad_enabled_based_on_audio_processing(
# VAD should NOT be created when requires_external_vad is False
mock_vad.assert_not_called()
async def test_invalid_pipeline_does_not_create_tts_stream(
hass: HomeAssistant,
mock_wake_word_provider_entity: MockWakeWordEntity,
init_components,
) -> None:
"""Test that an invalid pipeline won't create a TTS ResultStream."""
pipeline = async_get_pipeline(hass, None)
await async_update_pipeline(hass, pipeline, stt_engine="does-not-exist")
async def audio_data() -> AsyncGenerator[bytes]:
yield make_10ms_chunk(b"not used")
with patch.object(
mock_wake_word_provider_entity,
"async_process_audio_stream",
side_effect=assist_pipeline.error.WakeWordTimeoutError(
code="timeout", message="timeout"
),
):
await assist_pipeline.async_pipeline_from_audio_stream(
hass,
context=Context(),
event_callback=lambda event: None,
stt_metadata=stt.SpeechMetadata(
language="",
format=stt.AudioFormats.WAV,
codec=stt.AudioCodecs.PCM,
bit_rate=stt.AudioBitRates.BITRATE_16,
sample_rate=stt.AudioSampleRates.SAMPLERATE_16000,
channel=stt.AudioChannels.CHANNEL_MONO,
),
stt_stream=audio_data(),
start_stage=assist_pipeline.PipelineStage.STT,
end_stage=assist_pipeline.PipelineStage.TTS,
audio_settings=assist_pipeline.AudioSettings(is_vad_enabled=False),
)
assert len(hass.data[tts.DATA_TTS_MANAGER].token_to_stream) == 0
async def test_pipeline_error_before_tts_does_not_leak_result_stream(
hass: HomeAssistant,
mock_wake_word_provider_entity: MockWakeWordEntity,
init_components,
) -> None:
"""Test that a pipeline error before TTS will not leak a ResultStream."""
async def audio_data() -> AsyncGenerator[bytes]:
yield make_10ms_chunk(b"not used")
with patch.object(
mock_wake_word_provider_entity,
"async_process_audio_stream",
side_effect=assist_pipeline.error.WakeWordTimeoutError(
code="timeout", message="timeout"
),
):
for i in range(10):
with patch("secrets.token_urlsafe", return_value=f"mocked-token-{i}"):
await assist_pipeline.async_pipeline_from_audio_stream(
hass,
context=Context(),
event_callback=lambda event: None,
stt_metadata=stt.SpeechMetadata(
language="",
format=stt.AudioFormats.WAV,
codec=stt.AudioCodecs.PCM,
bit_rate=stt.AudioBitRates.BITRATE_16,
sample_rate=stt.AudioSampleRates.SAMPLERATE_16000,
channel=stt.AudioChannels.CHANNEL_MONO,
),
stt_stream=audio_data(),
start_stage=assist_pipeline.PipelineStage.WAKE_WORD,
end_stage=assist_pipeline.PipelineStage.TTS,
wake_word_settings=assist_pipeline.WakeWordSettings(
audio_seconds_to_buffer=1.5
),
audio_settings=assist_pipeline.AudioSettings(is_vad_enabled=False),
)
assert len(hass.data[tts.DATA_TTS_MANAGER].token_to_stream) == 0
+123
View File
@@ -9,7 +9,9 @@ from unittest.mock import AsyncMock, Mock, call, patch
from aioesphomeapi import (
APIClient,
APIConnectionError,
APIVersion,
AreaInfo,
BluetoothProxyFeature,
DeviceInfo,
EncryptionPlaintextAPIError,
ExecuteServiceResponse,
@@ -3274,3 +3276,124 @@ async def test_service_registration_response_types(
hass.services.supports_response(DOMAIN, "test_status_service")
== SupportsResponse.NONE
)
def _create_cached_bluetooth_proxy_entry(
hass: HomeAssistant,
hass_storage: dict[str, Any],
bluetooth_proxy_feature_flags: BluetoothProxyFeature,
) -> tuple[MockConfigEntry, DeviceInfo]:
"""Create an entry with cached device info so setup knows the proxy state."""
entry = MockConfigEntry(
domain=DOMAIN,
unique_id="11:22:33:44:55:aa",
data={
CONF_HOST: "test.local",
CONF_PORT: 6053,
CONF_PASSWORD: "",
CONF_BLUETOOTH_MAC_ADDRESS: "AA:BB:CC:DD:EE:FC",
},
)
entry.add_to_hass(hass)
device_info = DeviceInfo(
name="test",
mac_address="11:22:33:44:55:AA",
bluetooth_mac_address="AA:BB:CC:DD:EE:FC",
bluetooth_proxy_feature_flags=bluetooth_proxy_feature_flags,
)
storage_key = f"{DOMAIN}.{entry.entry_id}"
hass_storage[storage_key] = {
"version": 1,
"minor_version": 1,
"key": storage_key,
"data": {
"device_info": device_info.to_dict(),
"api_version": APIVersion(1, 9).to_dict(),
},
}
return entry, device_info
@pytest.mark.usefixtures("mock_zeroconf")
async def test_bluetooth_proxy_waits_for_scanner_at_startup(
hass: HomeAssistant,
mock_client: APIClient,
hass_storage: dict[str, Any],
) -> None:
"""Test setup waits for a cached bluetooth proxy to register its scanner."""
entry, device_info = _create_cached_bluetooth_proxy_entry(
hass, hass_storage, BluetoothProxyFeature.PASSIVE_SCAN
)
connect_event = asyncio.Event()
reached_connect = asyncio.Event()
async def _block_until_released() -> tuple[DeviceInfo, list[Any], list[Any]]:
reached_connect.set()
await connect_event.wait()
return (device_info, [], [])
mock_client.device_info_and_list_entities = _block_until_released
setup_task = hass.async_create_task(hass.config_entries.async_setup(entry.entry_id))
async with asyncio.timeout(2):
await reached_connect.wait()
# Setup must still be waiting for the scanner to be registered.
assert not setup_task.done()
connect_event.set()
async with asyncio.timeout(2):
assert await setup_task is True
assert entry.runtime_data.first_connect_done.is_set()
@pytest.mark.usefixtures("mock_zeroconf")
async def test_bluetooth_proxy_startup_wait_times_out(
hass: HomeAssistant,
mock_client: APIClient,
hass_storage: dict[str, Any],
) -> None:
"""Test setup finishes if a cached bluetooth proxy never connects."""
entry, device_info = _create_cached_bluetooth_proxy_entry(
hass, hass_storage, BluetoothProxyFeature.PASSIVE_SCAN
)
connect_event = asyncio.Event()
async def _never_returns() -> tuple[DeviceInfo, list[Any], list[Any]]:
await connect_event.wait()
return (device_info, [], [])
mock_client.device_info_and_list_entities = _never_returns
with patch("homeassistant.components.esphome.manager.STARTUP_SCANNER_WAIT", 0.05):
async with asyncio.timeout(2):
assert await hass.config_entries.async_setup(entry.entry_id) is True
connect_event.set()
await hass.async_block_till_done()
@pytest.mark.usefixtures("mock_zeroconf")
async def test_non_bluetooth_device_does_not_wait_at_startup(
hass: HomeAssistant,
mock_client: APIClient,
hass_storage: dict[str, Any],
) -> None:
"""Test setup does not wait for a device that is not a bluetooth proxy."""
entry, device_info = _create_cached_bluetooth_proxy_entry(
hass, hass_storage, BluetoothProxyFeature(0)
)
connect_event = asyncio.Event()
async def _never_returns() -> tuple[DeviceInfo, list[Any], list[Any]]:
await connect_event.wait()
return (device_info, [], [])
mock_client.device_info_and_list_entities = _never_returns
# The connection is blocked, but without proxy flags setup must not wait.
async with asyncio.timeout(2):
assert await hass.config_entries.async_setup(entry.entry_id) is True
connect_event.set()
await hass.async_block_till_done()
+33 -8
View File
@@ -11,11 +11,10 @@ from gardena_bluetooth.client import Client
from gardena_bluetooth.const import DeviceInformation
from gardena_bluetooth.exceptions import CharacteristicNotFound
from gardena_bluetooth.parse import Characteristic, Service
from gardena_bluetooth.scan import (
async_get_manufacturer_data as _async_get_manufacturer_data,
)
import pytest
from homeassistant.components import bluetooth
from homeassistant.components.gardena_bluetooth import async_get_product_type
from homeassistant.components.gardena_bluetooth.const import DOMAIN
from homeassistant.components.gardena_bluetooth.coordinator import SCAN_INTERVAL
from homeassistant.core import HomeAssistant
@@ -178,23 +177,49 @@ def enable_all_entities(entity_registry_enabled_by_default: None) -> None:
@pytest.fixture
def manufacturer_request_event() -> Generator[asyncio.Event]:
"""Track manufacturer data requests with an event."""
def get_product_type_event() -> Generator[asyncio.Event]:
"""Track product type data requests with an event."""
event = asyncio.Event()
async def _get(*args, **kwargs):
event.set()
return await _async_get_manufacturer_data(*args, **kwargs)
return await async_get_product_type(*args, **kwargs)
with (
patch(
"homeassistant.components.gardena_bluetooth.async_get_manufacturer_data",
"homeassistant.components.gardena_bluetooth.async_get_product_type",
wraps=_get,
),
patch(
"homeassistant.components.gardena_bluetooth.config_flow.async_get_manufacturer_data",
"homeassistant.components.gardena_bluetooth.config_flow.async_get_product_type",
wraps=_get,
),
):
yield event
@pytest.fixture
def constant_advertisements() -> Generator[None]:
"""Ensure async_process_advertisements only return a constant list."""
async def _advertisements(
hass: HomeAssistant,
callback: bluetooth.models.ProcessAdvertisementCallback,
match_dict: bluetooth.match.BluetoothCallbackMatcher,
mode: bluetooth.BluetoothScanningMode,
timeout: int,
) -> bluetooth.BluetoothServiceInfoBleak:
last = None
for advertisement in bluetooth.async_discovered_service_info(hass):
callback(advertisement)
last = advertisement
if not last:
raise TimeoutError
return last
with (
patch.object(bluetooth, "async_process_advertisements", new=_advertisements),
):
yield
@@ -1,7 +1,5 @@
"""Test the Gardena Bluetooth config flow."""
import asyncio
from collections.abc import Awaitable, Callable
from unittest.mock import Mock
from gardena_bluetooth.exceptions import CharacteristicNotFound
@@ -26,13 +24,10 @@ from . import (
from tests.common import MockConfigEntry
from tests.components.bluetooth import inject_bluetooth_service_info
pytestmark = pytest.mark.usefixtures("mock_setup_entry")
pytestmark = pytest.mark.usefixtures("mock_setup_entry", "constant_advertisements")
async def test_user_selection(
hass: HomeAssistant,
snapshot: SnapshotAssertion,
) -> None:
async def test_user_selection(hass: HomeAssistant, snapshot: SnapshotAssertion) -> None:
"""Test we can select a device."""
inject_bluetooth_service_info(hass, WATER_TIMER_SERVICE_INFO)
@@ -138,9 +133,6 @@ async def test_no_valid_devices(
async def test_timeout_manufacturer_data(
hass: HomeAssistant,
snapshot: SnapshotAssertion,
scan_step: Callable[[], Awaitable[None]],
manufacturer_request_event: asyncio.Event,
) -> None:
"""Test the flow aborts with no_devices_found.
@@ -149,24 +141,9 @@ async def test_timeout_manufacturer_data(
"""
inject_bluetooth_service_info(hass, MISSING_PRODUCT_SERVICE_INFO)
# The injected advertisement starts a bluetooth discovery flow which also
# calls async_get_manufacturer_data. Drain it first so it doesn't race
# with the user flow's own request.
await manufacturer_request_event.wait()
await scan_step()
await hass.async_block_till_done(wait_background_tasks=True)
manufacturer_request_event.clear()
async with asyncio.TaskGroup() as tg:
task = tg.create_task(
hass.config_entries.flow.async_init(
DOMAIN, context={"source": config_entries.SOURCE_USER}
)
)
await manufacturer_request_event.wait()
await scan_step()
result = await task
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": config_entries.SOURCE_USER}
)
assert result.get("type") == "abort"
assert result.get("reason") == "no_devices_found"
@@ -72,6 +72,7 @@ from tests.components.bluetooth import inject_bluetooth_service_info
),
],
)
@pytest.mark.usefixtures("constant_advertisements")
async def test_setup(
hass: HomeAssistant,
device_registry: dr.DeviceRegistry,
@@ -99,7 +100,7 @@ async def test_setup_delayed_product(
device_registry: dr.DeviceRegistry,
mock_entry: MockConfigEntry,
mock_read_char_raw: dict[str, bytes],
manufacturer_request_event: asyncio.Event,
get_product_type_event: asyncio.Event,
snapshot: SnapshotAssertion,
) -> None:
"""Test setup creates expected devices."""
@@ -107,15 +108,16 @@ async def test_setup_delayed_product(
mock_read_char_raw[Battery.battery_level.uuid] = Battery.battery_level.encode(100)
mock_entry.add_to_hass(hass)
await hass.async_block_till_done()
manufacturer_request_event.clear()
get_product_type_event.clear()
async with asyncio.TaskGroup() as tg:
setup_task = tg.create_task(
hass.config_entries.async_setup(mock_entry.entry_id)
)
await manufacturer_request_event.wait()
await get_product_type_event.wait()
assert mock_entry.state is ConfigEntryState.SETUP_IN_PROGRESS
inject_bluetooth_service_info(hass, MISSING_MANUFACTURER_DATA_SERVICE_INFO)
inject_bluetooth_service_info(hass, WATER_TIMER_SERVICE_INFO)
@@ -123,6 +125,7 @@ async def test_setup_delayed_product(
assert await setup_task is True
@pytest.mark.usefixtures("constant_advertisements")
async def test_setup_retry(
hass: HomeAssistant, mock_entry: MockConfigEntry, mock_client: Mock
) -> None:
@@ -26,6 +26,8 @@ from . import AQUA_CONTOUR_SERVICE_INFO, WATER_TIMER_SERVICE_INFO, setup_entry
from tests.common import MockConfigEntry
pytestmark = pytest.mark.usefixtures("constant_advertisements")
@pytest.mark.parametrize(
("service_info", "uuid", "raw", "entity_id"),
@@ -25,6 +25,8 @@ from . import AQUA_CONTOUR_SERVICE_INFO, setup_entry
from tests.common import MockConfigEntry, snapshot_platform
pytestmark = pytest.mark.usefixtures("constant_advertisements")
@pytest.fixture
def mock_chars(mock_read_char_raw):
@@ -27,6 +27,8 @@ from . import AQUA_CONTOUR_SERVICE_INFO, WATER_TIMER_SERVICE_INFO, setup_entry
from tests.common import MockConfigEntry, snapshot_platform
pytestmark = pytest.mark.usefixtures("constant_advertisements")
@pytest.mark.parametrize(
("service_info", "uuid", "raw", "entity_id"),
@@ -20,6 +20,8 @@ from . import setup_entry
from tests.common import MockConfigEntry
pytestmark = pytest.mark.usefixtures("constant_advertisements")
@pytest.fixture
def mock_switch_chars(mock_read_char_raw):
@@ -20,6 +20,8 @@ from . import AQUA_CONTOUR_SERVICE_INFO, setup_entry
from tests.common import snapshot_platform
pytestmark = pytest.mark.usefixtures("constant_advertisements")
@pytest.mark.parametrize(
("service_info", "raw"),
@@ -20,6 +20,8 @@ from . import setup_entry
from tests.common import MockConfigEntry
pytestmark = pytest.mark.usefixtures("constant_advertisements")
@pytest.fixture
def mock_switch_chars(mock_read_char_raw):
@@ -234,6 +234,75 @@ async def test_config_entry_migration_v2_prefers_active_entry(
assert active_entry.unique_id == serial_number
async def test_config_entry_migration_v2_removes_duplicates_of_migrated_entry(
hass: HomeAssistant,
) -> None:
"""Test v1.2 migration removes duplicates of an already migrated entry.
A migrated entry (minor version 2) never runs the migration again, so the
remaining minor version 1 duplicates have to remove themselves instead of
relying on the canonical entry's migration to remove them.
"""
serial_number = "E072A1D90104"
data = {
"device": "/dev/serial/by-id/usb-Nabu_Casa_ZBT-2_E072A1D90104-if00",
"firmware": "spinel",
"firmware_version": (
"SL-OPENTHREAD/2.7.2.0_GitHub-fb0446f53; EFR32; Feb 24 2026 00:58:55"
),
"manufacturer": "Nabu Casa",
"pid": "831A",
"product": "ZBT-2",
"serial_number": serial_number,
"vid": "303A",
}
older_entry = MockConfigEntry(
domain=DOMAIN,
unique_id="303A:831A_E072A1D90104_Nabu Casa_ZBT-2 - Nabu Casa ZBT-2",
source="usb",
data=dict(data),
version=1,
minor_version=1,
)
older_entry.add_to_hass(hass)
duplicate_entry = MockConfigEntry(
domain=DOMAIN,
unique_id="303A:831A_E072A1D90104_Nabu Casa_ZBT-2",
source="import",
data=dict(data),
version=1,
minor_version=1,
)
duplicate_entry.add_to_hass(hass)
migrated_entry = MockConfigEntry(
domain=DOMAIN,
unique_id=serial_number,
source="import",
data=dict(data),
version=1,
minor_version=2,
)
migrated_entry.add_to_hass(hass)
with patch(
"homeassistant.components.homeassistant_connect_zbt2.os.path.exists",
return_value=True,
):
await async_setup_component(hass, DOMAIN, {})
await hass.async_block_till_done()
remaining_entries = hass.config_entries.async_entries(DOMAIN)
assert len(remaining_entries) == 1
assert remaining_entries[0].entry_id == migrated_entry.entry_id
assert remaining_entries[0].minor_version == 2
assert remaining_entries[0].unique_id == serial_number
assert hass.config_entries.async_get_entry(older_entry.entry_id) is None
assert hass.config_entries.async_get_entry(duplicate_entry.entry_id) is None
async def test_setup_fails_on_missing_usb_port(hass: HomeAssistant) -> None:
"""Test setup failing when the USB port is missing."""
@@ -306,6 +306,79 @@ async def test_config_entry_migration_v5_prefers_active_entry(
assert active_entry.unique_id == serial_number
async def test_config_entry_migration_v5_removes_duplicates_of_migrated_entry(
hass: HomeAssistant,
) -> None:
"""Test v1.5 migration removes duplicates of an already migrated entry.
A migrated entry (minor version 5) never runs the migration again, so the
remaining minor version 4 duplicates have to remove themselves instead of
relying on the canonical entry's migration to remove them.
"""
serial_number = "9e2adbd75b8beb119fe564a0f320645d"
data = {
"description": "SkyConnect v1.0",
"device": (
"/dev/serial/by-id/"
"usb-Nabu_Casa_SkyConnect_v1.0_9e2adbd75b8beb119fe564a0f320645d-if00-port0"
),
"vid": "10C4",
"pid": "EA60",
"serial_number": serial_number,
"manufacturer": "Nabu Casa",
"product": "SkyConnect v1.0",
"firmware": "ezsp",
"firmware_version": "7.4.4.0",
}
older_entry = MockConfigEntry(
domain=DOMAIN,
unique_id=(
"10C4:EA60_9e2adbd75b8beb119fe564a0f320645d_Nabu Casa_SkyConnect v1.0"
),
source="usb",
data=dict(data),
version=1,
minor_version=4,
)
older_entry.add_to_hass(hass)
duplicate_entry = MockConfigEntry(
domain=DOMAIN,
unique_id="10C4:EA60_9e2adbd75b8beb119fe564a0f320645d_Nabu_Casa_SkyConnect",
source="import",
data=dict(data),
version=1,
minor_version=4,
)
duplicate_entry.add_to_hass(hass)
migrated_entry = MockConfigEntry(
domain=DOMAIN,
unique_id=serial_number,
source="import",
data=dict(data),
version=1,
minor_version=5,
)
migrated_entry.add_to_hass(hass)
with patch(
"homeassistant.components.homeassistant_sky_connect.os.path.exists",
return_value=True,
):
await async_setup_component(hass, DOMAIN, {})
await hass.async_block_till_done()
remaining = hass.config_entries.async_entries(DOMAIN)
assert len(remaining) == 1
assert remaining[0].entry_id == migrated_entry.entry_id
assert remaining[0].minor_version == 5
assert remaining[0].unique_id == serial_number
assert hass.config_entries.async_get_entry(older_entry.entry_id) is None
assert hass.config_entries.async_get_entry(duplicate_entry.entry_id) is None
async def test_setup_fails_on_missing_usb_port(hass: HomeAssistant) -> None:
"""Test setup failing when the USB port is missing."""
+73 -74
View File
@@ -17,6 +17,7 @@ from homeassistant import config as module_hass_config
from homeassistant.components import mqtt
from homeassistant.components.mqtt import debug_info
from homeassistant.components.mqtt.const import (
DOMAIN,
MQTT_CONNECTION_STATE,
SUPPORTED_COMPONENTS,
)
@@ -1004,12 +1005,10 @@ def help_custom_config(
config: ConfigType = copy.deepcopy(mqtt_base_config)
entity_instances: list[ConfigType] = []
for instance in mqtt_entity_configs:
base: ConfigType = copy.deepcopy(
mqtt_base_config[mqtt.DOMAIN][mqtt_entity_domain]
)
base: ConfigType = copy.deepcopy(mqtt_base_config[DOMAIN][mqtt_entity_domain])
base.update(instance)
entity_instances.append(base)
config[mqtt.DOMAIN][mqtt_entity_domain] = entity_instances
config[DOMAIN][mqtt_entity_domain] = entity_instances
return config
@@ -1038,7 +1037,7 @@ async def help_test_availability_without_topic(
config: ConfigType,
) -> None:
"""Test availability without defined availability topic."""
assert "availability_topic" not in config[mqtt.DOMAIN][domain]
assert "availability_topic" not in config[DOMAIN][domain]
await mqtt_mock_entry()
await hass.async_block_till_done()
@@ -1061,7 +1060,7 @@ async def help_test_default_availability_payload(
"""
# Add availability settings to config
config = copy.deepcopy(config)
config[mqtt.DOMAIN][domain]["availability_topic"] = "availability-topic"
config[DOMAIN][domain]["availability_topic"] = "availability-topic"
with patch("homeassistant.config.load_yaml_config_file", return_value=config):
await mqtt_mock_entry()
@@ -1108,7 +1107,7 @@ async def help_test_default_availability_list_payload(
"""
# Add availability settings to config
config = copy.deepcopy(config)
config[mqtt.DOMAIN][domain]["availability"] = [
config[DOMAIN][domain]["availability"] = [
{"topic": "availability-topic1"},
{"topic": "availability-topic2"},
]
@@ -1167,8 +1166,8 @@ async def help_test_default_availability_list_payload_all(
"""
# Add availability settings to config
config = copy.deepcopy(config)
config[mqtt.DOMAIN][domain]["availability_mode"] = "all"
config[mqtt.DOMAIN][domain]["availability"] = [
config[DOMAIN][domain]["availability_mode"] = "all"
config[DOMAIN][domain]["availability"] = [
{"topic": "availability-topic1"},
{"topic": "availability-topic2"},
]
@@ -1228,8 +1227,8 @@ async def help_test_default_availability_list_payload_any(
"""
# Add availability settings to config
config = copy.deepcopy(config)
config[mqtt.DOMAIN][domain]["availability_mode"] = "any"
config[mqtt.DOMAIN][domain]["availability"] = [
config[DOMAIN][domain]["availability_mode"] = "any"
config[DOMAIN][domain]["availability"] = [
{"topic": "availability-topic1"},
{"topic": "availability-topic2"},
]
@@ -1284,10 +1283,10 @@ async def help_test_default_availability_list_single(
"""
# Add availability settings to config
config = copy.deepcopy(config)
config[mqtt.DOMAIN][domain]["availability"] = [
config[DOMAIN][domain]["availability"] = [
{"topic": "availability-topic1"},
]
config[mqtt.DOMAIN][domain]["availability_topic"] = "availability-topic"
config[DOMAIN][domain]["availability_topic"] = "availability-topic"
with (
patch("homeassistant.config.load_yaml_config_file", return_value=config),
@@ -1316,9 +1315,9 @@ async def help_test_custom_availability_payload(
"""
# Add availability settings to config
config = copy.deepcopy(config)
config[mqtt.DOMAIN][domain]["availability_topic"] = "availability-topic"
config[mqtt.DOMAIN][domain]["payload_available"] = "good"
config[mqtt.DOMAIN][domain]["payload_not_available"] = "nogood"
config[DOMAIN][domain]["availability_topic"] = "availability-topic"
config[DOMAIN][domain]["payload_available"] = "good"
config[DOMAIN][domain]["payload_not_available"] = "nogood"
with patch("homeassistant.config.load_yaml_config_file", return_value=config):
await mqtt_mock_entry()
@@ -1362,17 +1361,17 @@ async def help_test_discovery_update_availability(
await mqtt_mock_entry()
# Add availability settings to config
config1 = copy.deepcopy(config)
config1[mqtt.DOMAIN][domain]["availability_topic"] = "availability-topic1"
config1[DOMAIN][domain]["availability_topic"] = "availability-topic1"
config2 = copy.deepcopy(config)
config2[mqtt.DOMAIN][domain]["availability"] = [
config2[DOMAIN][domain]["availability"] = [
{"topic": "availability-topic2"},
{"topic": "availability-topic3"},
]
config3 = copy.deepcopy(config)
config3[mqtt.DOMAIN][domain]["availability_topic"] = "availability-topic4"
data1 = json.dumps(config1[mqtt.DOMAIN][domain])
data2 = json.dumps(config2[mqtt.DOMAIN][domain])
data3 = json.dumps(config3[mqtt.DOMAIN][domain])
config3[DOMAIN][domain]["availability_topic"] = "availability-topic4"
data1 = json.dumps(config1[DOMAIN][domain])
data2 = json.dumps(config2[DOMAIN][domain])
data3 = json.dumps(config3[DOMAIN][domain])
async_fire_mqtt_message(hass, f"homeassistant/{domain}/bla/config", data1)
await hass.async_block_till_done()
@@ -1439,7 +1438,7 @@ async def help_test_setting_attribute_via_mqtt_json_message(
"""
# Add JSON attributes settings to config
config = copy.deepcopy(config)
config[mqtt.DOMAIN][domain]["json_attributes_topic"] = "attr-topic"
config[DOMAIN][domain]["json_attributes_topic"] = "attr-topic"
with patch("homeassistant.config.load_yaml_config_file", return_value=config):
await mqtt_mock_entry()
@@ -1465,8 +1464,8 @@ async def help_test_setting_blocked_attribute_via_mqtt_json_message(
# Add JSON attributes settings to config
config = copy.deepcopy(config)
config[mqtt.DOMAIN][domain]["json_attributes_topic"] = "attr-topic"
data = json.dumps(config[mqtt.DOMAIN][domain])
config[DOMAIN][domain]["json_attributes_topic"] = "attr-topic"
data = json.dumps(config[DOMAIN][domain])
async_fire_mqtt_message(hass, f"homeassistant/{domain}/bla/config", data)
await hass.async_block_till_done()
val = "abc123"
@@ -1494,8 +1493,8 @@ async def help_test_setting_attribute_with_template(
"""
# Add JSON attributes settings to config
config = copy.deepcopy(config)
config[mqtt.DOMAIN][domain]["json_attributes_topic"] = "attr-topic"
config[mqtt.DOMAIN][domain]["json_attributes_template"] = (
config[DOMAIN][domain]["json_attributes_topic"] = "attr-topic"
config[DOMAIN][domain]["json_attributes_template"] = (
"{{ value_json['Timer1'] | tojson }}"
)
with patch("homeassistant.config.load_yaml_config_file", return_value=config):
@@ -1524,7 +1523,7 @@ async def help_test_update_with_json_attrs_not_dict(
"""
# Add JSON attributes settings to config
config = copy.deepcopy(config)
config[mqtt.DOMAIN][domain]["json_attributes_topic"] = "attr-topic"
config[DOMAIN][domain]["json_attributes_topic"] = "attr-topic"
with patch("homeassistant.config.load_yaml_config_file", return_value=config):
await mqtt_mock_entry()
@@ -1548,7 +1547,7 @@ async def help_test_update_with_json_attrs_bad_json(
"""
# Add JSON attributes settings to config
config = copy.deepcopy(config)
config[mqtt.DOMAIN][domain]["json_attributes_topic"] = "attr-topic"
config[DOMAIN][domain]["json_attributes_topic"] = "attr-topic"
with patch("homeassistant.config.load_yaml_config_file", return_value=config):
await mqtt_mock_entry()
@@ -1572,11 +1571,11 @@ async def help_test_discovery_update_attr(
await mqtt_mock_entry()
# Add JSON attributes settings to config
config1 = copy.deepcopy(config)
config1[mqtt.DOMAIN][domain]["json_attributes_topic"] = "attr-topic1"
config1[DOMAIN][domain]["json_attributes_topic"] = "attr-topic1"
config2 = copy.deepcopy(config)
config2[mqtt.DOMAIN][domain]["json_attributes_topic"] = "attr-topic2"
data1 = json.dumps(config1[mqtt.DOMAIN][domain])
data2 = json.dumps(config2[mqtt.DOMAIN][domain])
config2[DOMAIN][domain]["json_attributes_topic"] = "attr-topic2"
data1 = json.dumps(config1[DOMAIN][domain])
data2 = json.dumps(config2[DOMAIN][domain])
async_fire_mqtt_message(hass, f"homeassistant/{domain}/bla/config", data1)
await hass.async_block_till_done()
@@ -1895,7 +1894,7 @@ async def help_test_entity_device_info_with_identifier(
"""
await mqtt_mock_entry()
# Add device settings to config
config = copy.deepcopy(config[mqtt.DOMAIN][domain])
config = copy.deepcopy(config[DOMAIN][domain])
config["device"] = copy.deepcopy(DEFAULT_CONFIG_DEVICE_INFO_ID)
config["unique_id"] = "veryunique"
@@ -1931,7 +1930,7 @@ async def help_test_entity_device_info_with_connection(
"""
await mqtt_mock_entry()
# Add device settings to config
config = copy.deepcopy(config[mqtt.DOMAIN][domain])
config = copy.deepcopy(config[DOMAIN][domain])
config["device"] = copy.deepcopy(DEFAULT_CONFIG_DEVICE_INFO_MAC)
config["unique_id"] = "veryunique"
@@ -1966,7 +1965,7 @@ async def help_test_entity_device_info_remove(
"""Test device registry remove."""
await mqtt_mock_entry()
# Add device settings to config
config = copy.deepcopy(config[mqtt.DOMAIN][domain])
config = copy.deepcopy(config[DOMAIN][domain])
config["device"] = copy.deepcopy(DEFAULT_CONFIG_DEVICE_INFO_ID)
config["unique_id"] = "veryunique"
@@ -1979,14 +1978,14 @@ async def help_test_entity_device_info_remove(
device = dev_registry.async_get_device(identifiers={("mqtt", "helloworld")})
assert device is not None
assert ent_registry.async_get_entity_id(domain, mqtt.DOMAIN, "veryunique")
assert ent_registry.async_get_entity_id(domain, DOMAIN, "veryunique")
async_fire_mqtt_message(hass, f"homeassistant/{domain}/bla/config", "")
await hass.async_block_till_done()
device = dev_registry.async_get_device(identifiers={("mqtt", "helloworld")})
assert device is None
assert not ent_registry.async_get_entity_id(domain, mqtt.DOMAIN, "veryunique")
assert not ent_registry.async_get_entity_id(domain, DOMAIN, "veryunique")
async def help_test_entity_device_info_update(
@@ -2001,7 +2000,7 @@ async def help_test_entity_device_info_update(
"""
await mqtt_mock_entry()
# Add device settings to config
config = copy.deepcopy(config[mqtt.DOMAIN][domain])
config = copy.deepcopy(config[DOMAIN][domain])
config["device"] = copy.deepcopy(DEFAULT_CONFIG_DEVICE_INFO_ID)
config["unique_id"] = "veryunique"
@@ -2039,7 +2038,7 @@ async def help_test_entity_name(
"""
await mqtt_mock_entry()
# Add device settings to config
config = copy.deepcopy(config[mqtt.DOMAIN][domain])
config = copy.deepcopy(config[DOMAIN][domain])
config["device"] = copy.deepcopy(DEFAULT_CONFIG_DEVICE_INFO_ID)
config["unique_id"] = "veryunique"
expected_entity_name = "test"
@@ -2074,12 +2073,12 @@ async def help_test_entity_id_update_subscriptions(
"""Test MQTT subscriptions are managed when entity_id is updated."""
# Add unique_id to config
config = copy.deepcopy(config)
config[mqtt.DOMAIN][domain]["unique_id"] = "TOTALLY_UNIQUE"
config[DOMAIN][domain]["unique_id"] = "TOTALLY_UNIQUE"
if topics is None:
# Add default topics to config
config[mqtt.DOMAIN][domain]["availability_topic"] = "avty-topic"
config[mqtt.DOMAIN][domain]["state_topic"] = "test-topic"
config[DOMAIN][domain]["availability_topic"] = "avty-topic"
config[DOMAIN][domain]["state_topic"] = "test-topic"
topics = ["avty-topic", "test-topic"]
assert len(topics) > 0
entity_registry = er.async_get(hass)
@@ -2130,15 +2129,15 @@ async def help_test_entity_id_update_discovery_update(
# Add unique_id to config
await mqtt_mock_entry()
config = copy.deepcopy(config)
config[mqtt.DOMAIN][domain]["unique_id"] = "TOTALLY_UNIQUE"
config[DOMAIN][domain]["unique_id"] = "TOTALLY_UNIQUE"
if topic is None:
# Add default topic to config
config[mqtt.DOMAIN][domain]["availability_topic"] = "avty-topic"
config[DOMAIN][domain]["availability_topic"] = "avty-topic"
topic = "avty-topic"
entity_registry = er.async_get(hass)
data = json.dumps(config[mqtt.DOMAIN][domain])
data = json.dumps(config[DOMAIN][domain])
async_fire_mqtt_message(hass, f"homeassistant/{domain}/bla/config", data)
await hass.async_block_till_done()
@@ -2155,8 +2154,8 @@ async def help_test_entity_id_update_discovery_update(
)
await hass.async_block_till_done()
config[mqtt.DOMAIN][domain]["availability_topic"] = f"{topic}_2"
data = json.dumps(config[mqtt.DOMAIN][domain])
config[DOMAIN][domain]["availability_topic"] = f"{topic}_2"
data = json.dumps(config[DOMAIN][domain])
async_fire_mqtt_message(hass, f"homeassistant/{domain}/bla/config", data)
await hass.async_block_till_done()
assert len(hass.states.async_entity_ids(domain)) == 1
@@ -2178,7 +2177,7 @@ async def help_test_entity_debug_info(
"""
await mqtt_mock_entry()
# Add device settings to config
config = copy.deepcopy(config[mqtt.DOMAIN][domain])
config = copy.deepcopy(config[DOMAIN][domain])
config["device"] = copy.deepcopy(DEFAULT_CONFIG_DEVICE_INFO_ID)
config["unique_id"] = "veryunique"
config["platform"] = "mqtt"
@@ -2219,7 +2218,7 @@ async def help_test_entity_debug_info_max_messages(
"""
await mqtt_mock_entry()
# Add device settings to config
config = copy.deepcopy(config[mqtt.DOMAIN][domain])
config = copy.deepcopy(config[DOMAIN][domain])
config["device"] = copy.deepcopy(DEFAULT_CONFIG_DEVICE_INFO_ID)
config["unique_id"] = "veryunique"
@@ -2282,7 +2281,7 @@ async def help_test_entity_debug_info_message(
"""
# Add device settings to config
await mqtt_mock_entry()
config = copy.deepcopy(config[mqtt.DOMAIN][domain])
config = copy.deepcopy(config[DOMAIN][domain])
config["device"] = copy.deepcopy(DEFAULT_CONFIG_DEVICE_INFO_ID)
config["unique_id"] = "veryunique"
@@ -2385,7 +2384,7 @@ async def help_test_entity_debug_info_remove(
"""
await mqtt_mock_entry()
# Add device settings to config
config = copy.deepcopy(config[mqtt.DOMAIN][domain])
config = copy.deepcopy(config[DOMAIN][domain])
config["device"] = copy.deepcopy(DEFAULT_CONFIG_DEVICE_INFO_ID)
config["unique_id"] = "veryunique"
config["platform"] = "mqtt"
@@ -2438,7 +2437,7 @@ async def help_test_entity_debug_info_update_entity_id(
"""
await mqtt_mock_entry()
# Add device settings to config
config = copy.deepcopy(config[mqtt.DOMAIN][domain])
config = copy.deepcopy(config[DOMAIN][domain])
config["device"] = copy.deepcopy(DEFAULT_CONFIG_DEVICE_INFO_ID)
config["unique_id"] = "veryunique"
config["platform"] = "mqtt"
@@ -2502,7 +2501,7 @@ async def help_test_entity_disabled_by_default(
"""Test device registry remove."""
await mqtt_mock_entry()
# Add device settings to config
config = copy.deepcopy(config[mqtt.DOMAIN][domain])
config = copy.deepcopy(config[DOMAIN][domain])
config["device"] = copy.deepcopy(DEFAULT_CONFIG_DEVICE_INFO_ID)
config["enabled_by_default"] = False
config["unique_id"] = "veryunique1"
@@ -2514,7 +2513,7 @@ async def help_test_entity_disabled_by_default(
data = json.dumps(config)
async_fire_mqtt_message(hass, f"homeassistant/{domain}/bla1/config", data)
await hass.async_block_till_done()
entity_id = ent_registry.async_get_entity_id(domain, mqtt.DOMAIN, "veryunique1")
entity_id = ent_registry.async_get_entity_id(domain, DOMAIN, "veryunique1")
assert entity_id is not None and hass.states.get(entity_id) is None
assert dev_registry.async_get_device(identifiers={("mqtt", "helloworld")})
@@ -2524,14 +2523,14 @@ async def help_test_entity_disabled_by_default(
data = json.dumps(config)
async_fire_mqtt_message(hass, f"homeassistant/{domain}/bla2/config", data)
await hass.async_block_till_done()
entity_id = ent_registry.async_get_entity_id(domain, mqtt.DOMAIN, "veryunique2")
entity_id = ent_registry.async_get_entity_id(domain, DOMAIN, "veryunique2")
assert entity_id is not None and hass.states.get(entity_id) is not None
# Remove the enabled entity, both entities and the device should be removed
async_fire_mqtt_message(hass, f"homeassistant/{domain}/bla2/config", "")
await hass.async_block_till_done()
assert not ent_registry.async_get_entity_id(domain, mqtt.DOMAIN, "veryunique1")
assert not ent_registry.async_get_entity_id(domain, mqtt.DOMAIN, "veryunique2")
assert not ent_registry.async_get_entity_id(domain, DOMAIN, "veryunique1")
assert not ent_registry.async_get_entity_id(domain, DOMAIN, "veryunique2")
assert not dev_registry.async_get_device(identifiers={("mqtt", "helloworld")})
@@ -2544,7 +2543,7 @@ async def help_test_entity_category(
"""Test device registry remove."""
await mqtt_mock_entry()
# Add device settings to config
config = copy.deepcopy(config[mqtt.DOMAIN][domain])
config = copy.deepcopy(config[DOMAIN][domain])
config["device"] = copy.deepcopy(DEFAULT_CONFIG_DEVICE_INFO_ID)
ent_registry = er.async_get(hass)
@@ -2555,7 +2554,7 @@ async def help_test_entity_category(
data = json.dumps(config)
async_fire_mqtt_message(hass, f"homeassistant/{domain}/{unique_id}/config", data)
await hass.async_block_till_done()
entity_id = ent_registry.async_get_entity_id(domain, mqtt.DOMAIN, unique_id)
entity_id = ent_registry.async_get_entity_id(domain, DOMAIN, unique_id)
assert entity_id is not None and hass.states.get(entity_id)
entry = ent_registry.async_get(entity_id)
assert entry is not None and entry.entity_category is None
@@ -2567,7 +2566,7 @@ async def help_test_entity_category(
data = json.dumps(config)
async_fire_mqtt_message(hass, f"homeassistant/{domain}/{unique_id}/config", data)
await hass.async_block_till_done()
entity_id = ent_registry.async_get_entity_id(domain, mqtt.DOMAIN, unique_id)
entity_id = ent_registry.async_get_entity_id(domain, DOMAIN, unique_id)
assert entity_id is not None and hass.states.get(entity_id)
entry = ent_registry.async_get(entity_id)
assert entry is not None and entry.entity_category == EntityCategory.DIAGNOSTIC
@@ -2579,7 +2578,7 @@ async def help_test_entity_category(
data = json.dumps(config)
async_fire_mqtt_message(hass, f"homeassistant/{domain}/{unique_id}/config", data)
await hass.async_block_till_done()
assert not ent_registry.async_get_entity_id(domain, mqtt.DOMAIN, unique_id)
assert not ent_registry.async_get_entity_id(domain, DOMAIN, unique_id)
async def help_test_entity_icon_and_entity_picture(
@@ -2591,7 +2590,7 @@ async def help_test_entity_icon_and_entity_picture(
"""Test entity picture and icon."""
await mqtt_mock_entry()
# Add device settings to config
config = copy.deepcopy(config[mqtt.DOMAIN][domain])
config = copy.deepcopy(config[DOMAIN][domain])
config["device"] = copy.deepcopy(DEFAULT_CONFIG_DEVICE_INFO_ID)
ent_registry = er.async_get(hass)
@@ -2602,7 +2601,7 @@ async def help_test_entity_icon_and_entity_picture(
data = json.dumps(config)
async_fire_mqtt_message(hass, f"homeassistant/{domain}/{unique_id}/config", data)
await hass.async_block_till_done()
entity_id = ent_registry.async_get_entity_id(domain, mqtt.DOMAIN, unique_id)
entity_id = ent_registry.async_get_entity_id(domain, DOMAIN, unique_id)
state = hass.states.get(entity_id)
assert entity_id is not None and state
assert state.attributes.get("icon") is None
@@ -2615,7 +2614,7 @@ async def help_test_entity_icon_and_entity_picture(
data = json.dumps(config)
async_fire_mqtt_message(hass, f"homeassistant/{domain}/{unique_id}/config", data)
await hass.async_block_till_done()
entity_id = ent_registry.async_get_entity_id(domain, mqtt.DOMAIN, unique_id)
entity_id = ent_registry.async_get_entity_id(domain, DOMAIN, unique_id)
state = hass.states.get(entity_id)
assert entity_id is not None and state
assert state.attributes.get("icon") is None
@@ -2629,7 +2628,7 @@ async def help_test_entity_icon_and_entity_picture(
data = json.dumps(config)
async_fire_mqtt_message(hass, f"homeassistant/{domain}/{unique_id}/config", data)
await hass.async_block_till_done()
entity_id = ent_registry.async_get_entity_id(domain, mqtt.DOMAIN, unique_id)
entity_id = ent_registry.async_get_entity_id(domain, DOMAIN, unique_id)
state = hass.states.get(entity_id)
assert entity_id is not None and state
assert state.attributes.get("icon") == "mdi:emoji-happy-outline"
@@ -2662,7 +2661,7 @@ async def help_test_publishing_with_custom_encoding(
setup_config = []
service_data = {}
for test_id, test_data in test_config.items():
test_config_setup: dict[str, Any] = copy.copy(config[mqtt.DOMAIN][domain])
test_config_setup: dict[str, Any] = copy.copy(config[DOMAIN][domain])
test_config_setup.update(
{
topic: f"cmd/{test_id}",
@@ -2802,7 +2801,7 @@ async def help_test_reloadable(
) -> None:
"""Test reloading an MQTT platform."""
# Set up with empty config
config = copy.deepcopy(config[mqtt.DOMAIN][domain])
config = copy.deepcopy(config[DOMAIN][domain])
# 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"
@@ -2810,11 +2809,11 @@ async def help_test_reloadable(
old_config_2["name"] = "test_old_2"
old_config = {
mqtt.DOMAIN: {domain: [old_config_1, old_config_2]},
DOMAIN: {domain: [old_config_1, old_config_2]},
}
# Start the MQTT entry with the old config
entry = MockConfigEntry(
domain=mqtt.DOMAIN,
domain=DOMAIN,
data={mqtt.CONF_BROKER: "test-broker"},
version=mqtt.CONFIG_ENTRY_VERSION,
minor_version=mqtt.CONFIG_ENTRY_MINOR_VERSION,
@@ -2838,7 +2837,7 @@ async def help_test_reloadable(
new_config_extra["name"] = "test_new_3"
new_config = {
mqtt.DOMAIN: {domain: [new_config_1, new_config_2, new_config_extra]},
DOMAIN: {domain: [new_config_1, new_config_2, new_config_extra]},
}
with patch("homeassistant.config.load_yaml_config_file", return_value=new_config):
# Reload the mqtt entry with the new config
@@ -2859,7 +2858,7 @@ async def help_test_reloadable(
async def help_test_unload_config_entry(hass: HomeAssistant) -> None:
"""Test unloading the MQTT config entry."""
mqtt_config_entry = hass.config_entries.async_entries(mqtt.DOMAIN)[0]
mqtt_config_entry = hass.config_entries.async_entries(DOMAIN)[0]
assert mqtt_config_entry.state is ConfigEntryState.LOADED
assert await hass.config_entries.async_unload(mqtt_config_entry.entry_id)
@@ -2878,14 +2877,14 @@ async def help_test_unload_config_entry_with_platform(
"""Test unloading the MQTT config entry with a specific platform domain."""
# prepare setup through configuration.yaml
config_setup: dict[str, dict[str, Any]] = copy.deepcopy(config)
config_setup[mqtt.DOMAIN][domain]["name"] = "config_setup"
config_setup[DOMAIN][domain]["name"] = "config_setup"
config_name = config_setup
with patch("homeassistant.config.load_yaml_config_file", return_value=config_name):
await mqtt_mock_entry()
# prepare setup through discovery
discovery_setup = copy.deepcopy(config[mqtt.DOMAIN][domain])
discovery_setup = copy.deepcopy(config[DOMAIN][domain])
discovery_setup["name"] = "discovery_setup"
async_fire_mqtt_message(
hass, f"homeassistant/{domain}/bla/config", json.dumps(discovery_setup)
+3 -2
View File
@@ -10,6 +10,7 @@ from unittest.mock import AsyncMock, MagicMock, patch
import pytest
from homeassistant.components import mqtt
from homeassistant.components.mqtt import DOMAIN
from homeassistant.components.mqtt.models import MessageCallbackType, ReceiveMessage
from homeassistant.components.mqtt.util import EnsureJobAfterCooldown
from homeassistant.const import EVENT_HOMEASSISTANT_STARTED
@@ -115,14 +116,14 @@ async def setup_with_birth_msg_client_mock(
patch("homeassistant.components.mqtt.client.SUBSCRIBE_COOLDOWN", 0.0),
):
entry = MockConfigEntry(
domain=mqtt.DOMAIN,
domain=DOMAIN,
data=mqtt_config_entry_data or {mqtt.CONF_BROKER: "test-broker"},
options=mqtt_config_entry_options or {},
version=mqtt.CONFIG_ENTRY_VERSION,
minor_version=mqtt.CONFIG_ENTRY_MINOR_VERSION,
)
entry.add_to_hass(hass)
hass.config.components.add(mqtt.DOMAIN)
hass.config.components.add(DOMAIN)
assert await hass.config_entries.async_setup(entry.entry_id)
hass.bus.async_fire(EVENT_HOMEASSISTANT_STARTED)
@@ -8,7 +8,7 @@ from unittest.mock import patch
import pytest
from homeassistant.components import alarm_control_panel, mqtt
from homeassistant.components import alarm_control_panel
from homeassistant.components.alarm_control_panel import (
AlarmControlPanelEntityFeature,
AlarmControlPanelState,
@@ -16,6 +16,7 @@ from homeassistant.components.alarm_control_panel import (
from homeassistant.components.mqtt.alarm_control_panel import (
MQTT_ALARM_ATTRIBUTES_BLOCKED,
)
from homeassistant.components.mqtt.const import DOMAIN
from homeassistant.components.mqtt.models import PublishPayloadType
from homeassistant.const import (
ATTR_CODE,
@@ -83,7 +84,7 @@ DEFAULT_FEATURES = (
)
DEFAULT_CONFIG = {
mqtt.DOMAIN: {
DOMAIN: {
alarm_control_panel.DOMAIN: {
"name": "test",
"state_topic": "alarm/state",
@@ -93,7 +94,7 @@ DEFAULT_CONFIG = {
}
DEFAULT_CONFIG_CODE_NOT_REQUIRED = {
mqtt.DOMAIN: {
DOMAIN: {
alarm_control_panel.DOMAIN: {
"name": "test",
"state_topic": "alarm/state",
@@ -104,7 +105,7 @@ DEFAULT_CONFIG_CODE_NOT_REQUIRED = {
}
DEFAULT_CONFIG_CODE = {
mqtt.DOMAIN: {
DOMAIN: {
alarm_control_panel.DOMAIN: {
"name": "test",
"state_topic": "alarm/state",
@@ -116,7 +117,7 @@ DEFAULT_CONFIG_CODE = {
}
DEFAULT_CONFIG_REMOTE_CODE = {
mqtt.DOMAIN: {
DOMAIN: {
alarm_control_panel.DOMAIN: {
"name": "test",
"state_topic": "alarm/state",
@@ -128,7 +129,7 @@ DEFAULT_CONFIG_REMOTE_CODE = {
}
DEFAULT_CONFIG_REMOTE_CODE_TEXT = {
mqtt.DOMAIN: {
DOMAIN: {
alarm_control_panel.DOMAIN: {
"name": "test",
"state_topic": "alarm/state",
@@ -151,7 +152,7 @@ def does_not_raise():
[
(
{
mqtt.DOMAIN: {
DOMAIN: {
alarm_control_panel.DOMAIN: {
"name": "test",
"command_topic": "alarm/command",
@@ -162,7 +163,7 @@ def does_not_raise():
),
(
{
mqtt.DOMAIN: {
DOMAIN: {
alarm_control_panel.DOMAIN: {
"name": "test",
"state_topic": "alarm/state",
@@ -173,7 +174,7 @@ def does_not_raise():
),
(
{
mqtt.DOMAIN: {
DOMAIN: {
alarm_control_panel.DOMAIN: {
"name": "test",
"command_topic": "alarm/command",
@@ -753,7 +754,7 @@ async def test_disarm_publishes_mqtt_with_template(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
alarm_control_panel.DOMAIN: {
"name": "test",
"command_topic": "test-topic",
@@ -953,7 +954,7 @@ async def test_discovery_update_attr(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
alarm_control_panel.DOMAIN: [
{
"name": "Test 1",
@@ -983,7 +984,7 @@ async def test_discovery_removal_alarm(
hass: HomeAssistant, mqtt_mock_entry: MqttMockHAClientGenerator
) -> None:
"""Test removal of discovered alarm_control_panel."""
data = json.dumps(DEFAULT_CONFIG[mqtt.DOMAIN][alarm_control_panel.DOMAIN])
data = json.dumps(DEFAULT_CONFIG[DOMAIN][alarm_control_panel.DOMAIN])
await help_test_discovery_removal(
hass, mqtt_mock_entry, alarm_control_panel.DOMAIN, data
)
@@ -993,8 +994,8 @@ async def test_discovery_update_alarm_topic_and_template(
hass: HomeAssistant, mqtt_mock_entry: MqttMockHAClientGenerator
) -> None:
"""Test update of discovered alarm_control_panel."""
config1 = copy.deepcopy(DEFAULT_CONFIG[mqtt.DOMAIN][alarm_control_panel.DOMAIN])
config2 = copy.deepcopy(DEFAULT_CONFIG[mqtt.DOMAIN][alarm_control_panel.DOMAIN])
config1 = copy.deepcopy(DEFAULT_CONFIG[DOMAIN][alarm_control_panel.DOMAIN])
config2 = copy.deepcopy(DEFAULT_CONFIG[DOMAIN][alarm_control_panel.DOMAIN])
config1["name"] = "Beer"
config2["name"] = "Milk"
config1["state_topic"] = "alarm/state1"
@@ -1027,8 +1028,8 @@ async def test_discovery_update_alarm_template(
hass: HomeAssistant, mqtt_mock_entry: MqttMockHAClientGenerator
) -> None:
"""Test update of discovered alarm_control_panel."""
config1 = copy.deepcopy(DEFAULT_CONFIG[mqtt.DOMAIN][alarm_control_panel.DOMAIN])
config2 = copy.deepcopy(DEFAULT_CONFIG[mqtt.DOMAIN][alarm_control_panel.DOMAIN])
config1 = copy.deepcopy(DEFAULT_CONFIG[DOMAIN][alarm_control_panel.DOMAIN])
config2 = copy.deepcopy(DEFAULT_CONFIG[DOMAIN][alarm_control_panel.DOMAIN])
config1["name"] = "Beer"
config2["name"] = "Milk"
config1["state_topic"] = "alarm/state1"
@@ -1059,7 +1060,7 @@ async def test_discovery_update_unchanged_alarm(
hass: HomeAssistant, mqtt_mock_entry: MqttMockHAClientGenerator
) -> None:
"""Test update of discovered alarm_control_panel."""
config1 = copy.deepcopy(DEFAULT_CONFIG[mqtt.DOMAIN][alarm_control_panel.DOMAIN])
config1 = copy.deepcopy(DEFAULT_CONFIG[DOMAIN][alarm_control_panel.DOMAIN])
config1["name"] = "Beer"
data1 = json.dumps(config1)
@@ -1109,7 +1110,7 @@ async def test_encoding_subscribable_topics(
hass,
mqtt_mock_entry,
alarm_control_panel.DOMAIN,
DEFAULT_CONFIG[mqtt.DOMAIN][alarm_control_panel.DOMAIN],
DEFAULT_CONFIG[DOMAIN][alarm_control_panel.DOMAIN],
topic,
value,
)
+27 -28
View File
@@ -11,7 +11,8 @@ from freezegun import freeze_time
from freezegun.api import FrozenDateTimeFactory
import pytest
from homeassistant.components import binary_sensor, mqtt
from homeassistant.components import binary_sensor
from homeassistant.components.mqtt.const import DOMAIN
from homeassistant.const import (
EVENT_STATE_CHANGED,
STATE_OFF,
@@ -63,7 +64,7 @@ from tests.common import (
from tests.typing import MqttMockHAClientGenerator, MqttMockPahoClient
DEFAULT_CONFIG = {
mqtt.DOMAIN: {
DOMAIN: {
binary_sensor.DOMAIN: {
"name": "test",
"state_topic": "test-topic",
@@ -76,7 +77,7 @@ DEFAULT_CONFIG = {
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
binary_sensor.DOMAIN: {
"name": "test",
"state_topic": "test-topic",
@@ -111,7 +112,7 @@ async def test_setting_sensor_value_expires_availability_topic(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
binary_sensor.DOMAIN: {
"name": "test",
"state_topic": "test-topic",
@@ -288,7 +289,7 @@ async def test_expiration_on_discovery_and_discovery_update_of_binary_sensor(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
binary_sensor.DOMAIN: {
"name": "test",
"state_topic": "test-topic",
@@ -326,7 +327,7 @@ async def test_setting_sensor_value_via_mqtt_message(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
binary_sensor.DOMAIN: {
"name": "test",
"state_topic": "test-topic",
@@ -370,7 +371,7 @@ async def test_invalid_sensor_value_via_mqtt_message(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
binary_sensor.DOMAIN: {
"name": "test",
"state_topic": "test-topic",
@@ -405,7 +406,7 @@ async def test_setting_sensor_value_via_mqtt_message_and_template(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
binary_sensor.DOMAIN: {
"name": "test",
"state_topic": "test-topic",
@@ -446,7 +447,7 @@ async def test_setting_sensor_value_via_mqtt_message_and_template2(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
binary_sensor.DOMAIN: {
"name": "test",
"encoding": "",
@@ -485,7 +486,7 @@ async def test_setting_sensor_value_via_mqtt_msg_and_template_and_raw_state_enco
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
binary_sensor.DOMAIN: {
"name": "test",
"state_topic": "test-topic",
@@ -520,7 +521,7 @@ async def test_setting_sensor_value_via_mqtt_message_empty_template(
[
(
{
mqtt.DOMAIN: {
DOMAIN: {
binary_sensor.DOMAIN: {
"name": "test",
"device_class": "motion",
@@ -532,7 +533,7 @@ async def test_setting_sensor_value_via_mqtt_message_empty_template(
),
(
{
mqtt.DOMAIN: {
DOMAIN: {
binary_sensor.DOMAIN: {
"name": "test",
"device_class": None,
@@ -560,7 +561,7 @@ async def test_valid_device_class(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
binary_sensor.DOMAIN: {
"name": "test",
"device_class": "abc123",
@@ -622,7 +623,7 @@ async def test_custom_availability_payload(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
binary_sensor.DOMAIN: {
"name": "test",
"state_topic": "test-topic",
@@ -661,7 +662,7 @@ async def test_force_update_disabled(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
binary_sensor.DOMAIN: {
"name": "test",
"state_topic": "test-topic",
@@ -701,7 +702,7 @@ async def test_force_update_enabled(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
binary_sensor.DOMAIN: {
"name": "test",
"state_topic": "test-topic",
@@ -801,7 +802,7 @@ async def test_discovery_update_attr(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
binary_sensor.DOMAIN: [
{
"name": "Test 1",
@@ -829,7 +830,7 @@ async def test_discovery_removal_binary_sensor(
hass: HomeAssistant, mqtt_mock_entry: MqttMockHAClientGenerator
) -> None:
"""Test removal of discovered binary_sensor."""
data = json.dumps(DEFAULT_CONFIG[mqtt.DOMAIN][binary_sensor.DOMAIN])
data = json.dumps(DEFAULT_CONFIG[DOMAIN][binary_sensor.DOMAIN])
await help_test_discovery_removal(hass, mqtt_mock_entry, binary_sensor.DOMAIN, data)
@@ -837,8 +838,8 @@ async def test_discovery_update_binary_sensor_topic_template(
hass: HomeAssistant, mqtt_mock_entry: MqttMockHAClientGenerator
) -> None:
"""Test update of discovered binary_sensor."""
config1 = copy.deepcopy(DEFAULT_CONFIG[mqtt.DOMAIN][binary_sensor.DOMAIN])
config2 = copy.deepcopy(DEFAULT_CONFIG[mqtt.DOMAIN][binary_sensor.DOMAIN])
config1 = copy.deepcopy(DEFAULT_CONFIG[DOMAIN][binary_sensor.DOMAIN])
config2 = copy.deepcopy(DEFAULT_CONFIG[DOMAIN][binary_sensor.DOMAIN])
config1["name"] = "Beer"
config2["name"] = "Milk"
config1["state_topic"] = "sensor/state1"
@@ -873,8 +874,8 @@ async def test_discovery_update_binary_sensor_template(
hass: HomeAssistant, mqtt_mock_entry: MqttMockHAClientGenerator
) -> None:
"""Test update of discovered binary_sensor."""
config1 = copy.deepcopy(DEFAULT_CONFIG[mqtt.DOMAIN][binary_sensor.DOMAIN])
config2 = copy.deepcopy(DEFAULT_CONFIG[mqtt.DOMAIN][binary_sensor.DOMAIN])
config1 = copy.deepcopy(DEFAULT_CONFIG[DOMAIN][binary_sensor.DOMAIN])
config2 = copy.deepcopy(DEFAULT_CONFIG[DOMAIN][binary_sensor.DOMAIN])
config1["name"] = "Beer"
config2["name"] = "Milk"
config1["state_topic"] = "sensor/state1"
@@ -929,7 +930,7 @@ async def test_encoding_subscribable_topics(
hass,
mqtt_mock_entry,
binary_sensor.DOMAIN,
DEFAULT_CONFIG[mqtt.DOMAIN][binary_sensor.DOMAIN],
DEFAULT_CONFIG[DOMAIN][binary_sensor.DOMAIN],
topic,
value,
attribute,
@@ -941,7 +942,7 @@ async def test_discovery_update_unchanged_binary_sensor(
hass: HomeAssistant, mqtt_mock_entry: MqttMockHAClientGenerator
) -> None:
"""Test update of discovered binary_sensor."""
config1 = copy.deepcopy(DEFAULT_CONFIG[mqtt.DOMAIN][binary_sensor.DOMAIN])
config1 = copy.deepcopy(DEFAULT_CONFIG[DOMAIN][binary_sensor.DOMAIN])
config1["name"] = "Beer"
data1 = json.dumps(config1)
@@ -1097,9 +1098,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, {mqtt.DOMAIN: hass_config}
)
await help_test_reload_with_config(hass, caplog, tmp_path, {DOMAIN: hass_config})
state = hass.states.get("binary_sensor.test1")
assert state.state == state1
@@ -1137,7 +1136,7 @@ async def test_skip_restoring_state_with_over_due_expire_trigger(
freezer.move_to("2022-02-02 12:02:00+01:00")
domain = binary_sensor.DOMAIN
config3: ConfigType = copy.deepcopy(DEFAULT_CONFIG[mqtt.DOMAIN][domain])
config3: ConfigType = copy.deepcopy(DEFAULT_CONFIG[DOMAIN][domain])
config3["name"] = "test3"
config3["expire_after"] = 10
config3["state_topic"] = "test-topic3"
+14 -13
View File
@@ -6,7 +6,8 @@ from unittest.mock import patch
import pytest
from homeassistant.components import button, mqtt
from homeassistant.components import button
from homeassistant.components.mqtt.const import DOMAIN
from homeassistant.const import ATTR_ENTITY_ID, ATTR_FRIENDLY_NAME, STATE_UNKNOWN
from homeassistant.core import HomeAssistant
@@ -42,7 +43,7 @@ from .common import (
from tests.typing import MqttMockHAClientGenerator, MqttMockPahoClient
DEFAULT_CONFIG = {
mqtt.DOMAIN: {button.DOMAIN: {"name": "test", "command_topic": "test-topic"}}
DOMAIN: {button.DOMAIN: {"name": "test", "command_topic": "test-topic"}}
}
@@ -51,7 +52,7 @@ DEFAULT_CONFIG = {
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
button.DOMAIN: {
"command_topic": "command-topic",
"name": "test",
@@ -93,7 +94,7 @@ async def test_sending_mqtt_commands(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
button.DOMAIN: {
"command_topic": "command-topic",
"name": "test",
@@ -110,7 +111,7 @@ async def test_sending_mqtt_commands(
}
},
{
mqtt.DOMAIN: {
DOMAIN: {
button.DOMAIN: {
"command_topic": "command-topic",
"name": "test",
@@ -152,7 +153,7 @@ async def test_sending_mqtt_commands_with_message_expiry_interval(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
button.DOMAIN: {
"command_topic": "command-topic",
"command_template": '{ "{{ value }}": "{{ entity_id }}" }',
@@ -215,7 +216,7 @@ async def test_default_availability_payload(
) -> None:
"""Test availability by default payload with defined topic."""
config = {
mqtt.DOMAIN: {
DOMAIN: {
button.DOMAIN: {
"name": "test",
"command_topic": "command-topic",
@@ -233,7 +234,7 @@ async def test_custom_availability_payload(
) -> None:
"""Test availability by custom payload with defined topic."""
config = {
mqtt.DOMAIN: {
DOMAIN: {
button.DOMAIN: {
"name": "test",
"command_topic": "command-topic",
@@ -309,7 +310,7 @@ async def test_discovery_update_attr(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
button.DOMAIN: [
{
"name": "Test 1",
@@ -345,8 +346,8 @@ async def test_discovery_update_button(
hass: HomeAssistant, mqtt_mock_entry: MqttMockHAClientGenerator
) -> None:
"""Test update of discovered button."""
config1 = copy.deepcopy(DEFAULT_CONFIG[mqtt.DOMAIN][button.DOMAIN])
config2 = copy.deepcopy(DEFAULT_CONFIG[mqtt.DOMAIN][button.DOMAIN])
config1 = copy.deepcopy(DEFAULT_CONFIG[DOMAIN][button.DOMAIN])
config2 = copy.deepcopy(DEFAULT_CONFIG[DOMAIN][button.DOMAIN])
config1["name"] = "Beer"
config2["name"] = "Milk"
@@ -446,7 +447,7 @@ async def test_entity_debug_info_message(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
button.DOMAIN: {
"name": "test",
"command_topic": "test-topic",
@@ -470,7 +471,7 @@ async def test_invalid_device_class(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
button.DOMAIN: [
{
"name": "Test 1",
+8 -7
View File
@@ -7,8 +7,9 @@ from unittest.mock import patch
import pytest
from homeassistant.components import camera, mqtt
from homeassistant.components import camera
from homeassistant.components.mqtt.camera import MQTT_CAMERA_ATTRIBUTES_BLOCKED
from homeassistant.components.mqtt.const import DOMAIN
from homeassistant.core import HomeAssistant
from .common import (
@@ -45,12 +46,12 @@ from tests.typing import (
MqttMockPahoClient,
)
DEFAULT_CONFIG = {mqtt.DOMAIN: {camera.DOMAIN: {"name": "test", "topic": "test_topic"}}}
DEFAULT_CONFIG = {DOMAIN: {camera.DOMAIN: {"name": "test", "topic": "test_topic"}}}
@pytest.mark.parametrize(
"hass_config",
[{mqtt.DOMAIN: {camera.DOMAIN: {"topic": "test/camera", "name": "Test Camera"}}}],
[{DOMAIN: {camera.DOMAIN: {"topic": "test/camera", "name": "Test Camera"}}}],
)
async def test_run_camera_setup(
hass: HomeAssistant,
@@ -76,7 +77,7 @@ async def test_run_camera_setup(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
camera.DOMAIN: {
"topic": "test/camera",
"name": "Test Camera",
@@ -110,7 +111,7 @@ async def test_run_camera_b64_encoded(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
"camera": {
"topic": "test/camera",
"name": "Test Camera",
@@ -250,7 +251,7 @@ async def test_discovery_update_attr(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
camera.DOMAIN: [
{
"name": "Test 1",
@@ -278,7 +279,7 @@ async def test_discovery_removal_camera(
hass: HomeAssistant, mqtt_mock_entry: MqttMockHAClientGenerator
) -> None:
"""Test removal of discovered camera."""
data = json.dumps(DEFAULT_CONFIG[mqtt.DOMAIN][camera.DOMAIN])
data = json.dumps(DEFAULT_CONFIG[DOMAIN][camera.DOMAIN])
await help_test_discovery_removal(hass, mqtt_mock_entry, camera.DOMAIN, data)
+21 -21
View File
@@ -15,7 +15,7 @@ import pytest
from homeassistant.components import mqtt
from homeassistant.components.mqtt.client import RECONNECT_INTERVAL_SECONDS
from homeassistant.components.mqtt.const import SUPPORTED_COMPONENTS
from homeassistant.components.mqtt.const import DOMAIN, SUPPORTED_COMPONENTS
from homeassistant.components.mqtt.models import MessageCallbackType, ReceiveMessage
from homeassistant.config_entries import ConfigEntryDisabler, ConfigEntryState
from homeassistant.const import (
@@ -99,7 +99,7 @@ async def test_mqtt_await_ack_at_disconnect(hass: HomeAssistant) -> None:
)
mqtt_client.publish = MagicMock(return_value=FakeInfo())
entry = MockConfigEntry(
domain=mqtt.DOMAIN,
domain=DOMAIN,
data={
"certificate": "auto",
mqtt.CONF_BROKER: "test-broker",
@@ -276,7 +276,7 @@ async def test_message_expiry_interval_fails_for_legacy_protocols(
await mqtt.async_publish(
hass, "test-topic", "test-payload", 2, True, message_expiry_interval=60
)
assert exc.value.translation_domain == mqtt.DOMAIN
assert exc.value.translation_domain == DOMAIN
assert exc.value.translation_key == "mqtt_message_expiry_interval_not_supported"
assert exc.value.translation_placeholders == {
"topic": "test-topic",
@@ -399,7 +399,7 @@ async def test_subscribe_mqtt_config_entry_disabled(
"""Test the subscription of a topic when MQTT config entry is disabled."""
mqtt_mock.connected = True
mqtt_config_entry = hass.config_entries.async_entries(mqtt.DOMAIN)[0]
mqtt_config_entry = hass.config_entries.async_entries(DOMAIN)[0]
mqtt_config_entry_state = mqtt_config_entry.state
assert mqtt_config_entry_state is ConfigEntryState.LOADED
@@ -1340,7 +1340,7 @@ async def test_initial_setup_logs_error(
) -> None:
"""Test for setup failure if initial client connection fails."""
entry = MockConfigEntry(
domain=mqtt.DOMAIN,
domain=DOMAIN,
data={mqtt.CONF_BROKER: "test-broker"},
version=mqtt.CONFIG_ENTRY_VERSION,
minor_version=mqtt.CONFIG_ENTRY_MINOR_VERSION,
@@ -1487,7 +1487,7 @@ async def test_publish_error(
) -> None:
"""Test publish error."""
entry = MockConfigEntry(
domain=mqtt.DOMAIN,
domain=DOMAIN,
data={mqtt.CONF_BROKER: "test-broker"},
version=mqtt.CONFIG_ENTRY_VERSION,
minor_version=mqtt.CONFIG_ENTRY_MINOR_VERSION,
@@ -1681,7 +1681,7 @@ async def test_handle_mqtt_timeout_on_callback(
)
entry = MockConfigEntry(
domain=mqtt.DOMAIN,
domain=DOMAIN,
data={mqtt.CONF_BROKER: "test-broker"},
version=mqtt.CONFIG_ENTRY_VERSION,
minor_version=mqtt.CONFIG_ENTRY_MINOR_VERSION,
@@ -1718,7 +1718,7 @@ async def test_setup_raises_config_entry_not_ready_if_no_connect_broker(
) -> None:
"""Test for setup failure if connection to broker is missing."""
entry = MockConfigEntry(
domain=mqtt.DOMAIN,
domain=DOMAIN,
data={mqtt.CONF_BROKER: "test-broker"},
version=mqtt.CONFIG_ENTRY_VERSION,
minor_version=mqtt.CONFIG_ENTRY_MINOR_VERSION,
@@ -1863,14 +1863,14 @@ async def test_custom_birth_message(
"""Test sending birth message."""
entry = MockConfigEntry(
domain=mqtt.DOMAIN,
domain=DOMAIN,
data=mqtt_config_entry_data,
options=mqtt_config_entry_options,
version=mqtt.CONFIG_ENTRY_VERSION,
minor_version=mqtt.CONFIG_ENTRY_MINOR_VERSION,
)
entry.add_to_hass(hass)
hass.config.components.add(mqtt.DOMAIN)
hass.config.components.add(DOMAIN)
assert await hass.config_entries.async_setup(entry.entry_id)
mock_debouncer.clear()
hass.bus.async_fire(EVENT_HOMEASSISTANT_STARTED)
@@ -1913,14 +1913,14 @@ async def test_no_birth_message(
) -> None:
"""Test disabling birth message."""
entry = MockConfigEntry(
domain=mqtt.DOMAIN,
domain=DOMAIN,
data=mqtt_config_entry_data,
options=mqtt_config_entry_options,
version=mqtt.CONFIG_ENTRY_VERSION,
minor_version=mqtt.CONFIG_ENTRY_MINOR_VERSION,
)
entry.add_to_hass(hass)
hass.config.components.add(mqtt.DOMAIN)
hass.config.components.add(DOMAIN)
mock_debouncer.clear()
assert await hass.config_entries.async_setup(entry.entry_id)
# Wait for discovery cooldown
@@ -1953,14 +1953,14 @@ async def test_delayed_birth_message(
await hass.async_block_till_done()
birth = asyncio.Event()
entry = MockConfigEntry(
domain=mqtt.DOMAIN,
domain=DOMAIN,
data=mqtt_config_entry_data,
options=mqtt_config_entry_options,
version=mqtt.CONFIG_ENTRY_VERSION,
minor_version=mqtt.CONFIG_ENTRY_MINOR_VERSION,
)
entry.add_to_hass(hass)
hass.config.components.add(mqtt.DOMAIN)
hass.config.components.add(DOMAIN)
assert await hass.config_entries.async_setup(entry.entry_id)
@callback
@@ -2033,14 +2033,14 @@ async def test_custom_will_message(
) -> None:
"""Test will message."""
entry = MockConfigEntry(
domain=mqtt.DOMAIN,
domain=DOMAIN,
data=mqtt_config_entry_data,
options=mqtt_config_entry_options,
version=mqtt.CONFIG_ENTRY_VERSION,
minor_version=mqtt.CONFIG_ENTRY_MINOR_VERSION,
)
entry.add_to_hass(hass)
hass.config.components.add(mqtt.DOMAIN)
hass.config.components.add(DOMAIN)
assert await hass.config_entries.async_setup(entry.entry_id)
await hass.async_block_till_done()
@@ -2071,14 +2071,14 @@ async def test_no_will_message(
) -> None:
"""Test will message."""
entry = MockConfigEntry(
domain=mqtt.DOMAIN,
domain=DOMAIN,
data=mqtt_config_entry_data,
options=mqtt_config_entry_options,
version=mqtt.CONFIG_ENTRY_VERSION,
minor_version=mqtt.CONFIG_ENTRY_MINOR_VERSION,
)
entry.add_to_hass(hass)
hass.config.components.add(mqtt.DOMAIN)
hass.config.components.add(DOMAIN)
assert await hass.config_entries.async_setup(entry.entry_id)
await hass.async_block_till_done()
@@ -2619,7 +2619,7 @@ async def test_subscriptions_id_generation(hass: HomeAssistant) -> None:
assert new_id_3 == mqtt.models.MAX_28BIT
with pytest.raises(HomeAssistantError) as exc:
generator.get_or_generate("test4/#")
assert exc.value.translation_domain == mqtt.DOMAIN
assert exc.value.translation_domain == DOMAIN
assert exc.value.translation_key == "mqtt_max_subscription_id_reached"
generator.release("test2/#")
@@ -2629,7 +2629,7 @@ async def test_subscriptions_id_generation(hass: HomeAssistant) -> None:
with pytest.raises(HomeAssistantError) as exc:
generator.get_or_generate("test5/#")
assert exc.value.translation_domain == mqtt.DOMAIN
assert exc.value.translation_domain == DOMAIN
assert exc.value.translation_key == "mqtt_max_subscription_id_reached"
generator.release("test1/#")
@@ -2642,5 +2642,5 @@ async def test_subscriptions_id_generation(hass: HomeAssistant) -> None:
with pytest.raises(HomeAssistantError) as exc:
generator.get_or_generate("test7/#")
assert exc.value.translation_domain == mqtt.DOMAIN
assert exc.value.translation_domain == DOMAIN
assert exc.value.translation_key == "mqtt_max_subscription_id_reached"
+17 -16
View File
@@ -8,7 +8,7 @@ from unittest.mock import call, patch
import pytest
import voluptuous as vol
from homeassistant.components import climate, mqtt
from homeassistant.components import climate
from homeassistant.components.climate import (
ATTR_CURRENT_HUMIDITY,
ATTR_CURRENT_TEMPERATURE,
@@ -34,6 +34,7 @@ from homeassistant.components.mqtt.climate import (
)
from homeassistant.components.mqtt.const import (
DEFAULT_CLIMATE_INITIAL_TEMPERATURE as DEFAULT_INITIAL_TEMPERATURE,
DOMAIN,
)
from homeassistant.const import ATTR_TEMPERATURE, STATE_UNKNOWN
from homeassistant.core import HomeAssistant
@@ -83,7 +84,7 @@ from tests.typing import MqttMockHAClientGenerator, MqttMockPahoClient
ENTITY_CLIMATE = "climate.test"
DEFAULT_CONFIG = {
mqtt.DOMAIN: {
DOMAIN: {
climate.DOMAIN: {
"name": "test",
"mode_command_topic": "mode-topic",
@@ -1421,7 +1422,7 @@ async def test_get_target_temperature_low_high_with_templates(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
climate.DOMAIN: {
"name": "test",
"mode_command_topic": "mode-topic",
@@ -1588,7 +1589,7 @@ async def test_get_with_templates(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
climate.DOMAIN: {
"name": "test",
"mode_command_topic": "mode-topic",
@@ -2021,7 +2022,7 @@ async def test_discovery_update_attr(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
climate.DOMAIN: [
{
"name": "Test 1",
@@ -2074,7 +2075,7 @@ async def test_encoding_subscribable_topics(
attribute_value: Any,
) -> None:
"""Test handling of incoming encoded payload."""
config = copy.deepcopy(DEFAULT_CONFIG[mqtt.DOMAIN][climate.DOMAIN])
config = copy.deepcopy(DEFAULT_CONFIG[DOMAIN][climate.DOMAIN])
await help_test_encoding_subscribable_topics(
hass,
mqtt_mock_entry,
@@ -2091,7 +2092,7 @@ async def test_discovery_removal_climate(
hass: HomeAssistant, mqtt_mock_entry: MqttMockHAClientGenerator
) -> None:
"""Test removal of discovered climate."""
data = json.dumps(DEFAULT_CONFIG[mqtt.DOMAIN][climate.DOMAIN])
data = json.dumps(DEFAULT_CONFIG[DOMAIN][climate.DOMAIN])
await help_test_discovery_removal(hass, mqtt_mock_entry, climate.DOMAIN, data)
@@ -2172,7 +2173,7 @@ async def test_entity_id_update_subscriptions(
) -> None:
"""Test MQTT subscriptions are managed when entity_id is updated."""
config = {
mqtt.DOMAIN: {
DOMAIN: {
climate.DOMAIN: {
"name": "test",
"mode_state_topic": "test-topic",
@@ -2199,7 +2200,7 @@ async def test_entity_debug_info_message(
) -> None:
"""Test MQTT debug info."""
config = {
mqtt.DOMAIN: {
DOMAIN: {
climate.DOMAIN: {
"name": "test",
"mode_command_topic": "command-topic",
@@ -2362,8 +2363,8 @@ async def test_publishing_with_custom_encoding(
domain = climate.DOMAIN
config = copy.deepcopy(DEFAULT_CONFIG)
if topic != "preset_mode_command_topic":
del config[mqtt.DOMAIN][domain]["preset_mode_command_topic"]
del config[mqtt.DOMAIN][domain]["preset_modes"]
del config[DOMAIN][domain]["preset_mode_command_topic"]
del config[DOMAIN][domain]["preset_modes"]
await help_test_publishing_with_custom_encoding(
hass,
@@ -2384,7 +2385,7 @@ async def test_publishing_with_custom_encoding(
[
( # test_valid_humidity_min_max
{
mqtt.DOMAIN: {
DOMAIN: {
climate.DOMAIN: {
"name": "test",
"min_humidity": 20,
@@ -2396,7 +2397,7 @@ async def test_publishing_with_custom_encoding(
),
( # test_invalid_humidity_min_max_1
{
mqtt.DOMAIN: {
DOMAIN: {
climate.DOMAIN: {
"name": "test",
"min_humidity": 0,
@@ -2408,7 +2409,7 @@ async def test_publishing_with_custom_encoding(
),
( # test_invalid_humidity_min_max_2
{
mqtt.DOMAIN: {
DOMAIN: {
climate.DOMAIN: {
"name": "test",
"max_humidity": 20,
@@ -2420,7 +2421,7 @@ async def test_publishing_with_custom_encoding(
),
( # test_valid_humidity_state
{
mqtt.DOMAIN: {
DOMAIN: {
climate.DOMAIN: {
"name": "test",
"target_humidity_state_topic": "humidity-state",
@@ -2432,7 +2433,7 @@ async def test_publishing_with_custom_encoding(
),
( # test_invalid_humidity_state
{
mqtt.DOMAIN: {
DOMAIN: {
climate.DOMAIN: {
"name": "test",
"target_humidity_state_topic": "humidity-state",
+48 -48
View File
@@ -21,7 +21,7 @@ from homeassistant.components.mqtt.config_flow import (
PWD_NOT_CHANGED,
TRANSLATION_DESCRIPTION_PLACEHOLDERS,
)
from homeassistant.components.mqtt.const import CONF_DISCOVERY_QOS
from homeassistant.components.mqtt.const import CONF_DISCOVERY_QOS, DOMAIN
from homeassistant.components.mqtt.util import learn_more_url
from homeassistant.config_entries import ConfigSubentry, ConfigSubentryData
from homeassistant.const import (
@@ -541,7 +541,7 @@ async def test_manual_config_set(
)
# Check config entry got setup
assert len(mock_finish_setup.mock_calls) == 1
config_entry = hass.config_entries.async_entries(mqtt.DOMAIN)[0]
config_entry = hass.config_entries.async_entries(DOMAIN)[0]
assert config_entry.title == "127.0.0.1"
@@ -563,7 +563,7 @@ async def test_user_single_instance(hass: HomeAssistant) -> None:
async def test_hassio_already_configured(hass: HomeAssistant) -> None:
"""Test we only allow a single config flow."""
MockConfigEntry(
domain="mqtt",
domain=DOMAIN,
version=mqtt.CONFIG_ENTRY_VERSION,
minor_version=mqtt.CONFIG_ENTRY_MINOR_VERSION,
).add_to_hass(hass)
@@ -578,14 +578,14 @@ async def test_hassio_already_configured(hass: HomeAssistant) -> None:
async def test_hassio_ignored(hass: HomeAssistant) -> None:
"""Test we supervisor discovered instance can be ignored."""
MockConfigEntry(
domain=mqtt.DOMAIN,
domain=DOMAIN,
source=config_entries.SOURCE_IGNORE,
version=mqtt.CONFIG_ENTRY_VERSION,
minor_version=mqtt.CONFIG_ENTRY_MINOR_VERSION,
).add_to_hass(hass)
result = await hass.config_entries.flow.async_init(
mqtt.DOMAIN,
DOMAIN,
data=HassioServiceInfo(
config={
"addon": "Mosquitto",
@@ -1101,7 +1101,7 @@ async def test_option_flow(
"homeassistant.config.async_hass_config_yaml", AsyncMock(return_value={})
) as yaml_mock:
await mqtt_mock_entry()
config_entry = hass.config_entries.async_entries(mqtt.DOMAIN)[0]
config_entry = hass.config_entries.async_entries(DOMAIN)[0]
result = await hass.config_entries.options.async_init(config_entry.entry_id)
assert result["type"] is FlowResultType.FORM
@@ -1258,7 +1258,7 @@ async def test_bad_certificate(
test_input.pop(mqtt.CONF_CLIENT_KEY)
mqtt_mock = await mqtt_mock_entry()
config_entry: MockConfigEntry = hass.config_entries.async_entries(mqtt.DOMAIN)[0]
config_entry: MockConfigEntry = hass.config_entries.async_entries(DOMAIN)[0]
# Add at least one advanced option to get the full form
hass.config_entries.async_update_entry(
config_entry,
@@ -1335,7 +1335,7 @@ async def test_keepalive_validation(
mqtt_mock = await mqtt_mock_entry()
mock_try_connection.return_value = True
config_entry: MockConfigEntry = hass.config_entries.async_entries(mqtt.DOMAIN)[0]
config_entry: MockConfigEntry = hass.config_entries.async_entries(DOMAIN)[0]
# Add at least one advanced option to get the full form
hass.config_entries.async_update_entry(
config_entry,
@@ -1376,7 +1376,7 @@ async def test_disable_birth_will(
"""Test disabling birth and will."""
await mqtt_mock_entry()
mock_try_connection.return_value = True
config_entry = hass.config_entries.async_entries(mqtt.DOMAIN)[0]
config_entry = hass.config_entries.async_entries(DOMAIN)[0]
hass.config_entries.async_update_entry(
config_entry,
data={
@@ -1441,7 +1441,7 @@ async def test_invalid_discovery_prefix(
"""Test setting an invalid discovery prefix."""
mqtt_mock = await mqtt_mock_entry()
mock_try_connection.return_value = True
config_entry = hass.config_entries.async_entries(mqtt.DOMAIN)[0]
config_entry = hass.config_entries.async_entries(DOMAIN)[0]
hass.config_entries.async_update_entry(
config_entry,
data={
@@ -1506,7 +1506,7 @@ async def test_option_flow_default_suggested_values(
) -> None:
"""Test config flow options has default/suggested values."""
await mqtt_mock_entry()
config_entry = hass.config_entries.async_entries(mqtt.DOMAIN)[0]
config_entry = hass.config_entries.async_entries(DOMAIN)[0]
hass.config_entries.async_update_entry(
config_entry,
data={
@@ -1653,7 +1653,7 @@ async def test_step_reauth(
# Prepare the config entry
config_entry = MockConfigEntry(
domain=mqtt.DOMAIN,
domain=DOMAIN,
data=test_input,
version=mqtt.CONFIG_ENTRY_VERSION,
minor_version=mqtt.CONFIG_ENTRY_MINOR_VERSION,
@@ -1734,7 +1734,7 @@ async def test_step_hassio_reauth(
# Prepare the config entry
config_entry = MockConfigEntry(
domain=mqtt.DOMAIN,
domain=DOMAIN,
data=entry_data,
version=mqtt.CONFIG_ENTRY_VERSION,
minor_version=mqtt.CONFIG_ENTRY_MINOR_VERSION,
@@ -1822,7 +1822,7 @@ async def test_step_hassio_reauth_no_discovery_info(
# Prepare the config entry
config_entry = MockConfigEntry(
domain=mqtt.DOMAIN,
domain=DOMAIN,
data=entry_data,
version=mqtt.CONFIG_ENTRY_VERSION,
minor_version=mqtt.CONFIG_ENTRY_MINOR_VERSION,
@@ -1853,7 +1853,7 @@ async def test_reconfigure_user_connection_fails(
) -> None:
"""Test if connection cannot be made."""
config_entry = MockConfigEntry(
domain=mqtt.DOMAIN,
domain=DOMAIN,
version=mqtt.CONFIG_ENTRY_VERSION,
minor_version=mqtt.CONFIG_ENTRY_MINOR_VERSION,
)
@@ -1891,7 +1891,7 @@ async def test_options_bad_birth_message_fails(
) -> None:
"""Test bad birth message."""
config_entry = MockConfigEntry(
domain=mqtt.DOMAIN,
domain=DOMAIN,
version=mqtt.CONFIG_ENTRY_VERSION,
minor_version=mqtt.CONFIG_ENTRY_MINOR_VERSION,
)
@@ -1929,7 +1929,7 @@ async def test_options_bad_will_message_fails(
) -> None:
"""Test bad will message."""
config_entry = MockConfigEntry(
domain=mqtt.DOMAIN,
domain=DOMAIN,
version=mqtt.CONFIG_ENTRY_VERSION,
minor_version=mqtt.CONFIG_ENTRY_MINOR_VERSION,
)
@@ -1974,7 +1974,7 @@ async def test_try_connection_with_advanced_parameters(
) -> None:
"""Test config flow with advanced parameters from config."""
config_entry = MockConfigEntry(
domain=mqtt.DOMAIN,
domain=DOMAIN,
version=mqtt.CONFIG_ENTRY_VERSION,
minor_version=mqtt.CONFIG_ENTRY_MINOR_VERSION,
)
@@ -2112,7 +2112,7 @@ async def test_setup_with_advanced_settings(
file_id = mock_process_uploaded_file.file_id
config_entry = MockConfigEntry(
domain=mqtt.DOMAIN,
domain=DOMAIN,
version=mqtt.CONFIG_ENTRY_VERSION,
minor_version=mqtt.CONFIG_ENTRY_MINOR_VERSION,
)
@@ -2298,7 +2298,7 @@ async def test_setup_with_certificates(
file_id = mock_process_uploaded_file.file_id
config_entry = MockConfigEntry(
domain=mqtt.DOMAIN,
domain=DOMAIN,
version=mqtt.CONFIG_ENTRY_VERSION,
minor_version=mqtt.CONFIG_ENTRY_MINOR_VERSION,
)
@@ -2419,7 +2419,7 @@ async def test_change_websockets_transport_to_tcp(
) -> None:
"""Test reconfiguration flow changing websockets transport settings."""
config_entry = MockConfigEntry(
domain=mqtt.DOMAIN,
domain=DOMAIN,
version=mqtt.CONFIG_ENTRY_VERSION,
minor_version=mqtt.CONFIG_ENTRY_MINOR_VERSION,
)
@@ -2488,7 +2488,7 @@ async def test_reconfigure_flow_form(
) -> None:
"""Test reconfigure flow."""
await mqtt_mock_entry()
entry: MockConfigEntry = hass.config_entries.async_entries(mqtt.DOMAIN)[0]
entry: MockConfigEntry = hass.config_entries.async_entries(DOMAIN)[0]
result = await entry.start_reconfigure_flow(hass)
assert result["type"] is FlowResultType.FORM
assert result["step_id"] == "broker"
@@ -2542,7 +2542,7 @@ async def test_reconfigure_no_changed_password(
) -> None:
"""Test reconfigure flow."""
await mqtt_mock_entry()
entry: MockConfigEntry = hass.config_entries.async_entries(mqtt.DOMAIN)[0]
entry: MockConfigEntry = hass.config_entries.async_entries(DOMAIN)[0]
result = await entry.start_reconfigure_flow(hass)
assert result["type"] is FlowResultType.FORM
assert result["step_id"] == "broker"
@@ -2603,7 +2603,7 @@ async def test_migrate_config_entry(
expected_minor_version: int,
) -> None:
"""Test migrating a config entry."""
config_entry = hass.config_entries.async_entries(mqtt.DOMAIN)[0]
config_entry = hass.config_entries.async_entries(DOMAIN)[0]
# Mock to a migratable or compatbible config entry version
hass.config_entries.async_update_entry(
config_entry,
@@ -2645,7 +2645,7 @@ async def test_migrate_of_incompatible_config_entry(
options: dict[str, Any],
) -> None:
"""Test migrating a config entry."""
config_entry = hass.config_entries.async_entries(mqtt.DOMAIN)[0]
config_entry = hass.config_entries.async_entries(DOMAIN)[0]
# Mock an incompatible config entry version
hass.config_entries.async_update_entry(
config_entry,
@@ -4109,7 +4109,7 @@ async def test_subentry_configflow(
component = next(iter(config_subentries_data["components"].values()))
await mqtt_mock_entry()
config_entry = hass.config_entries.async_entries(mqtt.DOMAIN)[0]
config_entry = hass.config_entries.async_entries(DOMAIN)[0]
result = await hass.config_entries.subentries.async_init(
(config_entry.entry_id, "device"),
@@ -4266,7 +4266,7 @@ async def test_subentry_reconfigure_remove_entity(
) -> None:
"""Test the subentry ConfigFlow reconfigure removing an entity."""
await mqtt_mock_entry()
config_entry: MockConfigEntry = hass.config_entries.async_entries(mqtt.DOMAIN)[0]
config_entry: MockConfigEntry = hass.config_entries.async_entries(DOMAIN)[0]
subentry_id: str
subentry: ConfigSubentry
subentry_id, subentry = next(iter(config_entry.subentries.items()))
@@ -4275,7 +4275,7 @@ async def test_subentry_reconfigure_remove_entity(
assert result["step_id"] == "summary_menu"
# assert we have a device for the subentry
device = device_registry.async_get_device(identifiers={(mqtt.DOMAIN, subentry_id)})
device = device_registry.async_get_device(identifiers={(DOMAIN, subentry_id)})
assert device is not None
# assert we have an entity for all subentry components
@@ -4294,7 +4294,7 @@ async def test_subentry_reconfigure_remove_entity(
unique_entity_id = f"{subentry_id}_{key}"
entity_id = entity_registry.async_get_entity_id(
domain=component["platform"],
platform=mqtt.DOMAIN,
platform=DOMAIN,
unique_id=unique_entity_id,
)
assert entity_id is not None
@@ -4355,7 +4355,7 @@ async def test_subentry_reconfigure_remove_entity(
unique_entity_id = f"{subentry_id}_{object_list[1]}"
entity_id = entity_registry.async_get_entity_id(
domain=components[object_list[1]]["platform"],
platform=mqtt.DOMAIN,
platform=DOMAIN,
unique_id=unique_entity_id,
)
assert entity_id is None
@@ -4390,7 +4390,7 @@ async def test_subentry_reconfigure_edit_entity_multi_entitites(
) -> None:
"""Test the subentry ConfigFlow reconfigure with multi entities."""
await mqtt_mock_entry()
config_entry: MockConfigEntry = hass.config_entries.async_entries(mqtt.DOMAIN)[0]
config_entry: MockConfigEntry = hass.config_entries.async_entries(DOMAIN)[0]
subentry_id: str
subentry: ConfigSubentry
subentry_id, subentry = next(iter(config_entry.subentries.items()))
@@ -4400,7 +4400,7 @@ async def test_subentry_reconfigure_edit_entity_multi_entitites(
assert result["step_id"] == "summary_menu"
# assert we have a device for the subentry
device = device_registry.async_get_device(identifiers={(mqtt.DOMAIN, subentry_id)})
device = device_registry.async_get_device(identifiers={(DOMAIN, subentry_id)})
assert device is not None
# assert we have an entity for all subentry components
@@ -4418,7 +4418,7 @@ async def test_subentry_reconfigure_edit_entity_multi_entitites(
for key in components:
unique_entity_id = f"{subentry_id}_{key}"
entity_id = entity_registry.async_get_entity_id(
domain="notify", platform=mqtt.DOMAIN, unique_id=unique_entity_id
domain="notify", platform=DOMAIN, unique_id=unique_entity_id
)
assert entity_id is not None
entity_entry = entity_registry.async_get(entity_id)
@@ -4832,7 +4832,7 @@ async def test_subentry_reconfigure_edit_entity_single_entity(
) -> None:
"""Test the subentry ConfigFlow reconfigure with single entity."""
await mqtt_mock_entry()
config_entry: MockConfigEntry = hass.config_entries.async_entries(mqtt.DOMAIN)[0]
config_entry: MockConfigEntry = hass.config_entries.async_entries(DOMAIN)[0]
subentry_id: str
subentry: ConfigSubentry
subentry_id, subentry = next(iter(config_entry.subentries.items()))
@@ -4841,7 +4841,7 @@ async def test_subentry_reconfigure_edit_entity_single_entity(
assert result["step_id"] == "summary_menu"
# assert we have a device for the subentry
device = device_registry.async_get_device(identifiers={(mqtt.DOMAIN, subentry_id)})
device = device_registry.async_get_device(identifiers={(DOMAIN, subentry_id)})
assert device is not None
# assert we have an entity for the subentry component
@@ -4853,7 +4853,7 @@ async def test_subentry_reconfigure_edit_entity_single_entity(
unique_entity_id = f"{subentry_id}_{component_id}"
entity_id = entity_registry.async_get_entity_id(
domain=component["platform"], platform=mqtt.DOMAIN, unique_id=unique_entity_id
domain=component["platform"], platform=DOMAIN, unique_id=unique_entity_id
)
assert entity_id is not None
entity_entry = entity_registry.async_get(entity_id)
@@ -4971,7 +4971,7 @@ async def test_subentry_reconfigure_edit_entity_reset_fields(
) -> None:
"""Test the subentry ConfigFlow reconfigure resets filtered out fields."""
await mqtt_mock_entry()
config_entry: MockConfigEntry = hass.config_entries.async_entries(mqtt.DOMAIN)[0]
config_entry: MockConfigEntry = hass.config_entries.async_entries(DOMAIN)[0]
subentry_id: str
subentry: ConfigSubentry
subentry_id, subentry = next(iter(config_entry.subentries.items()))
@@ -4980,7 +4980,7 @@ async def test_subentry_reconfigure_edit_entity_reset_fields(
assert result["step_id"] == "summary_menu"
# assert we have a device for the subentry
device = device_registry.async_get_device(identifiers={(mqtt.DOMAIN, subentry_id)})
device = device_registry.async_get_device(identifiers={(DOMAIN, subentry_id)})
assert device is not None
# assert we have an entity for the subentry component
@@ -4993,7 +4993,7 @@ async def test_subentry_reconfigure_edit_entity_reset_fields(
unique_entity_id = f"{subentry_id}_{component_id}"
entity_id = entity_registry.async_get_entity_id(
domain=component["platform"], platform=mqtt.DOMAIN, unique_id=unique_entity_id
domain=component["platform"], platform=DOMAIN, unique_id=unique_entity_id
)
assert entity_id is not None
entity_entry = entity_registry.async_get(entity_id)
@@ -5106,7 +5106,7 @@ async def test_subentry_reconfigure_add_entity(
) -> None:
"""Test the subentry ConfigFlow reconfigure and add an entity."""
await mqtt_mock_entry()
config_entry: MockConfigEntry = hass.config_entries.async_entries(mqtt.DOMAIN)[0]
config_entry: MockConfigEntry = hass.config_entries.async_entries(DOMAIN)[0]
subentry_id: str
subentry: ConfigSubentry
subentry_id, subentry = next(iter(config_entry.subentries.items()))
@@ -5115,7 +5115,7 @@ async def test_subentry_reconfigure_add_entity(
assert result["step_id"] == "summary_menu"
# assert we have a device for the subentry
device = device_registry.async_get_device(identifiers={(mqtt.DOMAIN, subentry_id)})
device = device_registry.async_get_device(identifiers={(DOMAIN, subentry_id)})
assert device is not None
# assert we have an entity for the subentry component
@@ -5124,7 +5124,7 @@ async def test_subentry_reconfigure_add_entity(
component_id_1, component1 = next(iter(components.items()))
unique_entity_id = f"{subentry_id}_{component_id_1}"
entity_id = entity_registry.async_get_entity_id(
domain=component1["platform"], platform=mqtt.DOMAIN, unique_id=unique_entity_id
domain=component1["platform"], platform=DOMAIN, unique_id=unique_entity_id
)
assert entity_id is not None
entity_entry = entity_registry.async_get(entity_id)
@@ -5212,7 +5212,7 @@ async def test_subentry_reconfigure_update_device_properties(
) -> None:
"""Test the subentry ConfigFlow reconfigure and update device properties."""
await mqtt_mock_entry()
config_entry: MockConfigEntry = hass.config_entries.async_entries(mqtt.DOMAIN)[0]
config_entry: MockConfigEntry = hass.config_entries.async_entries(DOMAIN)[0]
subentry_id: str
subentry: ConfigSubentry
subentry_id, subentry = next(iter(config_entry.subentries.items()))
@@ -5221,7 +5221,7 @@ async def test_subentry_reconfigure_update_device_properties(
assert result["step_id"] == "summary_menu"
# assert we have a device for the subentry
device = device_registry.async_get_device(identifiers={(mqtt.DOMAIN, subentry_id)})
device = device_registry.async_get_device(identifiers={(DOMAIN, subentry_id)})
assert device is not None
# assert we have an entity for all subentry components
@@ -5367,7 +5367,7 @@ async def test_subentry_reconfigure_availablity(
) -> None:
"""Test the subentry ConfigFlow reconfigure and update device properties."""
await mqtt_mock_entry()
config_entry: MockConfigEntry = hass.config_entries.async_entries(mqtt.DOMAIN)[0]
config_entry: MockConfigEntry = hass.config_entries.async_entries(DOMAIN)[0]
subentry_id: str
subentry: ConfigSubentry
subentry_id, subentry = next(iter(config_entry.subentries.items()))
@@ -5495,7 +5495,7 @@ async def test_subentry_reconfigure_export_settings(
) -> None:
"""Test the subentry ConfigFlow reconfigure export feature."""
await mqtt_mock_entry()
config_entry: MockConfigEntry = hass.config_entries.async_entries(mqtt.DOMAIN)[0]
config_entry: MockConfigEntry = hass.config_entries.async_entries(DOMAIN)[0]
subentry_id: str
subentry: ConfigSubentry
subentry_id, subentry = next(iter(config_entry.subentries.items()))
@@ -5504,7 +5504,7 @@ async def test_subentry_reconfigure_export_settings(
assert result["step_id"] == "summary_menu"
# assert we have a device for the subentry
device = device_registry.async_get_device(identifiers={(mqtt.DOMAIN, subentry_id)})
device = device_registry.async_get_device(identifiers={(DOMAIN, subentry_id)})
assert device is not None
# assert we entity for all subentry components
@@ -5561,7 +5561,7 @@ async def test_subentry_configflow_section_feature(
) -> None:
"""Test subentry sections are hidden with no configurable options."""
await mqtt_mock_entry()
config_entry = hass.config_entries.async_entries(mqtt.DOMAIN)[0]
config_entry = hass.config_entries.async_entries(DOMAIN)[0]
result = await hass.config_entries.subentries.async_init(
(config_entry.entry_id, "device"),
+80 -82
View File
@@ -6,7 +6,7 @@ from unittest.mock import patch
import pytest
from homeassistant.components import cover, mqtt
from homeassistant.components import cover
from homeassistant.components.cover import (
ATTR_CURRENT_POSITION,
ATTR_CURRENT_TILT_POSITION,
@@ -14,7 +14,7 @@ from homeassistant.components.cover import (
ATTR_TILT_POSITION,
CoverState,
)
from homeassistant.components.mqtt.const import CONF_STATE_TOPIC
from homeassistant.components.mqtt.const import CONF_STATE_TOPIC, DOMAIN
from homeassistant.components.mqtt.cover import (
CONF_GET_POSITION_TEMPLATE,
CONF_GET_POSITION_TOPIC,
@@ -81,16 +81,14 @@ from .common import (
from tests.common import async_fire_mqtt_message
from tests.typing import MqttMockHAClientGenerator, MqttMockPahoClient
DEFAULT_CONFIG = {
mqtt.DOMAIN: {cover.DOMAIN: {"name": "test", "state_topic": "test-topic"}}
}
DEFAULT_CONFIG = {DOMAIN: {cover.DOMAIN: {"name": "test", "state_topic": "test-topic"}}}
@pytest.mark.parametrize(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
cover.DOMAIN: {
"name": "test",
"state_topic": "state-topic",
@@ -134,7 +132,7 @@ async def test_state_via_state_topic(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
cover.DOMAIN: {
"name": "test",
"state_topic": "state-topic",
@@ -180,7 +178,7 @@ async def test_opening_and_closing_state_via_custom_state_payload(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
cover.DOMAIN: {
"name": "test",
"position_topic": "position-topic",
@@ -234,7 +232,7 @@ async def test_open_closed_state_from_position_optimistic(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
cover.DOMAIN: {
"name": "test",
"position_topic": "position-topic",
@@ -295,7 +293,7 @@ async def test_open_closed_state_from_position_optimistic_alt_positions(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
cover.DOMAIN: {
"name": "test",
"tilt_command_topic": "set-position-topic",
@@ -356,7 +354,7 @@ async def test_tilt_open_closed_toggle_optimistic(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
cover.DOMAIN: {
"name": "test",
"tilt_command_topic": "set-position-topic",
@@ -421,7 +419,7 @@ async def test_tilt_open_closed_toggle_optimistic_alt_positions(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
cover.DOMAIN: {
"name": "test",
"position_topic": "get-position-topic",
@@ -462,7 +460,7 @@ async def test_position_via_position_topic(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
cover.DOMAIN: {
"name": "test",
"state_topic": "state-topic",
@@ -503,7 +501,7 @@ async def test_state_via_template(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
cover.DOMAIN: {
"name": "test",
"state_topic": "state-topic",
@@ -546,7 +544,7 @@ async def test_state_via_template_and_entity_id(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
cover.DOMAIN: {
"name": "test",
"state_topic": "state-topic",
@@ -592,7 +590,7 @@ async def test_state_via_template_with_json_value(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
cover.DOMAIN: {
"name": "test",
"position_topic": "get-position-topic",
@@ -638,7 +636,7 @@ async def test_position_via_template_and_entity_id(
[
(
{
mqtt.DOMAIN: {
DOMAIN: {
cover.DOMAIN: {"name": "test", "qos": 0, "command_topic": "abc"}
}
},
@@ -646,7 +644,7 @@ async def test_position_via_template_and_entity_id(
),
(
{
mqtt.DOMAIN: {
DOMAIN: {
cover.DOMAIN: {
"name": "test",
"qos": 0,
@@ -660,7 +658,7 @@ async def test_position_via_template_and_entity_id(
# ({"set_position_topic": "abc"}, True), - not a valid configuration
(
{
mqtt.DOMAIN: {
DOMAIN: {
cover.DOMAIN: {
"name": "test",
"qos": 0,
@@ -673,7 +671,7 @@ async def test_position_via_template_and_entity_id(
),
(
{
mqtt.DOMAIN: {
DOMAIN: {
cover.DOMAIN: {
"name": "test",
"qos": 0,
@@ -685,7 +683,7 @@ async def test_position_via_template_and_entity_id(
),
(
{
mqtt.DOMAIN: {
DOMAIN: {
cover.DOMAIN: {
"name": "test",
"qos": 0,
@@ -716,7 +714,7 @@ async def test_optimistic_flag(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
cover.DOMAIN: {
"name": "test",
"command_topic": "command-topic",
@@ -784,7 +782,7 @@ async def test_optimistic_state_change(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
cover.DOMAIN: {
"name": "test",
"optimistic": True,
@@ -859,7 +857,7 @@ async def test_optimistic_state_change_with_position(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
cover.DOMAIN: {
"name": "test",
"state_topic": "state-topic",
@@ -894,7 +892,7 @@ async def test_send_open_cover_command(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
cover.DOMAIN: {
"name": "test",
"state_topic": "state-topic",
@@ -929,7 +927,7 @@ async def test_send_close_cover_command(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
cover.DOMAIN: {
"name": "test",
"state_topic": "state-topic",
@@ -965,7 +963,7 @@ async def test_send_stop_cover_command(
[
(
{
mqtt.DOMAIN: {
DOMAIN: {
cover.DOMAIN: {
"name": "test",
"state_topic": "state-topic",
@@ -979,7 +977,7 @@ async def test_send_stop_cover_command(
),
(
{
mqtt.DOMAIN: {
DOMAIN: {
cover.DOMAIN: {
"name": "test",
"state_topic": "state-topic",
@@ -1021,7 +1019,7 @@ async def test_send_stop_tilt_command(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
cover.DOMAIN: {
"name": "test",
"position_topic": "get-position-topic",
@@ -1076,7 +1074,7 @@ async def test_current_cover_position(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
cover.DOMAIN: {
"name": "test",
"position_topic": "get-position-topic",
@@ -1142,7 +1140,7 @@ async def test_current_cover_position_inverted(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
cover.DOMAIN: {
"name": "test",
"command_topic": "command-topic",
@@ -1167,7 +1165,7 @@ async def test_optimistic_position(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
cover.DOMAIN: {
"name": "test",
"position_topic": "get-position-topic",
@@ -1209,7 +1207,7 @@ async def test_position_update(
[
(
{
mqtt.DOMAIN: {
DOMAIN: {
cover.DOMAIN: {
"name": "test",
"position_topic": "get-position-topic",
@@ -1229,7 +1227,7 @@ async def test_position_update(
),
(
{
mqtt.DOMAIN: {
DOMAIN: {
cover.DOMAIN: {
"name": "test",
"position_topic": "get-position-topic",
@@ -1274,7 +1272,7 @@ async def test_set_position_templated(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
cover.DOMAIN: {
"name": "test",
"position_topic": "get-position-topic",
@@ -1322,7 +1320,7 @@ async def test_set_position_templated_and_attributes(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
cover.DOMAIN: {
"name": "test",
"position_topic": "get-position-topic",
@@ -1363,7 +1361,7 @@ async def test_set_tilt_templated(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
cover.DOMAIN: {
"name": "test",
"position_topic": "get-position-topic",
@@ -1457,7 +1455,7 @@ async def test_set_tilt_templated_and_attributes(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
cover.DOMAIN: {
"name": "test",
"position_topic": "state-topic",
@@ -1493,7 +1491,7 @@ async def test_set_position_untemplated(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
cover.DOMAIN: {
"name": "test",
"position_topic": "state-topic",
@@ -1531,7 +1529,7 @@ async def test_set_position_untemplated_custom_percentage_range(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
cover.DOMAIN: {
"name": "test",
"qos": 0,
@@ -1558,7 +1556,7 @@ async def test_no_command_topic(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
cover.DOMAIN: {
"name": "test",
"command_topic": "command-topic",
@@ -1584,7 +1582,7 @@ async def test_no_payload_close(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
cover.DOMAIN: {
"name": "test",
"command_topic": "command-topic",
@@ -1610,7 +1608,7 @@ async def test_no_payload_open(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
cover.DOMAIN: {
"name": "test",
"command_topic": "command-topic",
@@ -1636,7 +1634,7 @@ async def test_no_payload_stop(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
cover.DOMAIN: {
"command_topic": "test",
"name": "test",
@@ -1664,7 +1662,7 @@ async def test_with_command_topic_and_tilt(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
cover.DOMAIN: {
"name": "test",
"state_topic": "state-topic",
@@ -1695,7 +1693,7 @@ async def test_tilt_defaults(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
cover.DOMAIN: {
"name": "test",
"state_topic": "state-topic",
@@ -1785,7 +1783,7 @@ async def test_tilt_via_invocation_defaults(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
cover.DOMAIN: {
"name": "test",
"state_topic": "state-topic",
@@ -1877,7 +1875,7 @@ async def test_tilt_given_value(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
cover.DOMAIN: {
"name": "test",
"state_topic": "state-topic",
@@ -1957,7 +1955,7 @@ async def test_tilt_given_value_optimistic(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
cover.DOMAIN: {
"name": "test",
"state_topic": "state-topic",
@@ -2039,7 +2037,7 @@ async def test_tilt_given_value_altered_range(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
cover.DOMAIN: {
"name": "test",
"state_topic": "state-topic",
@@ -2080,7 +2078,7 @@ async def test_tilt_via_topic(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
cover.DOMAIN: {
"name": "test",
"state_topic": "state-topic",
@@ -2124,7 +2122,7 @@ async def test_tilt_via_topic_template(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
cover.DOMAIN: {
"name": "test",
"state_topic": "state-topic",
@@ -2177,7 +2175,7 @@ async def test_tilt_via_topic_template_json_value(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
cover.DOMAIN: {
"name": "test",
"state_topic": "state-topic",
@@ -2227,7 +2225,7 @@ async def test_tilt_via_topic_altered_range(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
cover.DOMAIN: {
"name": "test",
"state_topic": "state-topic",
@@ -2264,7 +2262,7 @@ async def test_tilt_status_out_of_range_warning(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
cover.DOMAIN: {
"name": "test",
"state_topic": "state-topic",
@@ -2299,7 +2297,7 @@ async def test_tilt_status_not_numeric_warning(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
cover.DOMAIN: {
"name": "test",
"state_topic": "state-topic",
@@ -2349,7 +2347,7 @@ async def test_tilt_via_topic_altered_range_inverted(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
cover.DOMAIN: {
"name": "test",
"state_topic": "state-topic",
@@ -2402,7 +2400,7 @@ async def test_tilt_via_topic_template_altered_range(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
cover.DOMAIN: {
"name": "test",
"state_topic": "state-topic",
@@ -2440,7 +2438,7 @@ async def test_tilt_position(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
cover.DOMAIN: {
"name": "test",
"state_topic": "state-topic",
@@ -2479,7 +2477,7 @@ async def test_tilt_position_templated(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
cover.DOMAIN: {
"name": "test",
"state_topic": "state-topic",
@@ -2559,7 +2557,7 @@ async def test_custom_availability_payload(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
cover.DOMAIN: {
"name": "test",
"device_class": "garage",
@@ -2583,7 +2581,7 @@ async def test_valid_device_class(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
cover.DOMAIN: {
"name": "test",
"device_class": "abc123",
@@ -2669,7 +2667,7 @@ async def test_discovery_update_attr(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
cover.DOMAIN: [
{
"name": "Test 1",
@@ -2807,7 +2805,7 @@ async def test_entity_debug_info_message(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
cover.DOMAIN: {
"name": "test",
"state_topic": "state-topic",
@@ -2868,7 +2866,7 @@ async def test_state_and_position_topics_state_not_set_via_position_topic(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
cover.DOMAIN: {
"name": "test",
"state_topic": "state-topic",
@@ -2925,7 +2923,7 @@ async def test_set_state_via_position_using_stopped_state(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
cover.DOMAIN: {
"name": "test",
"state_topic": "state-topic",
@@ -2963,7 +2961,7 @@ async def test_position_via_position_topic_template(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
cover.DOMAIN: {
"name": "test",
"state_topic": "state-topic",
@@ -3010,7 +3008,7 @@ async def test_position_via_position_topic_template_json_value(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
cover.DOMAIN: {
"name": "test",
"state_topic": "state-topic",
@@ -3053,7 +3051,7 @@ async def test_position_template_with_entity_id(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
cover.DOMAIN: {
"name": "test",
"state_topic": "state-topic",
@@ -3084,7 +3082,7 @@ async def test_position_via_position_topic_template_return_json(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
cover.DOMAIN: {
"name": "test",
"state_topic": "state-topic",
@@ -3117,7 +3115,7 @@ async def test_position_via_position_topic_template_return_json_warning(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
cover.DOMAIN: {
"name": "test",
"state_topic": "state-topic",
@@ -3165,7 +3163,7 @@ async def test_position_and_tilt_via_position_topic_template_return_json(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
cover.DOMAIN: {
"name": "test",
"state_topic": "state-topic",
@@ -3213,7 +3211,7 @@ async def test_position_via_position_topic_template_all_variables(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
cover.DOMAIN: {
"name": "test",
"state_topic": "state-topic",
@@ -3271,7 +3269,7 @@ async def test_set_state_via_stopped_state_no_position_topic(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
cover.DOMAIN: {
"name": "test",
"state_topic": "state-topic",
@@ -3301,7 +3299,7 @@ async def test_position_via_position_topic_template_return_invalid_json(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
cover.DOMAIN: {
"name": "test",
"command_topic": "command-topic",
@@ -3328,7 +3326,7 @@ async def test_set_position_topic_without_get_position_topic_error(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
cover.DOMAIN: {
"name": "test",
"command_topic": "command-topic",
@@ -3354,7 +3352,7 @@ async def test_value_template_without_state_topic_error(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
cover.DOMAIN: {
"name": "test",
"command_topic": "command-topic",
@@ -3381,7 +3379,7 @@ async def test_position_template_without_position_topic_error(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
cover.DOMAIN: {
"name": "test",
"command_topic": "command-topic",
@@ -3407,7 +3405,7 @@ async def test_set_position_template_without_set_position_topic(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
cover.DOMAIN: {
"name": "test",
"command_topic": "command-topic",
@@ -3433,7 +3431,7 @@ async def test_tilt_command_template_without_tilt_command_topic(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
cover.DOMAIN: {
"name": "test",
"command_topic": "command-topic",
@@ -3494,7 +3492,7 @@ async def test_publishing_with_custom_encoding(
"""Test publishing MQTT payload with different encoding."""
domain = cover.DOMAIN
config = deepcopy(DEFAULT_CONFIG)
config[mqtt.DOMAIN][domain]["position_topic"] = "some-position-topic"
config[DOMAIN][domain]["position_topic"] = "some-position-topic"
await help_test_publishing_with_custom_encoding(
hass,
@@ -3541,7 +3539,7 @@ async def test_encoding_subscribable_topics(
hass,
mqtt_mock_entry,
cover.DOMAIN,
DEFAULT_CONFIG[mqtt.DOMAIN][cover.DOMAIN],
DEFAULT_CONFIG[DOMAIN][cover.DOMAIN],
topic,
value,
attribute,
+10 -9
View File
@@ -6,7 +6,8 @@ from unittest.mock import patch
import pytest
from homeassistant.components import date, mqtt
from homeassistant.components import date
from homeassistant.components.mqtt.const import DOMAIN
from homeassistant.const import ATTR_ASSUMED_STATE, ATTR_ENTITY_ID, STATE_UNKNOWN
from homeassistant.core import HomeAssistant
@@ -44,7 +45,7 @@ from tests.common import async_fire_mqtt_message
from tests.typing import MqttMockHAClientGenerator, MqttMockPahoClient
DEFAULT_CONFIG = {
mqtt.DOMAIN: {date.DOMAIN: {"name": "test", "command_topic": "test-topic"}}
DOMAIN: {date.DOMAIN: {"name": "test", "command_topic": "test-topic"}}
}
@@ -64,7 +65,7 @@ async def async_set_value(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
date.DOMAIN: {
"name": "test",
"state_topic": "state-topic",
@@ -116,7 +117,7 @@ async def test_controlling_state_via_topic(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
date.DOMAIN: {
"name": "test",
"state_topic": "state-topic",
@@ -155,7 +156,7 @@ async def test_controlling_validation_state_via_topic(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
date.DOMAIN: {
"name": "test",
"command_topic": "command-topic",
@@ -219,7 +220,7 @@ async def test_default_availability_payload(
) -> None:
"""Test availability by default payload with defined topic."""
config = {
mqtt.DOMAIN: {
DOMAIN: {
date.DOMAIN: {
"name": "test",
"state_topic": "state-topic",
@@ -237,7 +238,7 @@ async def test_custom_availability_payload(
) -> None:
"""Test availability by custom payload with defined topic."""
config = {
mqtt.DOMAIN: {
DOMAIN: {
date.DOMAIN: {
"name": "test",
"state_topic": "state-topic",
@@ -313,7 +314,7 @@ async def test_discovery_update_attr(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
date.DOMAIN: [
{
"name": "Test 1",
@@ -492,7 +493,7 @@ async def test_encoding_subscribable_topics(
hass,
mqtt_mock_entry,
date.DOMAIN,
DEFAULT_CONFIG[mqtt.DOMAIN][date.DOMAIN],
DEFAULT_CONFIG[DOMAIN][date.DOMAIN],
topic,
value,
attribute,
+13 -12
View File
@@ -8,7 +8,8 @@ from dateutil.tz import UTC
from freezegun import freeze_time
import pytest
from homeassistant.components import datetime, mqtt
from homeassistant.components import datetime
from homeassistant.components.mqtt.const import DOMAIN
from homeassistant.const import ATTR_ASSUMED_STATE, ATTR_ENTITY_ID, STATE_UNKNOWN
from homeassistant.core import HomeAssistant
@@ -46,7 +47,7 @@ from tests.common import async_fire_mqtt_message
from tests.typing import MqttMockHAClientGenerator, MqttMockPahoClient
DEFAULT_CONFIG = {
mqtt.DOMAIN: {datetime.DOMAIN: {"name": "test", "command_topic": "test-topic"}}
DOMAIN: {datetime.DOMAIN: {"name": "test", "command_topic": "test-topic"}}
}
@@ -68,7 +69,7 @@ async def async_set_value(
[
(
{
mqtt.DOMAIN: {
DOMAIN: {
datetime.DOMAIN: {
"name": "test",
"state_topic": "state-topic",
@@ -84,7 +85,7 @@ async def async_set_value(
),
(
{
mqtt.DOMAIN: {
DOMAIN: {
datetime.DOMAIN: {
"name": "test",
"state_topic": "state-topic",
@@ -143,7 +144,7 @@ async def test_controlling_state_via_topic(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
datetime.DOMAIN: {
"name": "test",
"state_topic": "state-topic",
@@ -186,7 +187,7 @@ async def test_controlling_validation_state_via_topic(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
datetime.DOMAIN: {
"name": "test",
"state_topic": "state-topic",
@@ -224,7 +225,7 @@ async def test_ambiguous_date_time_state_update(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
datetime.DOMAIN: {
"name": "test",
"state_topic": "state-topic",
@@ -257,7 +258,7 @@ async def test_date_time_with_invalid_timezone_identifier(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
datetime.DOMAIN: {
"name": "test",
"command_topic": "command-topic",
@@ -324,7 +325,7 @@ async def test_default_availability_payload(
) -> None:
"""Test availability by default payload with defined topic."""
config = {
mqtt.DOMAIN: {
DOMAIN: {
datetime.DOMAIN: {
"name": "test",
"state_topic": "state-topic",
@@ -348,7 +349,7 @@ async def test_custom_availability_payload(
) -> None:
"""Test availability by custom payload with defined topic."""
config = {
mqtt.DOMAIN: {
DOMAIN: {
datetime.DOMAIN: {
"name": "test",
"state_topic": "state-topic",
@@ -430,7 +431,7 @@ async def test_discovery_update_attr(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
datetime.DOMAIN: [
{
"name": "Test 1",
@@ -611,7 +612,7 @@ async def test_encoding_subscribable_topics(
hass,
mqtt_mock_entry,
datetime.DOMAIN,
DEFAULT_CONFIG[mqtt.DOMAIN][datetime.DOMAIN],
DEFAULT_CONFIG[DOMAIN][datetime.DOMAIN],
topic,
value,
attribute,
+3 -3
View File
@@ -5,7 +5,7 @@ from datetime import UTC, datetime
from freezegun.api import FrozenDateTimeFactory
import pytest
from homeassistant.components import device_tracker, mqtt
from homeassistant.components import device_tracker
from homeassistant.components.mqtt.const import DOMAIN
from homeassistant.const import STATE_HOME, STATE_NOT_HOME, STATE_UNKNOWN
from homeassistant.core import HomeAssistant
@@ -27,7 +27,7 @@ from tests.typing import (
)
DEFAULT_CONFIG = {
mqtt.DOMAIN: {
DOMAIN: {
device_tracker.DOMAIN: {
"name": "test",
"state_topic": "test-topic",
@@ -693,7 +693,7 @@ async def test_setting_blocked_attribute_via_mqtt_json_message(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
device_tracker.DOMAIN: {"name": "jan", "state_topic": "/location/jan"}
}
}
+3 -2
View File
@@ -6,6 +6,7 @@ from unittest.mock import ANY
import pytest
from homeassistant.components import mqtt
from homeassistant.components.mqtt.const import DOMAIN
from homeassistant.const import CONF_PASSWORD, CONF_USERNAME
from homeassistant.core import HomeAssistant
from homeassistant.helpers import device_registry as dr, entity_registry as er
@@ -29,7 +30,7 @@ async def test_entry_diagnostics(
) -> None:
"""Test config entry diagnostics."""
mqtt_mock = await mqtt_mock_entry()
config_entry = hass.config_entries.async_entries(mqtt.DOMAIN)[0]
config_entry = hass.config_entries.async_entries(DOMAIN)[0]
mqtt_mock.connected = True
await get_diagnostics_for_config_entry(hass, hass_client, config_entry)
@@ -167,7 +168,7 @@ async def test_redact_diagnostics(
expected_config["data"]["password"] = "**REDACTED**"
expected_config["data"]["username"] = "**REDACTED**"
config_entry = hass.config_entries.async_entries(mqtt.DOMAIN)[0]
config_entry = hass.config_entries.async_entries(DOMAIN)[0]
mqtt_mock.connected = True
# Discover a device with a device tracker
+9 -9
View File
@@ -18,7 +18,7 @@ from homeassistant.components.mqtt.abbreviations import (
ABBREVIATIONS,
DEVICE_ABBREVIATIONS,
)
from homeassistant.components.mqtt.const import SUPPORTED_COMPONENTS
from homeassistant.components.mqtt.const import DOMAIN, SUPPORTED_COMPONENTS
from homeassistant.components.mqtt.discovery import (
MQTT_DISCOVERY_DONE,
MQTT_DISCOVERY_NEW,
@@ -207,7 +207,7 @@ async def test_subscribing_config_topic(
) -> None:
"""Test setting up discovery."""
mqtt_mock = await mqtt_mock_entry()
entry = hass.config_entries.async_entries(mqtt.DOMAIN)[0]
entry = hass.config_entries.async_entries(DOMAIN)[0]
discovery_topic = "homeassistant"
await async_start(hass, discovery_topic, entry)
@@ -1754,7 +1754,7 @@ async def test_cleanup_device_manual(
assert state is not None
# Remove MQTT from the device
mqtt_config_entry = hass.config_entries.async_entries(mqtt.DOMAIN)[0]
mqtt_config_entry = hass.config_entries.async_entries(DOMAIN)[0]
mock_debouncer.clear()
response = await ws_client.remove_device(
device_entry.id, mqtt_config_entry.entry_id
@@ -2018,7 +2018,7 @@ async def test_cleanup_device_multiple_config_entries(
)
assert device_entry is not None
mqtt_config_entry = hass.config_entries.async_entries(mqtt.DOMAIN)[0]
mqtt_config_entry = hass.config_entries.async_entries(DOMAIN)[0]
sensor_config = {
"device": {"connections": [["mac", "12:34:56:AB:CD:EF"]]},
@@ -2063,7 +2063,7 @@ async def test_cleanup_device_multiple_config_entries(
assert state is not None
# Remove MQTT from the device
mqtt_config_entry = hass.config_entries.async_entries(mqtt.DOMAIN)[0]
mqtt_config_entry = hass.config_entries.async_entries(DOMAIN)[0]
response = await ws_client.remove_device(
device_entry.id, mqtt_config_entry.entry_id
)
@@ -2136,7 +2136,7 @@ async def test_cleanup_device_multiple_config_entries_mqtt(
connections={("mac", "12:34:56:AB:CD:EF")},
)
mqtt_config_entry = hass.config_entries.async_entries(mqtt.DOMAIN)[0]
mqtt_config_entry = hass.config_entries.async_entries(DOMAIN)[0]
sensor_config = {
"device": {"connections": [["mac", "12:34:56:AB:CD:EF"]]},
@@ -2599,7 +2599,7 @@ async def test_mqtt_integration_discovery_flow_fitering_on_redundant_payload(
birth.set()
entry = MockConfigEntry(
domain=mqtt.DOMAIN,
domain=DOMAIN,
data={mqtt.CONF_BROKER: "mock-broker"},
options=ENTRY_DEFAULT_BIRTH_MESSAGE,
version=mqtt.CONFIG_ENTRY_VERSION,
@@ -2670,7 +2670,7 @@ async def test_mqtt_discovery_flow_starts_once(
birth.set()
entry = MockConfigEntry(
domain=mqtt.DOMAIN,
domain=DOMAIN,
data={mqtt.CONF_BROKER: "mock-broker"},
options=ENTRY_DEFAULT_BIRTH_MESSAGE,
version=mqtt.CONFIG_ENTRY_VERSION,
@@ -2808,7 +2808,7 @@ async def test_mqtt_discovery_flow_subscribes_atr_configured_qos(
birth.set()
entry = MockConfigEntry(
domain=mqtt.DOMAIN,
domain=DOMAIN,
data={mqtt.CONF_BROKER: "mock-broker"},
options=mqtt_config_entry_options,
version=mqtt.CONFIG_ENTRY_VERSION,
+7 -6
View File
@@ -7,7 +7,8 @@ from unittest.mock import patch
from freezegun.api import FrozenDateTimeFactory
import pytest
from homeassistant.components import event, mqtt
from homeassistant.components import event
from homeassistant.components.mqtt.const import DOMAIN
from homeassistant.components.mqtt.event import MQTT_EVENT_ATTRIBUTES_BLOCKED
from homeassistant.const import STATE_UNKNOWN
from homeassistant.core import HomeAssistant
@@ -56,7 +57,7 @@ from tests.common import MockConfigEntry, async_fire_mqtt_message
from tests.typing import MqttMockHAClientGenerator, MqttMockPahoClient
DEFAULT_CONFIG = {
mqtt.DOMAIN: {
DOMAIN: {
event.DOMAIN: {
"name": "test",
"state_topic": "test-topic",
@@ -186,7 +187,7 @@ async def test_setting_event_value_with_invalid_payload(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
event.DOMAIN: {
"name": "test",
"state_topic": "test-topic",
@@ -319,7 +320,7 @@ async def test_discovery_update_availability(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
event.DOMAIN: {
"name": "test",
"state_topic": "test-topic",
@@ -405,7 +406,7 @@ async def test_discovery_update_attr(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
event.DOMAIN: [
{
"name": "Test 1",
@@ -630,7 +631,7 @@ async def test_entity_category(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
event.DOMAIN: {
"name": "test",
"state_topic": "test-topic",
+36 -35
View File
@@ -7,7 +7,7 @@ from unittest.mock import patch
import pytest
from voluptuous.error import MultipleInvalid
from homeassistant.components import fan, mqtt
from homeassistant.components import fan
from homeassistant.components.fan import (
ATTR_DIRECTION,
ATTR_OSCILLATING,
@@ -16,6 +16,7 @@ from homeassistant.components.fan import (
ATTR_PRESET_MODES,
NotValidPresetModeError,
)
from homeassistant.components.mqtt.const import DOMAIN
from homeassistant.components.mqtt.fan import (
CONF_DIRECTION_COMMAND_TOPIC,
CONF_DIRECTION_STATE_TOPIC,
@@ -72,7 +73,7 @@ from tests.components.fan import common
from tests.typing import MqttMockHAClientGenerator, MqttMockPahoClient
DEFAULT_CONFIG = {
mqtt.DOMAIN: {
DOMAIN: {
fan.DOMAIN: {
"name": "test",
"state_topic": "state-topic",
@@ -82,7 +83,7 @@ DEFAULT_CONFIG = {
}
@pytest.mark.parametrize("hass_config", [{mqtt.DOMAIN: {fan.DOMAIN: {"name": "test"}}}])
@pytest.mark.parametrize("hass_config", [{DOMAIN: {fan.DOMAIN: {"name": "test"}}}])
@pytest.mark.usefixtures("hass")
async def test_fail_setup_if_no_command_topic(
caplog: pytest.LogCaptureFixture, mqtt_mock_entry: MqttMockHAClientGenerator
@@ -96,7 +97,7 @@ async def test_fail_setup_if_no_command_topic(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
fan.DOMAIN: {
"name": "test",
"state_topic": "state-topic",
@@ -232,7 +233,7 @@ async def test_controlling_state_via_topic(
help_custom_config(
fan.DOMAIN,
{
mqtt.DOMAIN: {
DOMAIN: {
fan.DOMAIN: {
"command_topic": "command-topic",
"percentage_command_topic": "percentage-command-topic",
@@ -295,7 +296,7 @@ async def test_controlling_state_via_topic_with_different_speed_range(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
fan.DOMAIN: {
"name": "test",
"state_topic": "state-topic",
@@ -354,7 +355,7 @@ async def test_controlling_state_via_topic_no_percentage_topics(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
fan.DOMAIN: {
"name": "test",
"state_topic": "state-topic",
@@ -472,7 +473,7 @@ async def test_controlling_state_via_topic_and_json_message(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
fan.DOMAIN: {
"name": "test",
"state_topic": "shared-state-topic",
@@ -587,7 +588,7 @@ async def test_controlling_state_via_topic_and_json_message_shared_topic(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
fan.DOMAIN: {
"name": "test",
"command_topic": "command-topic",
@@ -734,7 +735,7 @@ async def test_sending_mqtt_commands_and_optimistic(
help_custom_config(
fan.DOMAIN,
{
mqtt.DOMAIN: {
DOMAIN: {
fan.DOMAIN: {
"name": "test1",
"command_topic": "command-topic",
@@ -842,7 +843,7 @@ async def test_sending_mqtt_commands_with_alternate_speed_range(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
fan.DOMAIN: {
"name": "test",
"command_topic": "command-topic",
@@ -989,7 +990,7 @@ async def test_sending_mqtt_commands_and_optimistic_no_legacy(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
fan.DOMAIN: {
"name": "test",
"command_topic": "command-topic",
@@ -1197,7 +1198,7 @@ async def test_sending_mqtt_command_templates_(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
fan.DOMAIN: {
"name": "test",
"command_topic": "command-topic",
@@ -1260,7 +1261,7 @@ async def test_sending_mqtt_commands_and_optimistic_no_percentage_topic(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
fan.DOMAIN: {
"name": "test",
"state_topic": "state-topic",
@@ -1576,7 +1577,7 @@ async def test_encoding_subscribable_topics(
attribute_value: Any,
) -> None:
"""Test handling of incoming encoded payload."""
config: dict[str, Any] = copy.deepcopy(DEFAULT_CONFIG[mqtt.DOMAIN][fan.DOMAIN])
config: dict[str, Any] = copy.deepcopy(DEFAULT_CONFIG[DOMAIN][fan.DOMAIN])
config[ATTR_PRESET_MODES] = ["eco", "auto"]
config[CONF_PRESET_MODE_COMMAND_TOPIC] = "fan/some_preset_mode_command_topic"
config[CONF_PERCENTAGE_COMMAND_TOPIC] = "fan/some_percentage_command_topic"
@@ -1598,7 +1599,7 @@ async def test_encoding_subscribable_topics(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
fan.DOMAIN: {
"name": "test",
"command_topic": "command-topic",
@@ -1672,7 +1673,7 @@ async def test_attributes(
(
"test1",
{
mqtt.DOMAIN: {
DOMAIN: {
fan.DOMAIN: {
"name": "test1",
"command_topic": "command-topic",
@@ -1686,7 +1687,7 @@ async def test_attributes(
(
"test2",
{
mqtt.DOMAIN: {
DOMAIN: {
fan.DOMAIN: {
"name": "test2",
"command_topic": "command-topic",
@@ -1703,7 +1704,7 @@ async def test_attributes(
(
"test3",
{
mqtt.DOMAIN: {
DOMAIN: {
fan.DOMAIN: {
"name": "test3",
"command_topic": "command-topic",
@@ -1720,7 +1721,7 @@ async def test_attributes(
(
"test4",
{
mqtt.DOMAIN: {
DOMAIN: {
fan.DOMAIN: {
"name": "test4",
"command_topic": "command-topic",
@@ -1735,7 +1736,7 @@ async def test_attributes(
(
"test5",
{
mqtt.DOMAIN: {
DOMAIN: {
fan.DOMAIN: {
"name": "test5",
"command_topic": "command-topic",
@@ -1753,7 +1754,7 @@ async def test_attributes(
(
"test6",
{
mqtt.DOMAIN: {
DOMAIN: {
fan.DOMAIN: {
"name": "test6",
"command_topic": "command-topic",
@@ -1771,7 +1772,7 @@ async def test_attributes(
(
"test7",
{
mqtt.DOMAIN: {
DOMAIN: {
fan.DOMAIN: {
"name": "test7",
"command_topic": "command-topic",
@@ -1788,7 +1789,7 @@ async def test_attributes(
(
"test8",
{
mqtt.DOMAIN: {
DOMAIN: {
fan.DOMAIN: {
"name": "test8",
"command_topic": "command-topic",
@@ -1807,7 +1808,7 @@ async def test_attributes(
(
"test9",
{
mqtt.DOMAIN: {
DOMAIN: {
fan.DOMAIN: {
"name": "test9",
"command_topic": "command-topic",
@@ -1825,7 +1826,7 @@ async def test_attributes(
(
"test10",
{
mqtt.DOMAIN: {
DOMAIN: {
fan.DOMAIN: {
"name": "test10",
"command_topic": "command-topic",
@@ -1843,7 +1844,7 @@ async def test_attributes(
(
"test11",
{
mqtt.DOMAIN: {
DOMAIN: {
fan.DOMAIN: {
"name": "test11",
"command_topic": "command-topic",
@@ -1863,7 +1864,7 @@ async def test_attributes(
(
"test12",
{
mqtt.DOMAIN: {
DOMAIN: {
fan.DOMAIN: {
"name": "test12",
"command_topic": "command-topic",
@@ -1882,7 +1883,7 @@ async def test_attributes(
(
"test13",
{
mqtt.DOMAIN: {
DOMAIN: {
fan.DOMAIN: {
"name": "test13",
"command_topic": "command-topic",
@@ -1899,7 +1900,7 @@ async def test_attributes(
(
"test14",
{
mqtt.DOMAIN: {
DOMAIN: {
fan.DOMAIN: {
"name": "test14",
"command_topic": "command-topic",
@@ -1916,7 +1917,7 @@ async def test_attributes(
(
"test15",
{
mqtt.DOMAIN: {
DOMAIN: {
fan.DOMAIN: {
"name": "test15",
"command_topic": "command-topic",
@@ -1932,7 +1933,7 @@ async def test_attributes(
(
"test16",
{
mqtt.DOMAIN: {
DOMAIN: {
fan.DOMAIN: {
"name": "test16",
"command_topic": "command-topic",
@@ -1951,7 +1952,7 @@ async def test_attributes(
(
"test17",
{
mqtt.DOMAIN: {
DOMAIN: {
fan.DOMAIN: {
"name": "test17",
"command_topic": "command-topic",
@@ -2096,7 +2097,7 @@ async def test_discovery_update_attr(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
fan.DOMAIN: [
{
"name": "Test 1",
@@ -2293,7 +2294,7 @@ async def test_publishing_with_custom_encoding(
domain = fan.DOMAIN
config: dict[str, Any] = copy.deepcopy(DEFAULT_CONFIG)
if topic == "preset_mode_command_topic":
config[mqtt.DOMAIN][domain]["preset_modes"] = ["auto", "eco"]
config[DOMAIN][domain]["preset_modes"] = ["auto", "eco"]
await help_test_publishing_with_custom_encoding(
hass,
+29 -31
View File
@@ -7,7 +7,7 @@ from unittest.mock import patch
import pytest
from voluptuous.error import MultipleInvalid
from homeassistant.components import humidifier, mqtt
from homeassistant.components import humidifier
from homeassistant.components.humidifier import (
ATTR_CURRENT_HUMIDITY,
ATTR_HUMIDITY,
@@ -16,7 +16,7 @@ from homeassistant.components.humidifier import (
SERVICE_SET_MODE,
HumidifierAction,
)
from homeassistant.components.mqtt.const import CONF_CURRENT_HUMIDITY_TOPIC
from homeassistant.components.mqtt.const import CONF_CURRENT_HUMIDITY_TOPIC, DOMAIN
from homeassistant.components.mqtt.humidifier import (
CONF_MODE_COMMAND_TOPIC,
CONF_MODE_STATE_TOPIC,
@@ -71,7 +71,7 @@ from tests.common import async_fire_mqtt_message
from tests.typing import MqttMockHAClientGenerator, MqttMockPahoClient
DEFAULT_CONFIG = {
mqtt.DOMAIN: {
DOMAIN: {
humidifier.DOMAIN: {
"name": "test",
"state_topic": "state-topic",
@@ -133,7 +133,7 @@ async def async_set_humidity(
@pytest.mark.parametrize(
"hass_config", [{mqtt.DOMAIN: {humidifier.DOMAIN: {"name": "test"}}}]
"hass_config", [{DOMAIN: {humidifier.DOMAIN: {"name": "test"}}}]
)
@pytest.mark.usefixtures("hass")
async def test_fail_setup_if_no_command_topic(
@@ -148,7 +148,7 @@ async def test_fail_setup_if_no_command_topic(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
humidifier.DOMAIN: {
"name": "test",
"action_topic": "action-topic",
@@ -308,7 +308,7 @@ async def test_controlling_state_via_topic(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
humidifier.DOMAIN: {
"name": "test",
"action_topic": "action-topic",
@@ -449,7 +449,7 @@ async def test_controlling_state_via_topic_and_json_message(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
humidifier.DOMAIN: {
"name": "test",
"state_topic": "shared-state-topic",
@@ -528,7 +528,7 @@ async def test_controlling_state_via_topic_and_json_message_shared_topic(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
humidifier.DOMAIN: {
"name": "test",
"command_topic": "command-topic",
@@ -627,7 +627,7 @@ async def test_sending_mqtt_commands_and_optimistic(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
humidifier.DOMAIN: {
"name": "test",
"command_topic": "command-topic",
@@ -731,7 +731,7 @@ async def test_sending_mqtt_command_templates_(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
humidifier.DOMAIN: {
"name": "test",
"state_topic": "state-topic",
@@ -870,9 +870,7 @@ async def test_encoding_subscribable_topics(
attribute_value: Any,
) -> None:
"""Test handling of incoming encoded payload."""
config: dict[str, Any] = copy.deepcopy(
DEFAULT_CONFIG[mqtt.DOMAIN][humidifier.DOMAIN]
)
config: dict[str, Any] = copy.deepcopy(DEFAULT_CONFIG[DOMAIN][humidifier.DOMAIN])
config["modes"] = ["eco", "auto"]
config[CONF_MODE_COMMAND_TOPIC] = "humidifier/some_mode_command_topic"
await help_test_encoding_subscribable_topics(
@@ -891,7 +889,7 @@ async def test_encoding_subscribable_topics(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
humidifier.DOMAIN: {
"name": "test",
"command_topic": "command-topic",
@@ -941,7 +939,7 @@ async def test_attributes(
[
( # test valid case 1
{
mqtt.DOMAIN: {
DOMAIN: {
humidifier.DOMAIN: {
"name": "test",
"command_topic": "command-topic",
@@ -953,7 +951,7 @@ async def test_attributes(
),
( # test valid case 2
{
mqtt.DOMAIN: {
DOMAIN: {
humidifier.DOMAIN: {
"name": "test",
"command_topic": "command-topic",
@@ -966,7 +964,7 @@ async def test_attributes(
),
( # test valid case 3
{
mqtt.DOMAIN: {
DOMAIN: {
humidifier.DOMAIN: {
"name": "test",
"command_topic": "command-topic",
@@ -979,7 +977,7 @@ async def test_attributes(
),
( # test valid case 4
{
mqtt.DOMAIN: {
DOMAIN: {
humidifier.DOMAIN: {
"name": "test",
"command_topic": "command-topic",
@@ -992,7 +990,7 @@ async def test_attributes(
),
( # test invalid device_class
{
mqtt.DOMAIN: {
DOMAIN: {
humidifier.DOMAIN: {
"name": "test",
"command_topic": "command-topic",
@@ -1005,7 +1003,7 @@ async def test_attributes(
),
( # test mode_command_topic without modes
{
mqtt.DOMAIN: {
DOMAIN: {
humidifier.DOMAIN: {
"name": "test",
"command_topic": "command-topic",
@@ -1018,7 +1016,7 @@ async def test_attributes(
),
( # test invalid humidity min max case 1
{
mqtt.DOMAIN: {
DOMAIN: {
humidifier.DOMAIN: {
"name": "test",
"command_topic": "command-topic",
@@ -1032,7 +1030,7 @@ async def test_attributes(
),
( # test invalid humidity min max case 2
{
mqtt.DOMAIN: {
DOMAIN: {
humidifier.DOMAIN: {
"name": "test",
"command_topic": "command-topic",
@@ -1046,7 +1044,7 @@ async def test_attributes(
),
( # test invalid mode, is reset payload
{
mqtt.DOMAIN: {
DOMAIN: {
humidifier.DOMAIN: {
"name": "test",
"command_topic": "command-topic",
@@ -1075,7 +1073,7 @@ async def test_validity_configurations(
(
"test1",
{
mqtt.DOMAIN: {
DOMAIN: {
humidifier.DOMAIN: {
"name": "test1",
"command_topic": "command-topic",
@@ -1089,7 +1087,7 @@ async def test_validity_configurations(
(
"test2",
{
mqtt.DOMAIN: {
DOMAIN: {
humidifier.DOMAIN: {
"name": "test2",
"command_topic": "command-topic",
@@ -1105,7 +1103,7 @@ async def test_validity_configurations(
(
"test3",
{
mqtt.DOMAIN: {
DOMAIN: {
humidifier.DOMAIN: {
"name": "test3",
"command_topic": "command-topic",
@@ -1119,7 +1117,7 @@ async def test_validity_configurations(
(
"test4",
{
mqtt.DOMAIN: {
DOMAIN: {
humidifier.DOMAIN: {
"name": "test4",
"command_topic": "command-topic",
@@ -1135,7 +1133,7 @@ async def test_validity_configurations(
(
"test5",
{
mqtt.DOMAIN: {
DOMAIN: {
humidifier.DOMAIN: {
"name": "test5",
"command_topic": "command-topic",
@@ -1148,7 +1146,7 @@ async def test_validity_configurations(
(
"test6",
{
mqtt.DOMAIN: {
DOMAIN: {
humidifier.DOMAIN: {
"name": "test6",
"target_humidity_command_topic": "humidity-command-topic",
@@ -1291,7 +1289,7 @@ async def test_discovery_update_attr(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
humidifier.DOMAIN: [
{
"name": "Test 1",
@@ -1494,7 +1492,7 @@ async def test_publishing_with_custom_encoding(
domain = humidifier.DOMAIN
config: dict[str, Any] = copy.deepcopy(DEFAULT_CONFIG)
if topic == "mode_command_topic":
config[mqtt.DOMAIN][domain]["modes"] = ["auto", "eco"]
config[DOMAIN][domain]["modes"] = ["auto", "eco"]
await help_test_publishing_with_custom_encoding(
hass,
+16 -17
View File
@@ -10,7 +10,8 @@ import httpx
import pytest
import respx
from homeassistant.components import image, mqtt
from homeassistant.components import image
from homeassistant.components.mqtt.const import DOMAIN
from homeassistant.const import STATE_UNAVAILABLE, STATE_UNKNOWN
from homeassistant.core import HomeAssistant
@@ -49,15 +50,13 @@ from tests.typing import (
MqttMockPahoClient,
)
DEFAULT_CONFIG = {
mqtt.DOMAIN: {image.DOMAIN: {"name": "test", "image_topic": "test_topic"}}
}
DEFAULT_CONFIG = {DOMAIN: {image.DOMAIN: {"name": "test", "image_topic": "test_topic"}}}
@pytest.mark.freeze_time("2023-04-01 00:00:00+00:00")
@pytest.mark.parametrize(
"hass_config",
[{mqtt.DOMAIN: {image.DOMAIN: {"image_topic": "test/image", "name": "Test"}}}],
[{DOMAIN: {image.DOMAIN: {"image_topic": "test/image", "name": "Test"}}}],
)
async def test_run_image_setup(
hass: HomeAssistant,
@@ -93,7 +92,7 @@ async def test_run_image_setup(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
image.DOMAIN: {
"image_topic": "test/image",
"name": "Test",
@@ -147,7 +146,7 @@ async def test_run_image_b64_encoded(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
"image": {
"image_topic": "test/image",
"name": "Test",
@@ -200,7 +199,7 @@ async def test_image_b64_encoded_with_availability(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
"image": {
"url_topic": "test/image",
"name": "Test",
@@ -281,7 +280,7 @@ async def test_image_from_url(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
"image": {
"url_topic": "test/image",
"name": "Test",
@@ -334,7 +333,7 @@ async def test_image_from_url_with_template(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
"image": {
"url_topic": "test/image",
"name": "Test",
@@ -402,7 +401,7 @@ async def test_image_from_url_content_type(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
"image": {
"url_topic": "test/image",
"name": "Test",
@@ -462,7 +461,7 @@ async def test_image_from_url_fails(
[
(
{
mqtt.DOMAIN: {
DOMAIN: {
"image": {
"url_topic": "test/image",
"content_type": "image/jpg",
@@ -475,7 +474,7 @@ async def test_image_from_url_fails(
),
(
{
mqtt.DOMAIN: {
DOMAIN: {
"image": {
"url_topic": "test/image",
"image_topic": "test/image-data-topic",
@@ -488,7 +487,7 @@ async def test_image_from_url_fails(
),
(
{
mqtt.DOMAIN: {
DOMAIN: {
"image": {
"name": "Test",
"encoding": "utf-8",
@@ -601,7 +600,7 @@ async def test_discovery_update_attr(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
image.DOMAIN: [
{
"name": "Test 1",
@@ -629,7 +628,7 @@ async def test_discovery_removal_image(
hass: HomeAssistant, mqtt_mock_entry: MqttMockHAClientGenerator
) -> None:
"""Test removal of discovered image."""
data = json.dumps(DEFAULT_CONFIG[mqtt.DOMAIN][image.DOMAIN])
data = json.dumps(DEFAULT_CONFIG[DOMAIN][image.DOMAIN])
await help_test_discovery_removal(hass, mqtt_mock_entry, image.DOMAIN, data)
@@ -806,7 +805,7 @@ async def test_skipped_async_ha_write_state(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
image.DOMAIN: {
"name": "test",
"url_topic": "test-topic",
+61 -48
View File
@@ -18,6 +18,7 @@ import voluptuous as vol
from homeassistant import core as ha
from homeassistant.components import mqtt
from homeassistant.components.mqtt import debug_info
from homeassistant.components.mqtt.const import DOMAIN
from homeassistant.components.mqtt.models import (
MessageCallbackType,
MqttCommandTemplateException,
@@ -272,7 +273,7 @@ async def test_service_call_without_topic_does_not_publish(
mqtt_mock = await mqtt_mock_entry()
with pytest.raises(vol.Invalid):
await hass.services.async_call(
mqtt.DOMAIN,
DOMAIN,
mqtt.SERVICE_PUBLISH,
{},
blocking=True,
@@ -284,7 +285,7 @@ async def test_service_call_mqtt_entry_does_not_publish(
hass: HomeAssistant, mqtt_client_mock: MqttMockPahoClient
) -> None:
"""Test the service call if topic is missing."""
assert await async_setup_component(hass, mqtt.DOMAIN, {})
assert await async_setup_component(hass, DOMAIN, {})
with pytest.raises(
ServiceValidationError,
match=(
@@ -292,7 +293,7 @@ async def test_service_call_mqtt_entry_does_not_publish(
),
):
await hass.services.async_call(
mqtt.DOMAIN,
DOMAIN,
mqtt.SERVICE_PUBLISH,
{
mqtt.ATTR_TOPIC: "test_topic",
@@ -312,7 +313,7 @@ async def test_service_call_with_template_topic_renders_invalid_topic(
mqtt_mock = await mqtt_mock_entry()
with pytest.raises(vol.Invalid) as exc:
await hass.services.async_call(
mqtt.DOMAIN,
DOMAIN,
mqtt.SERVICE_PUBLISH,
{
mqtt.ATTR_TOPIC: "test/{{ '+' if True else 'topic' }}/topic",
@@ -356,7 +357,7 @@ async def test_mqtt_publish_action_call_with_raw_data(
"""
mqtt_mock = await mqtt_mock_entry()
await hass.services.async_call(
mqtt.DOMAIN,
DOMAIN,
mqtt.SERVICE_PUBLISH,
{
mqtt.ATTR_TOPIC: "test/topic",
@@ -372,7 +373,7 @@ async def test_mqtt_publish_action_call_with_raw_data(
"homeassistant.components.mqtt.models.literal_eval"
) as literal_eval_mock:
await hass.services.async_call(
mqtt.DOMAIN,
DOMAIN,
mqtt.SERVICE_PUBLISH,
{
mqtt.ATTR_TOPIC: "test/topic",
@@ -383,7 +384,7 @@ async def test_mqtt_publish_action_call_with_raw_data(
literal_eval_mock.assert_not_called()
await hass.services.async_call(
mqtt.DOMAIN,
DOMAIN,
mqtt.SERVICE_PUBLISH,
{
mqtt.ATTR_TOPIC: "test/topic",
@@ -404,7 +405,7 @@ async def test_service_call_with_ascii_qos_retain_flags(
"""
mqtt_mock = await mqtt_mock_entry()
await hass.services.async_call(
mqtt.DOMAIN,
DOMAIN,
mqtt.SERVICE_PUBLISH,
{
mqtt.ATTR_TOPIC: "test/topic",
@@ -423,7 +424,7 @@ async def test_service_call_with_ascii_qos_retain_flags(
# Test service call without payload
await hass.services.async_call(
mqtt.DOMAIN,
DOMAIN,
mqtt.SERVICE_PUBLISH,
{
mqtt.ATTR_TOPIC: "test/topic",
@@ -485,7 +486,7 @@ async def test_publish_action_with_message_expiry_interval(
"""Test the publish action message expiry interval option."""
mqtt_mock = await mqtt_mock_entry()
await hass.services.async_call(
mqtt.DOMAIN,
DOMAIN,
mqtt.SERVICE_PUBLISH,
{
mqtt.ATTR_TOPIC: "test/topic",
@@ -708,7 +709,7 @@ def test_entity_device_info_schema() -> None:
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
"sensor": [
{
"name": "test-sensor",
@@ -807,13 +808,13 @@ async def test_reload_entry_with_restored_subscriptions(
"""Test reloading the config entry with with subscriptions restored."""
# Setup the MQTT entry
entry = MockConfigEntry(
domain=mqtt.DOMAIN,
domain=DOMAIN,
data={mqtt.CONF_BROKER: "test-broker"},
version=mqtt.CONFIG_ENTRY_VERSION,
minor_version=mqtt.CONFIG_ENTRY_MINOR_VERSION,
)
entry.add_to_hass(hass)
hass.config.components.add(mqtt.DOMAIN)
hass.config.components.add(DOMAIN)
with patch("homeassistant.config.load_yaml_config_file", return_value={}):
await hass.config_entries.async_setup(entry.entry_id)
@@ -869,11 +870,27 @@ async def test_reload_entry_with_restored_subscriptions(
assert recorded_calls[1].payload == "wild-card-payload3"
@pytest.mark.usefixtures("mqtt_client_mock")
async def test_reload_without_entry(
hass: HomeAssistant, caplog: pytest.LogCaptureFixture
) -> None:
"""Test reloading without a valid config entry set up."""
# Setup the MQTT integration without entry
assert await async_setup_component(hass, DOMAIN, {})
await hass.async_block_till_done()
with caplog.at_level(logging.DEBUG):
await hass.services.async_call(DOMAIN, SERVICE_RELOAD, {}, blocking=True)
assert (
"Skipped reloading MQTT integration, the MQTT config entry is not enabled"
in caplog.text
)
@pytest.mark.parametrize(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
"light": {
"platform": "mqtt",
"name": "test",
@@ -894,7 +911,7 @@ async def test_setup_manual_mqtt_with_platform_key(
)
@pytest.mark.parametrize("hass_config", [{mqtt.DOMAIN: {"light": {"name": "test"}}}])
@pytest.mark.parametrize("hass_config", [{DOMAIN: {"light": {"name": "test"}}}])
async def test_setup_manual_mqtt_with_invalid_config(
mqtt_mock_entry: MqttMockHAClientGenerator, caplog: pytest.LogCaptureFixture
) -> None:
@@ -916,13 +933,13 @@ async def test_default_entry_setting_are_applied(
# Config entry data is incomplete but valid according the schema
entry = MockConfigEntry(
domain=mqtt.DOMAIN,
domain=DOMAIN,
data={"broker": "test-broker", "port": 1234},
version=mqtt.CONFIG_ENTRY_VERSION,
minor_version=mqtt.CONFIG_ENTRY_MINOR_VERSION,
)
entry.add_to_hass(hass)
hass.config.components.add(mqtt.DOMAIN)
hass.config.components.add(DOMAIN)
assert await hass.config_entries.async_setup(entry.entry_id)
await hass.async_block_till_done()
@@ -1122,7 +1139,7 @@ async def test_mqtt_ws_remove_discovered_device(
assert device_entry is not None
client = await hass_ws_client(hass)
mqtt_config_entry = hass.config_entries.async_entries(mqtt.DOMAIN)[0]
mqtt_config_entry = hass.config_entries.async_entries(DOMAIN)[0]
response = await client.remove_device(device_entry.id, mqtt_config_entry.entry_id)
assert response["success"]
@@ -1460,7 +1477,7 @@ async def test_debug_info_non_mqtt(
)
assert await async_setup_component(
hass, mqtt.DOMAIN, {mqtt.DOMAIN: {domain: {"platform": "test"}}}
hass, DOMAIN, {DOMAIN: {domain: {"platform": "test"}}}
)
debug_info_data = debug_info.info_for_device(hass, device_entry.id)
@@ -1759,20 +1776,20 @@ async def test_unload_config_entry(
) -> None:
"""Test unloading the MQTT entry."""
entry = MockConfigEntry(
domain=mqtt.DOMAIN,
domain=DOMAIN,
data={mqtt.CONF_BROKER: "test-broker", CONF_PROTOCOL: "5"},
version=mqtt.CONFIG_ENTRY_VERSION,
minor_version=mqtt.CONFIG_ENTRY_MINOR_VERSION,
)
entry.add_to_hass(hass)
assert await async_setup_component(hass, mqtt.DOMAIN, {})
assert hass.services.has_service(mqtt.DOMAIN, "dump")
assert hass.services.has_service(mqtt.DOMAIN, "publish")
assert await async_setup_component(hass, DOMAIN, {})
assert hass.services.has_service(DOMAIN, "dump")
assert hass.services.has_service(DOMAIN, "publish")
# Make sure the debouncer finishes
await mock_debouncer.wait()
mqtt_config_entry = hass.config_entries.async_entries(mqtt.DOMAIN)[0]
mqtt_config_entry = hass.config_entries.async_entries(DOMAIN)[0]
assert mqtt_config_entry.state is ConfigEntryState.LOADED
# Publish just before unloading to test await cleanup
@@ -1802,8 +1819,8 @@ async def test_unload_config_entry(
assert new_mqtt_config_entry.state is ConfigEntryState.NOT_LOADED
await hass.async_block_till_done(wait_background_tasks=True)
assert hass.services.has_service(mqtt.DOMAIN, "dump")
assert hass.services.has_service(mqtt.DOMAIN, "publish")
assert hass.services.has_service(DOMAIN, "dump")
assert hass.services.has_service(DOMAIN, "publish")
assert "No ACK from MQTT server" not in caplog.text
@@ -1811,9 +1828,9 @@ async def test_publish_or_subscribe_without_valid_config_entry(
hass: HomeAssistant, record_calls: MessageCallbackType
) -> None:
"""Test internal publish function with bad use cases."""
assert await async_setup_component(hass, mqtt.DOMAIN, {})
assert hass.services.has_service(mqtt.DOMAIN, "dump")
assert hass.services.has_service(mqtt.DOMAIN, "publish")
assert await async_setup_component(hass, DOMAIN, {})
assert hass.services.has_service(DOMAIN, "dump")
assert hass.services.has_service(DOMAIN, "publish")
with pytest.raises(HomeAssistantError):
await mqtt.async_publish(
hass, "some-topic", "test-payload", qos=0, retain=False, encoding=None
@@ -1846,7 +1863,7 @@ async def test_disabling_and_enabling_entry(
) -> None:
"""Test disabling and enabling the config entry."""
await mqtt_mock_entry()
entry = hass.config_entries.async_entries(mqtt.DOMAIN)[0]
entry = hass.config_entries.async_entries(DOMAIN)[0]
assert entry.state is ConfigEntryState.LOADED
# Late discovery of a mqtt entity
config_tag = (
@@ -1913,7 +1930,7 @@ async def test_disabling_and_enabling_entry(
[
(
{
mqtt.DOMAIN: {
DOMAIN: {
"light": [
{
"name": "test1",
@@ -1932,7 +1949,7 @@ async def test_disabling_and_enabling_entry(
),
(
{
mqtt.DOMAIN: {
DOMAIN: {
"light": [
{
"name": "test1",
@@ -2019,8 +2036,8 @@ async def test_link_config_entry(
entity_names = ["test_manual", "test_discovery"]
# Check if both entities were linked to the MQTT config entry
mqtt_config_entry = hass.config_entries.async_entries(mqtt.DOMAIN)[0]
mqtt_platforms = async_get_platforms(hass, mqtt.DOMAIN)
mqtt_config_entry = hass.config_entries.async_entries(DOMAIN)[0]
mqtt_platforms = async_get_platforms(hass, DOMAIN)
@callback
def _check_entities() -> int:
@@ -2100,12 +2117,12 @@ async def test_reload_config_entry(
await hass.async_block_till_done()
assert hass.states.get("sensor.test_discovery") is not None
entry = hass.config_entries.async_entries(mqtt.DOMAIN)[0]
entry = hass.config_entries.async_entries(DOMAIN)[0]
@callback
def _check_entities() -> int:
entities: list[Entity] = []
mqtt_platforms = async_get_platforms(hass, mqtt.DOMAIN)
mqtt_platforms = async_get_platforms(hass, DOMAIN)
for mqtt_platform in mqtt_platforms:
assert mqtt_platform.config_entry is entry
entities += (entity for entity in mqtt_platform.entities.values())
@@ -2439,16 +2456,14 @@ async def test_mqtt_integration_level_imports(attr: str) -> None:
@pytest.mark.usefixtures("mqtt_client_mock")
@pytest.mark.parametrize(
"hass_config", [{mqtt.DOMAIN: {"sensor": {"state_topic": "test-topic"}}}]
"hass_config", [{DOMAIN: {"sensor": {"state_topic": "test-topic"}}}]
)
async def test_yaml_config_without_entry(
hass: HomeAssistant, hass_config: ConfigType, issue_registry: ir.IssueRegistry
) -> None:
"""Test a repair issue is created for YAML setup without an active config entry."""
await async_setup_component(hass, mqtt.DOMAIN, hass_config)
issue = issue_registry.async_get_issue(
mqtt.DOMAIN, "yaml_setup_without_active_setup"
)
await async_setup_component(hass, DOMAIN, hass_config)
issue = issue_registry.async_get_issue(DOMAIN, "yaml_setup_without_active_setup")
assert issue is not None
assert (
issue.learn_more_url == "https://www.home-assistant.io/integrations/mqtt/"
@@ -2457,7 +2472,7 @@ async def test_yaml_config_without_entry(
@pytest.mark.parametrize(
"hass_config", [{mqtt.DOMAIN: {"sensor": {"state_topic": "test-topic"}}}]
"hass_config", [{DOMAIN: {"sensor": {"state_topic": "test-topic"}}}]
)
async def test_yaml_config_with_active_mqtt_config_entry(
hass: HomeAssistant,
@@ -2467,9 +2482,7 @@ async def test_yaml_config_with_active_mqtt_config_entry(
) -> None:
"""Test no repair issue is created for YAML setup with an active config entry."""
await mqtt_mock_entry()
issue = issue_registry.async_get_issue(
mqtt.DOMAIN, "yaml_setup_without_active_setup"
)
issue = issue_registry.async_get_issue(DOMAIN, "yaml_setup_without_active_setup")
state = hass.states.get("sensor.mqtt_sensor")
assert state is not None
assert issue is None
@@ -2520,7 +2533,7 @@ async def test_mqtt_protocol_successful_migration_to_v5(
"The MQTT protocol version was successfully updated to version 5"
in caplog.text
)
entry = hass.config_entries.async_entries(mqtt.DOMAIN)[0]
entry = hass.config_entries.async_entries(DOMAIN)[0]
assert entry.data[mqtt.CONF_PROTOCOL] == mqtt.PROTOCOL_5
@@ -2582,7 +2595,7 @@ async def test_mqtt_protocol_failed_migration_to_v5(
issue_registry = ir.async_get(hass)
assert len(issue_registry.issues) == 1
issue = issue_registry.async_get_issue(mqtt.DOMAIN, "protocol_5_migration")
issue = issue_registry.async_get_issue(DOMAIN, "protocol_5_migration")
assert issue is not None
assert issue.translation_key == "protocol_5_migration"
assert issue.translation_placeholders == {
@@ -2593,5 +2606,5 @@ async def test_mqtt_protocol_failed_migration_to_v5(
"The MQTT protocol version was successfully updated to version 5"
not in caplog.text
)
entry = hass.config_entries.async_entries(mqtt.DOMAIN)[0]
entry = hass.config_entries.async_entries(DOMAIN)[0]
assert entry.data.get(mqtt.CONF_PROTOCOL, mqtt.PROTOCOL_311) == current_protocol
+16 -17
View File
@@ -7,7 +7,7 @@ from unittest.mock import patch
import pytest
from homeassistant.components import lawn_mower, mqtt
from homeassistant.components import lawn_mower
from homeassistant.components.lawn_mower import (
DOMAIN as LAWN_MOWER_DOMAIN,
SERVICE_DOCK,
@@ -15,6 +15,7 @@ from homeassistant.components.lawn_mower import (
SERVICE_START_MOWING,
LawnMowerEntityFeature,
)
from homeassistant.components.mqtt.const import DOMAIN
from homeassistant.components.mqtt.lawn_mower import MQTT_LAWN_MOWER_ATTRIBUTES_BLOCKED
from homeassistant.const import ATTR_ASSUMED_STATE, ATTR_ENTITY_ID, STATE_UNKNOWN
from homeassistant.core import HomeAssistant, State
@@ -63,7 +64,7 @@ DEFAULT_FEATURES = (
)
DEFAULT_CONFIG = {
mqtt.DOMAIN: {
DOMAIN: {
lawn_mower.DOMAIN: {
"name": "test",
"dock_command_topic": "dock-test-topic",
@@ -78,7 +79,7 @@ DEFAULT_CONFIG = {
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
lawn_mower.DOMAIN: {
"activity_state_topic": "test/lawn_mower_stat",
"dock_command_topic": "dock-test-topic",
@@ -135,7 +136,7 @@ async def test_run_lawn_mower_setup_and_state_updates(
),
(
{
mqtt.DOMAIN: {
DOMAIN: {
lawn_mower.DOMAIN: {
"pause_command_topic": "pause-test-topic",
"name": "test",
@@ -146,7 +147,7 @@ async def test_run_lawn_mower_setup_and_state_updates(
),
(
{
mqtt.DOMAIN: {
DOMAIN: {
lawn_mower.DOMAIN: {
"dock_command_topic": "dock-test-topic",
"start_mowing_command_topic": "start_mowing-test-topic",
@@ -175,7 +176,7 @@ async def test_supported_features(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
lawn_mower.DOMAIN: {
"activity_state_topic": "test/lawn_mower_stat",
"name": "Test Lawn Mower",
@@ -289,7 +290,7 @@ async def test_run_lawn_mower_service_optimistic(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
lawn_mower.DOMAIN: {
"pause_command_topic": "test/lawn_mower_pause_cmd",
"name": "Test Lawn Mower",
@@ -315,7 +316,7 @@ async def test_restore_lawn_mower_from_invalid_state(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
lawn_mower.DOMAIN: {
"name": "Test Lawn Mower",
"dock_command_topic": "test/lawn_mower_dock_cmd",
@@ -501,7 +502,7 @@ async def test_discovery_update_attr(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
lawn_mower.DOMAIN: [
{
"name": "Test 1",
@@ -529,7 +530,7 @@ async def test_discovery_removal_lawn_mower(
hass: HomeAssistant, mqtt_mock_entry: MqttMockHAClientGenerator
) -> None:
"""Test removal of discovered lawn_mower."""
data = json.dumps(DEFAULT_CONFIG[mqtt.DOMAIN][lawn_mower.DOMAIN])
data = json.dumps(DEFAULT_CONFIG[DOMAIN][lawn_mower.DOMAIN])
await help_test_discovery_removal(hass, mqtt_mock_entry, lawn_mower.DOMAIN, data)
@@ -628,7 +629,7 @@ async def test_entity_id_update_subscriptions(
) -> None:
"""Test MQTT subscriptions are managed when entity_id is updated."""
config = {
mqtt.DOMAIN: {
DOMAIN: {
lawn_mower.DOMAIN: {
"name": "test",
"activity_state_topic": "test-topic",
@@ -687,7 +688,7 @@ async def test_entity_debug_info_message(
) -> None:
"""Test MQTT debug info."""
config = {
mqtt.DOMAIN: {
DOMAIN: {
lawn_mower.DOMAIN: {
"activity_state_topic": "test/lawn_mower_stat",
"dock_command_topic": "dock-test-topic",
@@ -714,7 +715,7 @@ async def test_entity_debug_info_message(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
lawn_mower.DOMAIN: {
"dock_command_topic": "dock-test-topic",
"pause_command_topic": "pause-test-topic",
@@ -826,9 +827,7 @@ async def test_encoding_subscribable_topics(
attribute_value: Any,
) -> None:
"""Test handling of incoming encoded payload."""
config: dict[str, Any] = copy.deepcopy(
DEFAULT_CONFIG[mqtt.DOMAIN][lawn_mower.DOMAIN]
)
config: dict[str, Any] = copy.deepcopy(DEFAULT_CONFIG[DOMAIN][lawn_mower.DOMAIN])
config["actions"] = ["milk", "beer"]
await help_test_encoding_subscribable_topics(
hass,
@@ -935,7 +934,7 @@ async def test_skipped_async_ha_write_state(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
lawn_mower.DOMAIN: {
"name": "test",
"activity_state_topic": "test-topic",
+43 -44
View File
@@ -192,7 +192,8 @@ from unittest.mock import call, patch
import pytest
from homeassistant.components import light, mqtt
from homeassistant.components import light
from homeassistant.components.mqtt.const import DOMAIN
from homeassistant.components.mqtt.light.schema_basic import (
CONF_BRIGHTNESS_COMMAND_TOPIC,
CONF_COLOR_TEMP_COMMAND_TOPIC,
@@ -246,13 +247,11 @@ from tests.components.light import common
from tests.typing import MqttMockHAClientGenerator, MqttMockPahoClient
DEFAULT_CONFIG = {
mqtt.DOMAIN: {light.DOMAIN: {"name": "test", "command_topic": "test-topic"}}
DOMAIN: {light.DOMAIN: {"name": "test", "command_topic": "test-topic"}}
}
@pytest.mark.parametrize(
"hass_config", [{mqtt.DOMAIN: {light.DOMAIN: {"name": "test"}}}]
)
@pytest.mark.parametrize("hass_config", [{DOMAIN: {light.DOMAIN: {"name": "test"}}}])
async def test_fail_setup_if_no_command_topic(
hass: HomeAssistant,
mqtt_mock_entry: MqttMockHAClientGenerator,
@@ -267,7 +266,7 @@ async def test_fail_setup_if_no_command_topic(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
light.DOMAIN: {
"name": "test",
"state_topic": "test_light_rgb/status",
@@ -421,7 +420,7 @@ async def test_no_min_max_kelvin(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
light.DOMAIN: {
"name": "test",
"state_topic": "test_light_rgb/status",
@@ -548,7 +547,7 @@ async def test_controlling_state_via_topic(
[
(
{
mqtt.DOMAIN: {
DOMAIN: {
light.DOMAIN: {
"name": "test",
"state_topic": "test_light_color_temp/status",
@@ -574,7 +573,7 @@ async def test_controlling_state_via_topic(
),
(
{
mqtt.DOMAIN: {
DOMAIN: {
light.DOMAIN: {
"name": "test",
"state_topic": "test_light_color_temp/status",
@@ -803,7 +802,7 @@ async def test_received_rgbx_values_set_state_optimistic(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
light.DOMAIN: {
"name": "test",
"state_topic": "test_light_rgb/status",
@@ -935,7 +934,7 @@ async def test_invalid_state_via_topic(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
light.DOMAIN: {
"name": "test",
"state_topic": "test_scale/status",
@@ -985,7 +984,7 @@ async def test_brightness_controlling_scale(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
light.DOMAIN: {
"name": "test",
"state_topic": "test_scale_rgb/status",
@@ -1059,7 +1058,7 @@ async def test_brightness_from_rgb_controlling_scale(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
light.DOMAIN: {
"name": "test",
"state_topic": "test_light_rgb/status",
@@ -1179,7 +1178,7 @@ async def test_controlling_state_via_topic_with_templates(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
light.DOMAIN: {
"name": "test",
"command_topic": "test_light_rgb/set",
@@ -1445,7 +1444,7 @@ async def test_sending_mqtt_commands_and_optimistic(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
light.DOMAIN: {
"name": "test",
"command_topic": "test_light_rgb/set",
@@ -1494,7 +1493,7 @@ async def test_sending_mqtt_rgb_command_with_template(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
light.DOMAIN: {
"name": "test",
"command_topic": "test_light_rgb/set",
@@ -1543,7 +1542,7 @@ async def test_sending_mqtt_rgbw_command_with_template(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
light.DOMAIN: {
"name": "test",
"command_topic": "test_light_rgb/set",
@@ -1593,7 +1592,7 @@ async def test_sending_mqtt_rgbww_command_with_template(
[
(
{
mqtt.DOMAIN: {
DOMAIN: {
light.DOMAIN: {
"name": "test",
"command_topic": "test_light_color_temp/set",
@@ -1614,7 +1613,7 @@ async def test_sending_mqtt_rgbww_command_with_template(
),
(
{
mqtt.DOMAIN: {
DOMAIN: {
light.DOMAIN: {
"name": "test",
"command_topic": "test_light_color_temp/set",
@@ -1674,7 +1673,7 @@ async def test_sending_mqtt_color_temp_command_with_template(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
light.DOMAIN: {
"name": "test",
"command_topic": "test_light/set",
@@ -1718,7 +1717,7 @@ async def test_on_command_first(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
light.DOMAIN: {
"name": "test",
"command_topic": "test_light/set",
@@ -1761,7 +1760,7 @@ async def test_on_command_last(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
light.DOMAIN: {
"name": "test",
"command_topic": "test_light/set",
@@ -1826,7 +1825,7 @@ async def test_on_command_brightness(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
light.DOMAIN: {
"name": "test",
"command_topic": "test_light/set",
@@ -1908,7 +1907,7 @@ async def test_on_command_brightness_scaled(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
light.DOMAIN: {
"name": "test",
"command_topic": "test_light/set",
@@ -2010,7 +2009,7 @@ async def test_on_command_rgb(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
light.DOMAIN: {
"name": "test",
"command_topic": "test_light/set",
@@ -2126,7 +2125,7 @@ async def test_on_command_rgbw(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
light.DOMAIN: {
"name": "test",
"command_topic": "test_light/set",
@@ -2246,7 +2245,7 @@ async def test_on_command_rgbww(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
light.DOMAIN: {
"name": "test",
"command_topic": "test_light/set",
@@ -2293,7 +2292,7 @@ async def test_on_command_rgb_template(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
light.DOMAIN: {
"name": "test",
"command_topic": "test_light/set",
@@ -2345,7 +2344,7 @@ async def test_on_command_rgbw_template(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
light.DOMAIN: {
"name": "test",
"command_topic": "test_light/set",
@@ -2397,7 +2396,7 @@ async def test_on_command_rgbww_template(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
light.DOMAIN: {
"name": "test",
"command_topic": "tasmota_B94927/cmnd/POWER",
@@ -2509,7 +2508,7 @@ async def test_on_command_white(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
light.DOMAIN: {
"name": "test",
"state_topic": "test_light_rgb/status",
@@ -2664,7 +2663,7 @@ async def test_explicit_color_mode(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
light.DOMAIN: {
"name": "test",
"state_topic": "test_light_rgb/status",
@@ -2752,7 +2751,7 @@ async def test_explicit_color_mode_templated(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
light.DOMAIN: {
"name": "test",
"state_topic": "tasmota_B94927/tele/STATE",
@@ -2825,7 +2824,7 @@ async def test_white_state_update(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
light.DOMAIN: {
"name": "test",
"command_topic": "test_light/set",
@@ -2976,7 +2975,7 @@ async def test_discovery_update_attr(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
light.DOMAIN: [
{
"name": "Test 1",
@@ -3636,7 +3635,7 @@ async def test_entity_debug_info_message(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
light.DOMAIN: {
"name": "test",
"command_topic": "test_max_mireds/set",
@@ -3760,9 +3759,9 @@ async def test_publishing_with_custom_encoding(
domain = light.DOMAIN
config: dict[str, Any] = copy.deepcopy(DEFAULT_CONFIG)
if topic == "effect_command_topic":
config[mqtt.DOMAIN][domain]["effect_list"] = ["random", "color_loop"]
config[DOMAIN][domain]["effect_list"] = ["random", "color_loop"]
elif topic == "white_command_topic":
config[mqtt.DOMAIN][domain]["rgb_command_topic"] = "some-cmd-topic"
config[DOMAIN][domain]["rgb_command_topic"] = "some-cmd-topic"
await help_test_publishing_with_custom_encoding(
hass,
@@ -3847,7 +3846,7 @@ async def test_encoding_subscribable_topics(
init_payload: tuple[str, str] | None,
) -> None:
"""Test handling of incoming encoded payload."""
config: dict[str, Any] = copy.deepcopy(DEFAULT_CONFIG[mqtt.DOMAIN][light.DOMAIN])
config: dict[str, Any] = copy.deepcopy(DEFAULT_CONFIG[DOMAIN][light.DOMAIN])
config[CONF_EFFECT_COMMAND_TOPIC] = "light/CONF_EFFECT_COMMAND_TOPIC"
config[CONF_RGB_COMMAND_TOPIC] = "light/CONF_RGB_COMMAND_TOPIC"
config[CONF_BRIGHTNESS_COMMAND_TOPIC] = "light/CONF_BRIGHTNESS_COMMAND_TOPIC"
@@ -3888,7 +3887,7 @@ async def test_encoding_subscribable_topics_brightness(
init_payload: tuple[str, str] | None,
) -> None:
"""Test handling of incoming encoded payload for a brightness only light."""
config = copy.deepcopy(DEFAULT_CONFIG[mqtt.DOMAIN][light.DOMAIN])
config = copy.deepcopy(DEFAULT_CONFIG[DOMAIN][light.DOMAIN])
config[CONF_BRIGHTNESS_COMMAND_TOPIC] = "light/CONF_BRIGHTNESS_COMMAND_TOPIC"
await help_test_encoding_subscribable_topics(
@@ -3908,7 +3907,7 @@ async def test_encoding_subscribable_topics_brightness(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
light.DOMAIN: {
"name": "test",
"command_topic": "test_light_brightness/set",
@@ -3962,7 +3961,7 @@ async def test_sending_mqtt_brightness_command_with_template(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
light.DOMAIN: {
"name": "test",
"command_topic": "test_light_brightness/set",
@@ -4017,7 +4016,7 @@ async def test_sending_mqtt_effect_command_with_template(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
light.DOMAIN: {
"name": "test",
"command_topic": "test_light_hs/set",
@@ -4065,7 +4064,7 @@ async def test_sending_mqtt_hs_command_with_template(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
light.DOMAIN: {
"name": "test",
"command_topic": "test_light_xy/set",
+40 -39
View File
@@ -88,7 +88,8 @@ from unittest.mock import call, patch
import pytest
from homeassistant.components import light, mqtt
from homeassistant.components import light
from homeassistant.components.mqtt.const import DOMAIN
from homeassistant.components.mqtt.light.schema_basic import (
MQTT_LIGHT_ATTRIBUTES_BLOCKED,
)
@@ -139,7 +140,7 @@ from tests.components.light import common
from tests.typing import MqttMockHAClientGenerator, MqttMockPahoClient
DEFAULT_CONFIG = {
mqtt.DOMAIN: {
DOMAIN: {
light.DOMAIN: {
"schema": "json",
"name": "test",
@@ -150,7 +151,7 @@ DEFAULT_CONFIG = {
COLOR_MODES_CONFIG = {
mqtt.DOMAIN: {
DOMAIN: {
light.DOMAIN: {
"brightness": True,
"effect": True,
@@ -262,7 +263,7 @@ async def test_simple_on_off_light(
@pytest.mark.parametrize(
"hass_config", [{mqtt.DOMAIN: {light.DOMAIN: {"schema": "json", "name": "test"}}}]
"hass_config", [{DOMAIN: {light.DOMAIN: {"schema": "json", "name": "test"}}}]
)
async def test_fail_setup_if_no_command_topic(
mqtt_mock_entry: MqttMockHAClientGenerator,
@@ -391,7 +392,7 @@ async def test_controlling_state_with_unknown_color_mode(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
light.DOMAIN: {
"schema": "json",
"name": "test",
@@ -447,7 +448,7 @@ async def test_no_color_brightness_color_temp_if_no_topics(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
light.DOMAIN: {
"schema": "json",
"name": "test",
@@ -458,7 +459,7 @@ async def test_no_color_brightness_color_temp_if_no_topics(
}
},
{
mqtt.DOMAIN: {
DOMAIN: {
light.DOMAIN: {
"schema": "json",
"name": "test",
@@ -518,7 +519,7 @@ async def test_brightness_only(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
light.DOMAIN: {
"schema": "json",
"name": "test",
@@ -529,7 +530,7 @@ async def test_brightness_only(
}
},
{
mqtt.DOMAIN: {
DOMAIN: {
light.DOMAIN: {
"schema": "json",
"name": "test",
@@ -570,7 +571,7 @@ async def test_single_color_mode_turn_on(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
light.DOMAIN: {
"schema": "json",
"name": "test",
@@ -580,7 +581,7 @@ async def test_single_color_mode_turn_on(
}
},
{
mqtt.DOMAIN: {
DOMAIN: {
light.DOMAIN: {
"schema": "json",
"name": "test",
@@ -627,7 +628,7 @@ async def test_restore_state_with_none_color_mode(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
light.DOMAIN: {
"schema": "json",
"name": "test",
@@ -687,7 +688,7 @@ async def test_color_temp_only(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
light.DOMAIN: {
"schema": "json",
"name": "test",
@@ -778,7 +779,7 @@ async def test_controlling_state_color_temp_kelvin(
[
(
{
mqtt.DOMAIN: {
DOMAIN: {
light.DOMAIN: {
"schema": "json",
"name": "test",
@@ -791,7 +792,7 @@ async def test_controlling_state_color_temp_kelvin(
),
(
{
mqtt.DOMAIN: {
DOMAIN: {
light.DOMAIN: {
"schema": "json",
"name": "test",
@@ -806,7 +807,7 @@ async def test_controlling_state_color_temp_kelvin(
),
(
{
mqtt.DOMAIN: {
DOMAIN: {
light.DOMAIN: {
"schema": "json",
"name": "test",
@@ -821,7 +822,7 @@ async def test_controlling_state_color_temp_kelvin(
),
(
{
mqtt.DOMAIN: {
DOMAIN: {
light.DOMAIN: {
"schema": "json",
"name": "test",
@@ -836,7 +837,7 @@ async def test_controlling_state_color_temp_kelvin(
),
(
{
mqtt.DOMAIN: {
DOMAIN: {
light.DOMAIN: {
"schema": "json",
"name": "test",
@@ -1048,7 +1049,7 @@ async def test_controlling_state_via_topic(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
light.DOMAIN: {
"command_topic": "test_light_rgb/set",
"effect": True,
@@ -1296,7 +1297,7 @@ async def test_sending_mqtt_commands_and_optimistic(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
light.DOMAIN: {
"schema": "json",
"name": "test",
@@ -1361,7 +1362,7 @@ async def test_sending_hs_color(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
light.DOMAIN: {
"schema": "json",
"name": "test",
@@ -1422,7 +1423,7 @@ async def test_sending_rgb_color_no_brightness(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
light.DOMAIN: {
"command_topic": "test_light_rgb/set",
"name": "test",
@@ -1507,7 +1508,7 @@ async def test_sending_rgb_color_no_brightness2(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
light.DOMAIN: {
"schema": "json",
"name": "test",
@@ -1579,7 +1580,7 @@ async def test_sending_rgb_color_with_brightness(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
light.DOMAIN: {
"schema": "json",
"name": "test",
@@ -1653,7 +1654,7 @@ async def test_sending_rgb_color_with_scaled_brightness(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
light.DOMAIN: {
"schema": "json",
"name": "test",
@@ -1710,7 +1711,7 @@ async def test_sending_scaled_white(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
light.DOMAIN: {
"schema": "json",
"name": "test",
@@ -1774,7 +1775,7 @@ async def test_sending_xy_color(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
light.DOMAIN: {
"schema": "json",
"name": "test",
@@ -1848,7 +1849,7 @@ async def test_effect(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
light.DOMAIN: {
"schema": "json",
"name": "test",
@@ -1931,7 +1932,7 @@ async def test_flash_short_and_long(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
light.DOMAIN: {
"schema": "json",
"name": "test",
@@ -1985,7 +1986,7 @@ async def test_transition(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
light.DOMAIN: {
"schema": "json",
"name": "test",
@@ -2048,7 +2049,7 @@ async def test_brightness_scale(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
light.DOMAIN: {
"schema": "json",
"name": "test",
@@ -2246,7 +2247,7 @@ async def test_update_discovery_with_members_without_init(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
light.DOMAIN: {
"schema": "json",
"name": "test",
@@ -2537,7 +2538,7 @@ async def test_discovery_update_attr(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
light.DOMAIN: [
{
"name": "Test 1",
@@ -2713,7 +2714,7 @@ async def test_entity_debug_info_message(
[
(
{
mqtt.DOMAIN: {
DOMAIN: {
light.DOMAIN: {
"schema": "json",
"name": "test",
@@ -2728,7 +2729,7 @@ async def test_entity_debug_info_message(
),
(
{
mqtt.DOMAIN: {
DOMAIN: {
light.DOMAIN: {
"schema": "json",
"name": "test",
@@ -2743,7 +2744,7 @@ async def test_entity_debug_info_message(
),
(
{
mqtt.DOMAIN: {
DOMAIN: {
light.DOMAIN: {
"schema": "json",
"name": "test",
@@ -2758,7 +2759,7 @@ async def test_entity_debug_info_message(
),
(
{
mqtt.DOMAIN: {
DOMAIN: {
light.DOMAIN: {
"schema": "json",
"name": "test",
@@ -2826,7 +2827,7 @@ async def test_publishing_with_custom_encoding(
domain = light.DOMAIN
config: dict[str, Any] = copy.deepcopy(DEFAULT_CONFIG)
if topic == "effect_command_topic":
config[mqtt.DOMAIN][domain]["effect_list"] = ["random", "color_loop"]
config[DOMAIN][domain]["effect_list"] = ["random", "color_loop"]
await help_test_publishing_with_custom_encoding(
hass,
@@ -2878,7 +2879,7 @@ async def test_encoding_subscribable_topics(
init_payload: tuple[str, str] | None,
) -> None:
"""Test handling of incoming encoded payload."""
config: dict[str, Any] = copy.deepcopy(DEFAULT_CONFIG[mqtt.DOMAIN][light.DOMAIN])
config: dict[str, Any] = copy.deepcopy(DEFAULT_CONFIG[DOMAIN][light.DOMAIN])
config["color_mode"] = True
config["supported_color_modes"] = [
"color_temp",
+24 -23
View File
@@ -31,7 +31,8 @@ from unittest.mock import patch
import pytest
from homeassistant.components import light, mqtt
from homeassistant.components import light
from homeassistant.components.mqtt.const import DOMAIN
from homeassistant.components.mqtt.light.schema_basic import (
MQTT_LIGHT_ATTRIBUTES_BLOCKED,
)
@@ -81,7 +82,7 @@ from tests.components.light import common
from tests.typing import MqttMockHAClientGenerator, MqttMockPahoClient
DEFAULT_CONFIG = {
mqtt.DOMAIN: {
DOMAIN: {
light.DOMAIN: {
"schema": "template",
"name": "test",
@@ -96,10 +97,10 @@ DEFAULT_CONFIG = {
@pytest.mark.parametrize(
"hass_config",
[
({mqtt.DOMAIN: {light.DOMAIN: {"schema": "template", "name": "test"}}},),
({DOMAIN: {light.DOMAIN: {"schema": "template", "name": "test"}}},),
(
{
mqtt.DOMAIN: {
DOMAIN: {
light.DOMAIN: {
"schema": "template",
"name": "test",
@@ -110,7 +111,7 @@ DEFAULT_CONFIG = {
),
(
{
mqtt.DOMAIN: {
DOMAIN: {
light.DOMAIN: {
"schema": "template",
"name": "test",
@@ -122,7 +123,7 @@ DEFAULT_CONFIG = {
),
(
{
mqtt.DOMAIN: {
DOMAIN: {
light.DOMAIN: {
"schema": "template",
"name": "test",
@@ -149,7 +150,7 @@ async def test_setup_fails(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
light.DOMAIN: {
"schema": "template",
"name": "test",
@@ -185,7 +186,7 @@ async def test_rgb_light(
[
(
{
mqtt.DOMAIN: {
DOMAIN: {
light.DOMAIN: {
"schema": "template",
"name": "test",
@@ -204,7 +205,7 @@ async def test_rgb_light(
),
(
{
mqtt.DOMAIN: {
DOMAIN: {
light.DOMAIN: {
"schema": "template",
"name": "test",
@@ -254,7 +255,7 @@ async def test_single_color_mode(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
light.DOMAIN: {
"schema": "template",
"name": "test",
@@ -309,7 +310,7 @@ async def test_state_change_via_topic(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
light.DOMAIN: {
"schema": "template",
"name": "test",
@@ -427,7 +428,7 @@ async def test_state_brightness_color_effect_temp_change_via_topic(
[
(
{
mqtt.DOMAIN: {
DOMAIN: {
light.DOMAIN: {
"schema": "template",
"name": "test",
@@ -459,7 +460,7 @@ async def test_state_brightness_color_effect_temp_change_via_topic(
),
(
{
mqtt.DOMAIN: {
DOMAIN: {
light.DOMAIN: {
"schema": "template",
"name": "test",
@@ -626,7 +627,7 @@ async def test_sending_mqtt_commands_and_optimistic(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
light.DOMAIN: {
"schema": "template",
"name": "test",
@@ -765,7 +766,7 @@ async def test_sending_mqtt_commands_non_optimistic_brightness_template(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
light.DOMAIN: {
"schema": "template",
"effect_list": ["rainbow", "colorloop"],
@@ -820,7 +821,7 @@ async def test_effect(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
light.DOMAIN: {
"schema": "template",
"name": "test",
@@ -871,7 +872,7 @@ async def test_flash(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
light.DOMAIN: {
"schema": "template",
"name": "test",
@@ -915,7 +916,7 @@ async def test_transition(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
light.DOMAIN: {
"schema": "template",
"name": "test",
@@ -1113,7 +1114,7 @@ async def test_discovery_update_attr(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
light.DOMAIN: [
{
"name": "Test 1",
@@ -1280,7 +1281,7 @@ async def test_entity_debug_info_message(
) -> None:
"""Test MQTT debug info."""
config = {
mqtt.DOMAIN: {
DOMAIN: {
light.DOMAIN: {
"schema": "template",
"name": "test",
@@ -1304,7 +1305,7 @@ async def test_entity_debug_info_message(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
light.DOMAIN: {
"schema": "template",
"name": "test",
@@ -1368,7 +1369,7 @@ async def test_publishing_with_custom_encoding(
domain = light.DOMAIN
config: dict[str, Any] = copy.deepcopy(DEFAULT_CONFIG)
if topic == "effect_command_topic":
config[mqtt.DOMAIN][domain]["effect_list"] = ["random", "color_loop"]
config[DOMAIN][domain]["effect_list"] = ["random", "color_loop"]
await help_test_publishing_with_custom_encoding(
hass,
@@ -1411,7 +1412,7 @@ async def test_encoding_subscribable_topics(
init_payload,
) -> None:
"""Test handling of incoming encoded payload."""
config = copy.deepcopy(DEFAULT_CONFIG[mqtt.DOMAIN][light.DOMAIN])
config = copy.deepcopy(DEFAULT_CONFIG[DOMAIN][light.DOMAIN])
config["state_template"] = "{{ value }}"
await help_test_encoding_subscribable_topics(
hass,
+12 -11
View File
@@ -5,7 +5,7 @@ from unittest.mock import patch
import pytest
from homeassistant.components import lock, mqtt
from homeassistant.components import lock
from homeassistant.components.lock import (
SERVICE_LOCK,
SERVICE_OPEN,
@@ -13,6 +13,7 @@ from homeassistant.components.lock import (
LockEntityFeature,
LockState,
)
from homeassistant.components.mqtt.const import DOMAIN
from homeassistant.components.mqtt.lock import MQTT_LOCK_ATTRIBUTES_BLOCKED
from homeassistant.const import (
ATTR_ASSUMED_STATE,
@@ -58,11 +59,11 @@ from tests.common import async_fire_mqtt_message
from tests.typing import MqttMockHAClientGenerator, MqttMockPahoClient
DEFAULT_CONFIG = {
mqtt.DOMAIN: {lock.DOMAIN: {"name": "test", "command_topic": "test-topic"}}
DOMAIN: {lock.DOMAIN: {"name": "test", "command_topic": "test-topic"}}
}
CONFIG_WITH_STATES = {
mqtt.DOMAIN: {
DOMAIN: {
lock.DOMAIN: {
"name": "test",
"state_topic": "state-topic",
@@ -324,7 +325,7 @@ async def test_controlling_non_default_state_via_topic_and_json_message(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
lock.DOMAIN: {
"name": "test",
"command_topic": "command-topic",
@@ -376,7 +377,7 @@ async def test_sending_mqtt_commands_and_optimistic(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
lock.DOMAIN: {
"name": "test",
"code_format": "^\\d{4}$",
@@ -437,7 +438,7 @@ async def test_sending_mqtt_commands_with_template(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
lock.DOMAIN: {
"name": "test",
"state_topic": "state-topic",
@@ -491,7 +492,7 @@ async def test_sending_mqtt_commands_and_explicit_optimistic(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
lock.DOMAIN: {
"name": "test",
"command_topic": "command-topic",
@@ -557,7 +558,7 @@ async def test_sending_mqtt_commands_support_open_and_optimistic(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
lock.DOMAIN: {
"name": "test",
"state_topic": "state-topic",
@@ -625,7 +626,7 @@ async def test_sending_mqtt_commands_support_open_and_explicit_optimistic(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
lock.DOMAIN: {
"name": "test",
"command_topic": "command-topic",
@@ -835,7 +836,7 @@ async def test_discovery_update_attr(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
lock.DOMAIN: [
{
"name": "Test 1",
@@ -1053,7 +1054,7 @@ async def test_encoding_subscribable_topics(
hass,
mqtt_mock_entry,
lock.DOMAIN,
DEFAULT_CONFIG[mqtt.DOMAIN][lock.DOMAIN],
DEFAULT_CONFIG[DOMAIN][lock.DOMAIN],
topic,
value,
attribute,
+23 -22
View File
@@ -6,6 +6,7 @@ from unittest.mock import call, patch
import pytest
from homeassistant.components import mqtt, sensor
from homeassistant.components.mqtt.const import DOMAIN
from homeassistant.components.mqtt.sensor import DEFAULT_NAME as DEFAULT_SENSOR_NAME
from homeassistant.config_entries import ConfigSubentryData
from homeassistant.const import (
@@ -36,7 +37,7 @@ from tests.typing import MqttMockHAClientGenerator
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
sensor.DOMAIN: {
"name": "test",
"state_topic": "test-topic",
@@ -104,7 +105,7 @@ async def test_availability_with_shared_state_topic(
[
( # default_entity_name_without_device_name
{
mqtt.DOMAIN: {
DOMAIN: {
sensor.DOMAIN: {
"state_topic": "test-topic",
"unique_id": "veryunique",
@@ -119,7 +120,7 @@ async def test_availability_with_shared_state_topic(
),
( # default_entity_name_with_device_name
{
mqtt.DOMAIN: {
DOMAIN: {
sensor.DOMAIN: {
"state_topic": "test-topic",
"unique_id": "veryunique",
@@ -134,7 +135,7 @@ async def test_availability_with_shared_state_topic(
),
( # name_follows_device_class
{
mqtt.DOMAIN: {
DOMAIN: {
sensor.DOMAIN: {
"state_topic": "test-topic",
"unique_id": "veryunique",
@@ -150,7 +151,7 @@ async def test_availability_with_shared_state_topic(
),
( # name_follows_device_class_without_device_name
{
mqtt.DOMAIN: {
DOMAIN: {
sensor.DOMAIN: {
"state_topic": "test-topic",
"unique_id": "veryunique",
@@ -166,7 +167,7 @@ async def test_availability_with_shared_state_topic(
),
( # name_overrides_device_class
{
mqtt.DOMAIN: {
DOMAIN: {
sensor.DOMAIN: {
"name": "MySensor",
"state_topic": "test-topic",
@@ -183,7 +184,7 @@ async def test_availability_with_shared_state_topic(
),
( # name_set_no_device_name_set
{
mqtt.DOMAIN: {
DOMAIN: {
sensor.DOMAIN: {
"name": "MySensor",
"state_topic": "test-topic",
@@ -200,7 +201,7 @@ async def test_availability_with_shared_state_topic(
),
( # none_entity_name_with_device_name
{
mqtt.DOMAIN: {
DOMAIN: {
sensor.DOMAIN: {
"name": None,
"state_topic": "test-topic",
@@ -217,7 +218,7 @@ async def test_availability_with_shared_state_topic(
),
( # none_entity_name_without_device_name
{
mqtt.DOMAIN: {
DOMAIN: {
sensor.DOMAIN: {
"name": None,
"state_topic": "test-topic",
@@ -234,7 +235,7 @@ async def test_availability_with_shared_state_topic(
),
( # entity_name_and_device_name_the_same
{
mqtt.DOMAIN: {
DOMAIN: {
sensor.DOMAIN: {
"name": "Hello world",
"state_topic": "test-topic",
@@ -254,7 +255,7 @@ async def test_availability_with_shared_state_topic(
),
( # entity_name_startswith_device_name1
{
mqtt.DOMAIN: {
DOMAIN: {
sensor.DOMAIN: {
"name": "World automation",
"state_topic": "test-topic",
@@ -274,7 +275,7 @@ async def test_availability_with_shared_state_topic(
),
( # entity_name_startswith_device_name2
{
mqtt.DOMAIN: {
DOMAIN: {
sensor.DOMAIN: {
"name": "world automation",
"state_topic": "test-topic",
@@ -328,7 +329,7 @@ async def test_default_entity_and_device_name(
await hass.async_block_till_done()
entry = MockConfigEntry(
domain=mqtt.DOMAIN,
domain=DOMAIN,
data={mqtt.CONF_BROKER: "mock-broker", mqtt.CONF_PROTOCOL: "5"},
version=mqtt.CONFIG_ENTRY_VERSION,
minor_version=mqtt.CONFIG_ENTRY_MINOR_VERSION,
@@ -417,7 +418,7 @@ async def test_name_attribute_is_set_or_not(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
sensor.DOMAIN: {
"name": "test",
"state_topic": "state-topic",
@@ -427,7 +428,7 @@ async def test_name_attribute_is_set_or_not(
}
},
{
mqtt.DOMAIN: {
DOMAIN: {
sensor.DOMAIN: {
"name": "test",
"state_topic": "state-topic",
@@ -439,7 +440,7 @@ async def test_name_attribute_is_set_or_not(
}
},
{
mqtt.DOMAIN: {
DOMAIN: {
sensor.DOMAIN: {
"name": "test",
"state_topic": "state-topic",
@@ -473,7 +474,7 @@ async def test_value_template_fails(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
sensor.DOMAIN: {
"name": "test",
"state_topic": "state-topic",
@@ -501,7 +502,7 @@ async def test_registry_enabled_by_default(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
sensor.DOMAIN: {
"name": "test",
"state_topic": "state-topic",
@@ -647,7 +648,7 @@ async def test_loading_subentries(
) -> None:
"""Test loading subentries."""
await mqtt_mock_entry()
entry = hass.config_entries.async_entries(mqtt.DOMAIN)[0]
entry = hass.config_entries.async_entries(DOMAIN)[0]
subentry_id = next(iter(entry.subentries))
# Each subentry has one device
device = device_registry.async_get_device({("mqtt", subentry_id)})
@@ -658,7 +659,7 @@ async def test_loading_subentries(
platform = component["platform"]
entity_id = f"{platform}.{slugify(device.name)}_{slugify(component['name'])}"
entity_entry_entity_id = entity_registry.async_get_entity_id(
platform, mqtt.DOMAIN, f"{subentry_id}_{object_id}"
platform, DOMAIN, f"{subentry_id}_{object_id}"
)
assert entity_entry_entity_id == entity_id
state = hass.states.get(entity_id)
@@ -699,7 +700,7 @@ async def test_loading_subentry_with_bad_component_schema(
) -> None:
"""Test loading subentries."""
await mqtt_mock_entry()
entry = hass.config_entries.async_entries(mqtt.DOMAIN)[0]
entry = hass.config_entries.async_entries(DOMAIN)[0]
subentry_id = next(iter(entry.subentries))
# Each subentry has one device
device = device_registry.async_get_device({("mqtt", subentry_id)})
@@ -729,7 +730,7 @@ async def test_qos_on_mqtt_device_from_subentry(
) -> None:
"""Test QoS is set correctly on entities from MQTT device."""
mqtt_mock = await mqtt_mock_entry()
entry = hass.config_entries.async_entries(mqtt.DOMAIN)[0]
entry = hass.config_entries.async_entries(DOMAIN)[0]
subentry_id = next(iter(entry.subentries))
# Each subentry has one device
device = device_registry.async_get_device({("mqtt", subentry_id)})
+8 -7
View File
@@ -6,7 +6,8 @@ from unittest.mock import patch
import pytest
from homeassistant.components import mqtt, notify
from homeassistant.components import notify
from homeassistant.components.mqtt.const import DOMAIN
from homeassistant.components.notify import ATTR_MESSAGE
from homeassistant.const import ATTR_ENTITY_ID, ATTR_FRIENDLY_NAME, STATE_UNKNOWN
from homeassistant.core import HomeAssistant
@@ -41,7 +42,7 @@ from .common import (
from tests.typing import MqttMockHAClientGenerator, MqttMockPahoClient
DEFAULT_CONFIG = {
mqtt.DOMAIN: {notify.DOMAIN: {"name": "test", "command_topic": "test-topic"}}
DOMAIN: {notify.DOMAIN: {"name": "test", "command_topic": "test-topic"}}
}
@@ -50,7 +51,7 @@ DEFAULT_CONFIG = {
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
notify.DOMAIN: {
"command_topic": "command-topic",
"name": "test",
@@ -90,7 +91,7 @@ async def test_sending_mqtt_commands(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
notify.DOMAIN: {
"command_topic": "command-topic",
"command_template": '{ "{{ entity_id }}": "{{ value }}" }',
@@ -231,7 +232,7 @@ async def test_discovery_update_attr(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
notify.DOMAIN: [
{
"name": "Test 1",
@@ -267,8 +268,8 @@ async def test_discovery_update_notify(
hass: HomeAssistant, mqtt_mock_entry: MqttMockHAClientGenerator
) -> None:
"""Test update of discovered notify."""
config1 = copy.deepcopy(DEFAULT_CONFIG[mqtt.DOMAIN][notify.DOMAIN])
config2 = copy.deepcopy(DEFAULT_CONFIG[mqtt.DOMAIN][notify.DOMAIN])
config1 = copy.deepcopy(DEFAULT_CONFIG[DOMAIN][notify.DOMAIN])
config2 = copy.deepcopy(DEFAULT_CONFIG[DOMAIN][notify.DOMAIN])
config1["name"] = "Beer"
config2["name"] = "Milk"
+28 -27
View File
@@ -6,7 +6,8 @@ from unittest.mock import patch
import pytest
from homeassistant.components import mqtt, number
from homeassistant.components import number
from homeassistant.components.mqtt.const import DOMAIN
from homeassistant.components.mqtt.number import (
CONF_MAX,
CONF_MIN,
@@ -69,7 +70,7 @@ from tests.common import async_fire_mqtt_message, mock_restore_cache_with_extra_
from tests.typing import MqttMockHAClientGenerator, MqttMockPahoClient
DEFAULT_CONFIG = {
mqtt.DOMAIN: {number.DOMAIN: {"name": "test", "command_topic": "test-topic"}}
DOMAIN: {number.DOMAIN: {"name": "test", "command_topic": "test-topic"}}
}
@@ -78,7 +79,7 @@ DEFAULT_CONFIG = {
[
(
{
mqtt.DOMAIN: {
DOMAIN: {
number.DOMAIN: {
"state_topic": "test/state_number",
"command_topic": "test/cmd_number",
@@ -95,7 +96,7 @@ DEFAULT_CONFIG = {
),
(
{
mqtt.DOMAIN: {
DOMAIN: {
number.DOMAIN: {
"state_topic": "test/state_number",
"command_topic": "test/cmd_number",
@@ -112,7 +113,7 @@ DEFAULT_CONFIG = {
),
(
{
mqtt.DOMAIN: {
DOMAIN: {
number.DOMAIN: {
"state_topic": "test/state_number",
"command_topic": "test/cmd_number",
@@ -163,7 +164,7 @@ async def test_run_number_setup(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
number.DOMAIN: {
"state_topic": "test/state_number",
"command_topic": "test/cmd_number",
@@ -260,7 +261,7 @@ async def test_native_value_validation(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
number.DOMAIN: {
"name": "test",
"command_topic": "test-topic-cmd",
@@ -316,7 +317,7 @@ async def test_equivalent_unit_of_measurement(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
number.DOMAIN: {
"state_topic": "test/state_number",
"command_topic": "test/cmd_number",
@@ -368,7 +369,7 @@ async def test_value_template(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
number.DOMAIN: {
"command_topic": "test/number",
"device_class": "temperature",
@@ -406,7 +407,7 @@ async def test_restore_native_value(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
number.DOMAIN: {
"command_topic": "test/number",
"name": "Test Number",
@@ -489,7 +490,7 @@ async def test_run_number_service_optimistic(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
number.DOMAIN: {
"command_topic": "test/number",
"name": "Test Number",
@@ -572,7 +573,7 @@ async def test_run_number_service_optimistic_with_command_template(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
number.DOMAIN: {
"command_topic": "test/number/set",
"state_topic": "test/number",
@@ -612,7 +613,7 @@ async def test_run_number_service(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
number.DOMAIN: {
"command_topic": "test/number/set",
"state_topic": "test/number",
@@ -753,7 +754,7 @@ async def test_discovery_update_attr(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
number.DOMAIN: [
{
"name": "Test 1",
@@ -783,7 +784,7 @@ async def test_discovery_removal_number(
hass: HomeAssistant, mqtt_mock_entry: MqttMockHAClientGenerator
) -> None:
"""Test removal of discovered number."""
data = json.dumps(DEFAULT_CONFIG[mqtt.DOMAIN][number.DOMAIN])
data = json.dumps(DEFAULT_CONFIG[DOMAIN][number.DOMAIN])
await help_test_discovery_removal(hass, mqtt_mock_entry, number.DOMAIN, data)
@@ -910,7 +911,7 @@ async def test_entity_debug_info_message(
[
(
{
mqtt.DOMAIN: {
DOMAIN: {
number.DOMAIN: {
"state_topic": "test/state_number",
"command_topic": "test/cmd_number",
@@ -927,7 +928,7 @@ async def test_entity_debug_info_message(
),
(
{
mqtt.DOMAIN: {
DOMAIN: {
number.DOMAIN: {
"state_topic": "test/state_number",
"command_topic": "test/cmd_number",
@@ -963,7 +964,7 @@ async def test_min_max_step_attributes(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
number.DOMAIN: {
"state_topic": "test/state_number",
"command_topic": "test/cmd_number",
@@ -988,7 +989,7 @@ async def test_invalid_min_max_attributes(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
number.DOMAIN: {
"state_topic": "test/state_number",
"command_topic": "test/cmd_number",
@@ -1013,7 +1014,7 @@ async def test_default_mode(
[
(
{
mqtt.DOMAIN: {
DOMAIN: {
number.DOMAIN: {
"state_topic": "test/state_number",
"command_topic": "test/cmd_number",
@@ -1026,7 +1027,7 @@ async def test_default_mode(
),
(
{
mqtt.DOMAIN: {
DOMAIN: {
number.DOMAIN: {
"state_topic": "test/state_number",
"command_topic": "test/cmd_number",
@@ -1039,7 +1040,7 @@ async def test_default_mode(
),
(
{
mqtt.DOMAIN: {
DOMAIN: {
number.DOMAIN: {
"state_topic": "test/state_number",
"command_topic": "test/cmd_number",
@@ -1069,7 +1070,7 @@ async def test_mode(
[
(
{
mqtt.DOMAIN: {
DOMAIN: {
number.DOMAIN: {
"state_topic": "test/state_number",
"command_topic": "test/cmd_number",
@@ -1082,7 +1083,7 @@ async def test_mode(
),
(
{
mqtt.DOMAIN: {
DOMAIN: {
number.DOMAIN: {
"state_topic": "test/state_number",
"command_topic": "test/cmd_number",
@@ -1110,7 +1111,7 @@ async def test_invalid_mode(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
number.DOMAIN: {
"state_topic": "test/state_number",
"command_topic": "test/cmd_number",
@@ -1141,7 +1142,7 @@ async def test_mqtt_payload_not_a_number_warning(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
number.DOMAIN: {
"state_topic": "test/state_number",
"command_topic": "test/cmd_number",
@@ -1242,7 +1243,7 @@ async def test_encoding_subscribable_topics(
hass,
mqtt_mock_entry,
number.DOMAIN,
DEFAULT_CONFIG[mqtt.DOMAIN][number.DOMAIN],
DEFAULT_CONFIG[DOMAIN][number.DOMAIN],
topic,
value,
attribute,
+9 -9
View File
@@ -7,7 +7,7 @@ from unittest.mock import patch
import pytest
from homeassistant.components import mqtt
from homeassistant.components.mqtt.const import DOMAIN
from homeassistant.config_entries import ConfigSubentry, ConfigSubentryData
from homeassistant.const import SERVICE_RELOAD
from homeassistant.core import HomeAssistant
@@ -34,7 +34,7 @@ async def help_setup_yaml(hass: HomeAssistant, config: dict[str, str]) -> None:
return_value=parse_yaml(config["yaml"]),
):
await hass.services.async_call(
mqtt.DOMAIN,
DOMAIN,
SERVICE_RELOAD,
{},
blocking=True,
@@ -80,7 +80,7 @@ async def test_subentry_reconfigure_export_settings(
) -> None:
"""Test the subentry ConfigFlow YAML export with migration to YAML."""
await mqtt_mock_entry()
config_entry: MockConfigEntry = hass.config_entries.async_entries(mqtt.DOMAIN)[0]
config_entry: MockConfigEntry = hass.config_entries.async_entries(DOMAIN)[0]
subentry_id: str
subentry: ConfigSubentry
subentry_id, subentry = next(iter(config_entry.subentries.items()))
@@ -89,7 +89,7 @@ async def test_subentry_reconfigure_export_settings(
assert result["step_id"] == "summary_menu"
# assert we have a device for the subentry
device = device_registry.async_get_device(identifiers={(mqtt.DOMAIN, subentry_id)})
device = device_registry.async_get_device(identifiers={(DOMAIN, subentry_id)})
assert device.config_entries_subentries[config_entry.entry_id] == {subentry_id}
assert device is not None
@@ -135,7 +135,7 @@ async def test_subentry_reconfigure_export_settings(
await setup_helper(hass, suggested_values_from_schema)
# Assert the subentry device was not effected by the exported configs
device = device_registry.async_get_device(identifiers={(mqtt.DOMAIN, subentry_id)})
device = device_registry.async_get_device(identifiers={(DOMAIN, subentry_id)})
assert device.config_entries_subentries[config_entry.entry_id] == {subentry_id}
assert device is not None
@@ -145,13 +145,13 @@ async def test_subentry_reconfigure_export_settings(
assert len(events) == 1
issue_id = events[0].data["issue_id"]
issue_registry = ir.async_get(hass)
repair_issue = issue_registry.async_get_issue(mqtt.DOMAIN, issue_id)
repair_issue = issue_registry.async_get_issue(DOMAIN, issue_id)
assert repair_issue.translation_key == translation_key
await async_process_repairs_platforms(hass)
client = await hass_client()
data = await start_repair_fix_flow(client, mqtt.DOMAIN, issue_id)
data = await start_repair_fix_flow(client, DOMAIN, issue_id)
flow_id = data["flow_id"]
assert data["description_placeholders"] == {"name": "Milk notifier"}
@@ -161,7 +161,7 @@ async def test_subentry_reconfigure_export_settings(
assert data["type"] == "create_entry"
# Assert the subentry is removed and no other entity has linked the device
device = device_registry.async_get_device(identifiers={(mqtt.DOMAIN, subentry_id)})
device = device_registry.async_get_device(identifiers={(DOMAIN, subentry_id)})
assert device is None
await hass.async_block_till_done(wait_background_tasks=True)
@@ -174,6 +174,6 @@ async def test_subentry_reconfigure_export_settings(
# The MQTT device was now set up from the new source
await hass.async_block_till_done(wait_background_tasks=True)
device = device_registry.async_get_device(identifiers={(mqtt.DOMAIN, subentry_id)})
device = device_registry.async_get_device(identifiers={(DOMAIN, subentry_id)})
assert device.config_entries_subentries[config_entry.entry_id] == {None}
assert device is not None
+9 -8
View File
@@ -6,7 +6,8 @@ from unittest.mock import patch
import pytest
from homeassistant.components import mqtt, scene
from homeassistant.components import scene
from homeassistant.components.mqtt.const import DOMAIN
from homeassistant.const import ATTR_ENTITY_ID, SERVICE_TURN_ON, STATE_UNKNOWN
from homeassistant.core import HomeAssistant, State
@@ -41,7 +42,7 @@ from tests.common import mock_restore_cache
from tests.typing import MqttMockHAClientGenerator, MqttMockPahoClient
DEFAULT_CONFIG = {
mqtt.DOMAIN: {
DOMAIN: {
scene.DOMAIN: {
"name": "test",
"command_topic": "test-topic",
@@ -55,7 +56,7 @@ DEFAULT_CONFIG = {
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
scene.DOMAIN: {
"name": "test",
"command_topic": "command-topic",
@@ -110,7 +111,7 @@ async def test_default_availability_payload(
) -> None:
"""Test availability by default payload with defined topic."""
config = {
mqtt.DOMAIN: {
DOMAIN: {
scene.DOMAIN: {
"name": "test",
"command_topic": "command-topic",
@@ -134,7 +135,7 @@ async def test_custom_availability_payload(
) -> None:
"""Test availability by custom payload with defined topic."""
config = {
mqtt.DOMAIN: {
DOMAIN: {
scene.DOMAIN: {
"name": "test",
"command_topic": "command-topic",
@@ -158,7 +159,7 @@ async def test_custom_availability_payload(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
scene.DOMAIN: [
{
"name": "Test 1",
@@ -194,8 +195,8 @@ async def test_discovery_update_payload(
hass: HomeAssistant, mqtt_mock_entry: MqttMockHAClientGenerator
) -> None:
"""Test update of discovered scene."""
config1 = copy.deepcopy(DEFAULT_CONFIG[mqtt.DOMAIN][scene.DOMAIN])
config2 = copy.deepcopy(DEFAULT_CONFIG[mqtt.DOMAIN][scene.DOMAIN])
config1 = copy.deepcopy(DEFAULT_CONFIG[DOMAIN][scene.DOMAIN])
config2 = copy.deepcopy(DEFAULT_CONFIG[DOMAIN][scene.DOMAIN])
config1["name"] = "Beer"
config2["name"] = "Milk"
config1["payload_on"] = "ON"
+15 -14
View File
@@ -9,7 +9,8 @@ from unittest.mock import patch
import pytest
from homeassistant.components import mqtt, select
from homeassistant.components import select
from homeassistant.components.mqtt.const import DOMAIN
from homeassistant.components.mqtt.select import MQTT_SELECT_ATTRIBUTES_BLOCKED
from homeassistant.components.select import (
ATTR_OPTION,
@@ -57,7 +58,7 @@ from tests.common import async_fire_mqtt_message, mock_restore_cache
from tests.typing import MqttMockHAClientGenerator, MqttMockPahoClient
DEFAULT_CONFIG = {
mqtt.DOMAIN: {
DOMAIN: {
select.DOMAIN: {
"name": "test",
"command_topic": "test-topic",
@@ -70,7 +71,7 @@ DEFAULT_CONFIG = {
def _test_run_select_setup_params(topic: str) -> Generator[tuple[ConfigType, str]]:
yield (
{
mqtt.DOMAIN: {
DOMAIN: {
select.DOMAIN: {
"state_topic": topic,
"command_topic": "test/select_cmd",
@@ -127,7 +128,7 @@ async def test_run_select_setup(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
select.DOMAIN: {
"state_topic": "test/select_stat",
"command_topic": "test/select_cmd",
@@ -171,7 +172,7 @@ async def test_value_template(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
select.DOMAIN: {
"command_topic": "test/select_cmd",
"name": "Test Select",
@@ -213,7 +214,7 @@ async def test_run_select_service_optimistic(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
select.DOMAIN: {
"command_topic": "test/select_cmd",
"name": "Test Select",
@@ -256,7 +257,7 @@ async def test_run_select_service_optimistic_with_command_template(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
select.DOMAIN: {
"command_topic": "test/select/set",
"state_topic": "test/select",
@@ -297,7 +298,7 @@ async def test_run_select_service(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
select.DOMAIN: {
"command_topic": "test/select/set",
"state_topic": "test/select",
@@ -441,7 +442,7 @@ async def test_discovery_update_attr(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
select.DOMAIN: [
{
"name": "Test 1",
@@ -473,7 +474,7 @@ async def test_discovery_removal_select(
hass: HomeAssistant, mqtt_mock_entry: MqttMockHAClientGenerator
) -> None:
"""Test removal of discovered select."""
data = json.dumps(DEFAULT_CONFIG[mqtt.DOMAIN][select.DOMAIN])
data = json.dumps(DEFAULT_CONFIG[DOMAIN][select.DOMAIN])
await help_test_discovery_removal(hass, mqtt_mock_entry, select.DOMAIN, data)
@@ -605,7 +606,7 @@ def _test_options_attributes_options_config(
for option in request:
yield (
{
mqtt.DOMAIN: {
DOMAIN: {
select.DOMAIN: {
"command_topic": "test/select/set",
"state_topic": "test/select",
@@ -636,7 +637,7 @@ async def test_options_attributes(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
select.DOMAIN: {
"state_topic": "test/select_stat",
"command_topic": "test/select_cmd",
@@ -690,7 +691,7 @@ async def test_publishing_with_custom_encoding(
"""Test publishing MQTT payload with different encoding."""
domain = select.DOMAIN
config = copy.deepcopy(DEFAULT_CONFIG)
config[mqtt.DOMAIN][domain]["options"] = ["milk", "beer"]
config[DOMAIN][domain]["options"] = ["milk", "beer"]
await help_test_publishing_with_custom_encoding(
hass,
@@ -731,7 +732,7 @@ async def test_encoding_subscribable_topics(
attribute_value: Any,
) -> None:
"""Test handling of incoming encoded payload."""
config = copy.deepcopy(DEFAULT_CONFIG[mqtt.DOMAIN][select.DOMAIN])
config = copy.deepcopy(DEFAULT_CONFIG[DOMAIN][select.DOMAIN])
config["options"] = ["milk", "beer"]
await help_test_encoding_subscribable_topics(
hass,
+37 -36
View File
@@ -13,7 +13,8 @@ from freezegun import freeze_time
from freezegun.api import FrozenDateTimeFactory
import pytest
from homeassistant.components import mqtt, sensor
from homeassistant.components import sensor
from homeassistant.components.mqtt.const import DOMAIN
from homeassistant.components.mqtt.sensor import MQTT_SENSOR_ATTRIBUTES_BLOCKED
from homeassistant.const import (
ATTR_UNIT_OF_MEASUREMENT,
@@ -84,7 +85,7 @@ from tests.common import (
from tests.typing import MqttMockHAClientGenerator, MqttMockPahoClient
DEFAULT_CONFIG = {
mqtt.DOMAIN: {sensor.DOMAIN: {"name": "test", "state_topic": "test-topic"}}
DOMAIN: {sensor.DOMAIN: {"name": "test", "state_topic": "test-topic"}}
}
@@ -92,7 +93,7 @@ DEFAULT_CONFIG = {
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
sensor.DOMAIN: {
"name": "test",
"state_topic": "test-topic",
@@ -122,7 +123,7 @@ async def test_setting_sensor_value_via_mqtt_message(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
sensor.DOMAIN: {
"name": "test",
"state_topic": "test-topic",
@@ -164,7 +165,7 @@ async def test_setting_enum_sensor_value_via_mqtt_message(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
sensor.DOMAIN: {
"name": "test",
"state_topic": "test-topic",
@@ -200,7 +201,7 @@ async def test_handling_undecoded_sensor_value(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
sensor.DOMAIN: {
"name": "test",
"state_topic": "test-topic",
@@ -363,7 +364,7 @@ async def test_setting_sensor_native_value_handling_via_mqtt_message(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
sensor.DOMAIN: {
"name": "test",
"state_topic": "test-topic",
@@ -420,7 +421,7 @@ async def test_setting_numeric_sensor_native_value_handling_via_mqtt_message(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
sensor.DOMAIN: {
"name": "test",
"state_topic": "test-topic",
@@ -454,7 +455,7 @@ async def test_setting_sensor_value_expires_availability_topic(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
sensor.DOMAIN: {
"name": "test",
"state_topic": "test-topic",
@@ -550,7 +551,7 @@ async def expires_helper(hass: HomeAssistant) -> None:
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
sensor.DOMAIN: {
"name": "test",
"state_topic": "test-topic",
@@ -582,7 +583,7 @@ async def test_setting_sensor_value_via_mqtt_json_message(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
sensor.DOMAIN: {
"name": "test",
"state_topic": "test-topic",
@@ -617,7 +618,7 @@ async def test_setting_sensor_value_via_mqtt_json_message_and_default_current_st
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
sensor.DOMAIN: {
"name": "test",
"state_class": "total",
@@ -667,7 +668,7 @@ async def test_setting_sensor_last_reset_via_mqtt_json_message(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
sensor.DOMAIN: {
"name": "test",
"state_class": "total",
@@ -705,7 +706,7 @@ async def test_setting_sensor_last_reset_via_mqtt_json_message_2(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
sensor.DOMAIN: {
"name": "test",
"state_topic": "test-topic",
@@ -742,7 +743,7 @@ async def test_force_update_disabled(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
sensor.DOMAIN: {
"name": "test",
"state_topic": "test-topic",
@@ -865,7 +866,7 @@ async def test_discovery_update_availability(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
sensor.DOMAIN: {
"name": "test",
"state_topic": "test-topic",
@@ -887,7 +888,7 @@ async def test_invalid_device_class(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
sensor.DOMAIN: {
"name": "test",
"state_topic": "test-topic",
@@ -912,7 +913,7 @@ async def test_invalid_unit_of_measurement(
)
# A repair issue was logged for the failing YAML config
assert len(events) == 1
assert events[0].data["domain"] == mqtt.DOMAIN
assert events[0].data["domain"] == DOMAIN
# Assert the sensor is not created
state = hass.states.get("sensor.test")
assert state is None
@@ -923,7 +924,7 @@ async def test_invalid_unit_of_measurement(
[
pytest.param(
{
mqtt.DOMAIN: {
DOMAIN: {
sensor.DOMAIN: {
"name": "test",
"state_topic": "test-topic",
@@ -939,7 +940,7 @@ async def test_invalid_unit_of_measurement(
),
pytest.param(
{
mqtt.DOMAIN: {
DOMAIN: {
sensor.DOMAIN: {
"name": "test",
"state_topic": "test-topic",
@@ -955,7 +956,7 @@ async def test_invalid_unit_of_measurement(
),
pytest.param(
{
mqtt.DOMAIN: {
DOMAIN: {
sensor.DOMAIN: {
"name": "test",
"state_topic": "test-topic",
@@ -971,7 +972,7 @@ async def test_invalid_unit_of_measurement(
),
pytest.param(
{
mqtt.DOMAIN: {
DOMAIN: {
sensor.DOMAIN: {
"name": "test",
"state_topic": "test-topic",
@@ -987,7 +988,7 @@ async def test_invalid_unit_of_measurement(
),
pytest.param(
{
mqtt.DOMAIN: {
DOMAIN: {
sensor.DOMAIN: {
"name": "test",
"state_topic": "test-topic",
@@ -1003,7 +1004,7 @@ async def test_invalid_unit_of_measurement(
),
pytest.param(
{
mqtt.DOMAIN: {
DOMAIN: {
sensor.DOMAIN: {
"name": "test",
"state_topic": "test-topic",
@@ -1061,7 +1062,7 @@ async def test_device_class_with_equivalent_unit_of_measurement_received(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
sensor.DOMAIN: {
"name": "test",
"state_topic": "test-topic",
@@ -1115,7 +1116,7 @@ async def test_equivalent_unit_of_measurement_received_without_device_class(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
sensor.DOMAIN: [
{
"name": "Test 1",
@@ -1191,7 +1192,7 @@ async def test_valid_device_class_and_uom(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
sensor.DOMAIN: {
"name": "test",
"state_topic": "test-topic",
@@ -1213,7 +1214,7 @@ async def test_invalid_state_class(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
sensor.DOMAIN: {
"name": "test",
"state_topic": "test-topic",
@@ -1240,7 +1241,7 @@ async def test_invalid_state_class_with_unit_of_measurement(
[
(
{
mqtt.DOMAIN: {
DOMAIN: {
sensor.DOMAIN: {
"name": "test",
"state_topic": "test-topic",
@@ -1254,7 +1255,7 @@ async def test_invalid_state_class_with_unit_of_measurement(
),
(
{
mqtt.DOMAIN: {
DOMAIN: {
sensor.DOMAIN: {
"name": "test",
"state_topic": "test-topic",
@@ -1268,7 +1269,7 @@ async def test_invalid_state_class_with_unit_of_measurement(
),
(
{
mqtt.DOMAIN: {
DOMAIN: {
sensor.DOMAIN: {
"name": "test",
"state_topic": "test-topic",
@@ -1294,7 +1295,7 @@ async def test_invalid_options_config(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
sensor.DOMAIN: [
{
"name": "Test 1",
@@ -1402,7 +1403,7 @@ async def test_discovery_update_attr(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
sensor.DOMAIN: [
{
"name": "Test 1",
@@ -1678,7 +1679,7 @@ async def test_entity_category(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
sensor.DOMAIN: {
"name": "test",
"state_topic": "test-topic",
@@ -1838,7 +1839,7 @@ async def test_encoding_subscribable_topics(
hass,
mqtt_mock_entry,
sensor.DOMAIN,
DEFAULT_CONFIG[mqtt.DOMAIN][sensor.DOMAIN],
DEFAULT_CONFIG[DOMAIN][sensor.DOMAIN],
topic,
value,
attribute,
@@ -2023,7 +2024,7 @@ async def test_value_incorrect_state_class_config(
)
caplog.clear()
config_payload = hass_config[mqtt.DOMAIN][sensor.DOMAIN][0]
config_payload = hass_config[DOMAIN][sensor.DOMAIN][0]
async_fire_mqtt_message(
hass, "homeassistant/sensor/bla/config", json.dumps(config_payload)
)
+19 -18
View File
@@ -6,7 +6,8 @@ from unittest.mock import patch
import pytest
from homeassistant.components import mqtt, siren
from homeassistant.components import siren
from homeassistant.components.mqtt.const import DOMAIN
from homeassistant.components.siren import ATTR_VOLUME_LEVEL
from homeassistant.const import (
ATTR_ASSUMED_STATE,
@@ -55,7 +56,7 @@ from tests.common import async_fire_mqtt_message
from tests.typing import MqttMockHAClientGenerator, MqttMockPahoClient
DEFAULT_CONFIG = {
mqtt.DOMAIN: {siren.DOMAIN: {"name": "test", "command_topic": "test-topic"}}
DOMAIN: {siren.DOMAIN: {"name": "test", "command_topic": "test-topic"}}
}
@@ -82,7 +83,7 @@ async def async_turn_off(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
siren.DOMAIN: {
"name": "test",
"state_topic": "state-topic",
@@ -119,7 +120,7 @@ async def test_controlling_state_via_topic(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
siren.DOMAIN: {
"name": "test",
"command_topic": "command-topic",
@@ -164,7 +165,7 @@ async def test_sending_mqtt_commands_and_optimistic(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
siren.DOMAIN: {
"name": "test",
"state_topic": "state-topic",
@@ -205,7 +206,7 @@ async def test_controlling_state_via_topic_and_json_message(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
siren.DOMAIN: {
"name": "test",
"state_topic": "state-topic",
@@ -292,7 +293,7 @@ async def test_controlling_state_and_attributes_with_json_message_without_templa
help_custom_config(
siren.DOMAIN,
{
mqtt.DOMAIN: {
DOMAIN: {
siren.DOMAIN: {
"command_topic": "command-topic",
}
@@ -387,7 +388,7 @@ async def test_filtering_not_supported_attributes_optimistic(
help_custom_config(
siren.DOMAIN,
{
mqtt.DOMAIN: {
DOMAIN: {
siren.DOMAIN: {
"command_topic": "command-topic",
}
@@ -495,7 +496,7 @@ async def test_default_availability_payload(
) -> None:
"""Test availability by default payload with defined topic."""
config = {
mqtt.DOMAIN: {
DOMAIN: {
siren.DOMAIN: {
"name": "test",
"state_topic": "state-topic",
@@ -521,7 +522,7 @@ async def test_custom_availability_payload(
) -> None:
"""Test availability by custom payload with defined topic."""
config = {
mqtt.DOMAIN: {
DOMAIN: {
siren.DOMAIN: {
"name": "test",
"state_topic": "state-topic",
@@ -547,7 +548,7 @@ async def test_custom_availability_payload(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
siren.DOMAIN: {
"name": "test",
"state_topic": "state-topic",
@@ -644,7 +645,7 @@ async def test_discovery_update_attr(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
siren.DOMAIN: [
{
"name": "Test 1",
@@ -686,8 +687,8 @@ async def test_discovery_update_siren_topic_template(
hass: HomeAssistant, mqtt_mock_entry: MqttMockHAClientGenerator
) -> None:
"""Test update of discovered siren."""
config1 = copy.deepcopy(DEFAULT_CONFIG[mqtt.DOMAIN][siren.DOMAIN])
config2 = copy.deepcopy(DEFAULT_CONFIG[mqtt.DOMAIN][siren.DOMAIN])
config1 = copy.deepcopy(DEFAULT_CONFIG[DOMAIN][siren.DOMAIN])
config2 = copy.deepcopy(DEFAULT_CONFIG[DOMAIN][siren.DOMAIN])
config1["name"] = "Beer"
config2["name"] = "Milk"
config1["state_topic"] = "siren/state1"
@@ -722,8 +723,8 @@ async def test_discovery_update_siren_template(
hass: HomeAssistant, mqtt_mock_entry: MqttMockHAClientGenerator
) -> None:
"""Test update of discovered siren."""
config1 = copy.deepcopy(DEFAULT_CONFIG[mqtt.DOMAIN][siren.DOMAIN])
config2 = copy.deepcopy(DEFAULT_CONFIG[mqtt.DOMAIN][siren.DOMAIN])
config1 = copy.deepcopy(DEFAULT_CONFIG[DOMAIN][siren.DOMAIN])
config2 = copy.deepcopy(DEFAULT_CONFIG[DOMAIN][siren.DOMAIN])
config1["name"] = "Beer"
config2["name"] = "Milk"
config1["state_topic"] = "siren/state1"
@@ -987,7 +988,7 @@ async def test_publishing_with_custom_encoding(
"""Test publishing MQTT payload with command templates and different encoding."""
domain = siren.DOMAIN
config: dict[str, Any] = copy.deepcopy(DEFAULT_CONFIG)
config[mqtt.DOMAIN][domain][siren.ATTR_AVAILABLE_TONES] = ["siren", "xylophone"]
config[DOMAIN][domain][siren.ATTR_AVAILABLE_TONES] = ["siren", "xylophone"]
await help_test_publishing_with_custom_encoding(
hass,
@@ -1029,7 +1030,7 @@ async def test_encoding_subscribable_topics(
hass,
mqtt_mock_entry,
siren.DOMAIN,
DEFAULT_CONFIG[mqtt.DOMAIN][siren.DOMAIN],
DEFAULT_CONFIG[DOMAIN][siren.DOMAIN],
topic,
value,
attribute,
+18 -17
View File
@@ -6,7 +6,8 @@ from unittest.mock import patch
import pytest
from homeassistant.components import mqtt, switch
from homeassistant.components import switch
from homeassistant.components.mqtt.const import DOMAIN
from homeassistant.const import (
ATTR_ASSUMED_STATE,
ATTR_DEVICE_CLASS,
@@ -52,7 +53,7 @@ from tests.components.switch import common
from tests.typing import MqttMockHAClientGenerator, MqttMockPahoClient
DEFAULT_CONFIG = {
mqtt.DOMAIN: {switch.DOMAIN: {"name": "test", "command_topic": "test-topic"}}
DOMAIN: {switch.DOMAIN: {"name": "test", "command_topic": "test-topic"}}
}
@@ -61,7 +62,7 @@ DEFAULT_CONFIG = {
[
(
{
mqtt.DOMAIN: {
DOMAIN: {
switch.DOMAIN: {
"name": "test",
"state_topic": "state-topic",
@@ -76,7 +77,7 @@ DEFAULT_CONFIG = {
),
(
{
mqtt.DOMAIN: {
DOMAIN: {
switch.DOMAIN: {
"name": "test",
"state_topic": "state-topic",
@@ -124,7 +125,7 @@ async def test_controlling_state_via_topic(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
switch.DOMAIN: {
"name": "test",
"command_topic": "command-topic",
@@ -171,7 +172,7 @@ async def test_sending_mqtt_commands_and_optimistic(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
switch.DOMAIN: {
"name": "test",
"command_topic": "command-topic",
@@ -195,7 +196,7 @@ async def test_sending_inital_state_and_optimistic(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
switch.DOMAIN: {
"name": "test",
"command_topic": "command-topic",
@@ -239,7 +240,7 @@ async def test_sending_mqtt_commands_with_command_template(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
switch.DOMAIN: {
"name": "test",
"state_topic": "state-topic",
@@ -302,7 +303,7 @@ async def test_default_availability_payload(
) -> None:
"""Test availability by default payload with defined topic."""
config = {
mqtt.DOMAIN: {
DOMAIN: {
switch.DOMAIN: {
"name": "test",
"state_topic": "state-topic",
@@ -328,7 +329,7 @@ async def test_custom_availability_payload(
) -> None:
"""Test availability by custom payload with defined topic."""
config = {
mqtt.DOMAIN: {
DOMAIN: {
switch.DOMAIN: {
"name": "test",
"state_topic": "state-topic",
@@ -354,7 +355,7 @@ async def test_custom_availability_payload(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
switch.DOMAIN: {
"name": "test",
"state_topic": "state-topic",
@@ -451,7 +452,7 @@ async def test_discovery_update_attr(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
switch.DOMAIN: [
{
"name": "Test 1",
@@ -493,8 +494,8 @@ async def test_discovery_update_switch_topic_template(
hass: HomeAssistant, mqtt_mock_entry: MqttMockHAClientGenerator
) -> None:
"""Test update of discovered switch."""
config1 = copy.deepcopy(DEFAULT_CONFIG[mqtt.DOMAIN][switch.DOMAIN])
config2 = copy.deepcopy(DEFAULT_CONFIG[mqtt.DOMAIN][switch.DOMAIN])
config1 = copy.deepcopy(DEFAULT_CONFIG[DOMAIN][switch.DOMAIN])
config2 = copy.deepcopy(DEFAULT_CONFIG[DOMAIN][switch.DOMAIN])
config1["name"] = "Beer"
config2["name"] = "Milk"
config1["state_topic"] = "switch/state1"
@@ -529,8 +530,8 @@ async def test_discovery_update_switch_template(
hass: HomeAssistant, mqtt_mock_entry: MqttMockHAClientGenerator
) -> None:
"""Test update of discovered switch."""
config1 = copy.deepcopy(DEFAULT_CONFIG[mqtt.DOMAIN][switch.DOMAIN])
config2 = copy.deepcopy(DEFAULT_CONFIG[mqtt.DOMAIN][switch.DOMAIN])
config1 = copy.deepcopy(DEFAULT_CONFIG[DOMAIN][switch.DOMAIN])
config2 = copy.deepcopy(DEFAULT_CONFIG[DOMAIN][switch.DOMAIN])
config1["name"] = "Beer"
config2["name"] = "Milk"
config1["state_topic"] = "switch/state1"
@@ -737,7 +738,7 @@ async def test_encoding_subscribable_topics(
hass,
mqtt_mock_entry,
switch.DOMAIN,
DEFAULT_CONFIG[mqtt.DOMAIN][switch.DOMAIN],
DEFAULT_CONFIG[DOMAIN][switch.DOMAIN],
topic,
value,
attribute,
+15 -14
View File
@@ -5,7 +5,8 @@ from unittest.mock import patch
import pytest
from homeassistant.components import mqtt, text
from homeassistant.components import text
from homeassistant.components.mqtt.const import DOMAIN
from homeassistant.const import ATTR_ASSUMED_STATE, ATTR_ENTITY_ID, STATE_UNKNOWN
from homeassistant.core import HomeAssistant
@@ -44,7 +45,7 @@ from tests.common import async_fire_mqtt_message
from tests.typing import MqttMockHAClientGenerator, MqttMockPahoClient
DEFAULT_CONFIG = {
mqtt.DOMAIN: {text.DOMAIN: {"name": "test", "command_topic": "test-topic"}}
DOMAIN: {text.DOMAIN: {"name": "test", "command_topic": "test-topic"}}
}
@@ -64,7 +65,7 @@ async def async_set_value(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
text.DOMAIN: {
"name": "test",
"state_topic": "state-topic",
@@ -106,7 +107,7 @@ async def test_controlling_state_via_topic(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
text.DOMAIN: {
"name": "test",
"state_topic": "state-topic",
@@ -163,7 +164,7 @@ async def test_forced_text_length(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
text.DOMAIN: {
"name": "test",
"state_topic": "state-topic",
@@ -237,7 +238,7 @@ async def test_controlling_validation_state_via_topic(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
text.DOMAIN: {
"name": "test",
"command_topic": "command-topic",
@@ -260,7 +261,7 @@ async def test_attribute_validation_max_greater_then_min(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
text.DOMAIN: {
"name": "test",
"command_topic": "command-topic",
@@ -283,7 +284,7 @@ async def test_attribute_validation_max_not_greater_then_max_state_length(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
text.DOMAIN: {
"name": "test",
"command_topic": "command-topic",
@@ -313,7 +314,7 @@ async def test_validation_payload_greater_then_max_state_length(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
text.DOMAIN: {
"name": "test",
"command_topic": "command-topic",
@@ -356,7 +357,7 @@ async def test_sending_mqtt_commands_and_optimistic(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
text.DOMAIN: {
"name": "test",
"command_topic": "command-topic",
@@ -421,7 +422,7 @@ async def test_default_availability_payload(
) -> None:
"""Test availability by default payload with defined topic."""
config = {
mqtt.DOMAIN: {
DOMAIN: {
text.DOMAIN: {
"name": "test",
"state_topic": "state-topic",
@@ -439,7 +440,7 @@ async def test_custom_availability_payload(
) -> None:
"""Test availability by custom payload with defined topic."""
config = {
mqtt.DOMAIN: {
DOMAIN: {
text.DOMAIN: {
"name": "test",
"state_topic": "state-topic",
@@ -515,7 +516,7 @@ async def test_discovery_update_attr(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
text.DOMAIN: [
{
"name": "Test 1",
@@ -758,7 +759,7 @@ async def test_encoding_subscribable_topics(
hass,
mqtt_mock_entry,
text.DOMAIN,
DEFAULT_CONFIG[mqtt.DOMAIN][text.DOMAIN],
DEFAULT_CONFIG[DOMAIN][text.DOMAIN],
topic,
value,
attribute,
+10 -9
View File
@@ -6,7 +6,8 @@ from unittest.mock import patch
import pytest
from homeassistant.components import mqtt, time
from homeassistant.components import time
from homeassistant.components.mqtt.const import DOMAIN
from homeassistant.const import ATTR_ASSUMED_STATE, ATTR_ENTITY_ID, STATE_UNKNOWN
from homeassistant.core import HomeAssistant
@@ -44,7 +45,7 @@ from tests.common import async_fire_mqtt_message
from tests.typing import MqttMockHAClientGenerator, MqttMockPahoClient
DEFAULT_CONFIG = {
mqtt.DOMAIN: {time.DOMAIN: {"name": "test", "command_topic": "test-topic"}}
DOMAIN: {time.DOMAIN: {"name": "test", "command_topic": "test-topic"}}
}
@@ -64,7 +65,7 @@ async def async_set_value(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
time.DOMAIN: {
"name": "test",
"state_topic": "state-topic",
@@ -116,7 +117,7 @@ async def test_controlling_state_via_topic(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
time.DOMAIN: {
"name": "test",
"state_topic": "state-topic",
@@ -155,7 +156,7 @@ async def test_controlling_validation_state_via_topic(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
time.DOMAIN: {
"name": "test",
"command_topic": "command-topic",
@@ -221,7 +222,7 @@ async def test_default_availability_payload(
) -> None:
"""Test availability by default payload with defined topic."""
config = {
mqtt.DOMAIN: {
DOMAIN: {
time.DOMAIN: {
"name": "test",
"state_topic": "state-topic",
@@ -239,7 +240,7 @@ async def test_custom_availability_payload(
) -> None:
"""Test availability by custom payload with defined topic."""
config = {
mqtt.DOMAIN: {
DOMAIN: {
time.DOMAIN: {
"name": "test",
"state_topic": "state-topic",
@@ -315,7 +316,7 @@ async def test_discovery_update_attr(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
time.DOMAIN: [
{
"name": "Test 1",
@@ -494,7 +495,7 @@ async def test_encoding_subscribable_topics(
hass,
mqtt_mock_entry,
time.DOMAIN,
DEFAULT_CONFIG[mqtt.DOMAIN][time.DOMAIN],
DEFAULT_CONFIG[DOMAIN][time.DOMAIN],
topic,
value,
attribute,
+16 -15
View File
@@ -6,7 +6,8 @@ from unittest.mock import patch
import pytest
from homeassistant.components import mqtt, update
from homeassistant.components import update
from homeassistant.components.mqtt.const import DOMAIN
from homeassistant.components.update import DOMAIN as UPDATE_DOMAIN, SERVICE_INSTALL
from homeassistant.const import ATTR_ENTITY_ID, STATE_OFF, STATE_ON, STATE_UNKNOWN
from homeassistant.core import HomeAssistant
@@ -42,7 +43,7 @@ from tests.common import async_fire_mqtt_message
from tests.typing import MqttMockHAClientGenerator, MqttMockPahoClient
DEFAULT_CONFIG = {
mqtt.DOMAIN: {
DOMAIN: {
update.DOMAIN: {
"name": "test",
"state_topic": "test-topic",
@@ -59,7 +60,7 @@ DEFAULT_CONFIG = {
[
(
{
mqtt.DOMAIN: {
DOMAIN: {
update.DOMAIN: {
"state_topic": "test/installed-version",
"latest_version_topic": "test/latest-version",
@@ -76,7 +77,7 @@ DEFAULT_CONFIG = {
),
(
{
mqtt.DOMAIN: {
DOMAIN: {
update.DOMAIN: {
"state_topic": "test/installed-version",
"latest_version_topic": "test/latest-version",
@@ -132,7 +133,7 @@ async def test_run_update_setup(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
update.DOMAIN: {
"state_topic": "test/installed-version",
"latest_version_topic": "test/latest-version",
@@ -182,7 +183,7 @@ async def test_run_update_setup_float(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
update.DOMAIN: {
"state_topic": "test/installed-version",
"value_template": "{{ value_json.installed }}",
@@ -227,7 +228,7 @@ async def test_value_template(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
update.DOMAIN: {
"state_topic": "test/update",
"value_template": (
@@ -298,7 +299,7 @@ async def test_errornous_value_template(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
update.DOMAIN: {
"state_topic": "test/installed-version",
"value_template": "{{ value_json.installed }}",
@@ -343,7 +344,7 @@ async def test_value_template_float(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
update.DOMAIN: {
"state_topic": "test/state-topic",
"name": "Test Update",
@@ -371,7 +372,7 @@ async def test_empty_json_state_message(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
update.DOMAIN: {
"state_topic": "test/state-topic",
"name": "Test Update",
@@ -424,7 +425,7 @@ async def test_invalid_json_state_message(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
update.DOMAIN: {
"state_topic": "test/state-topic",
"name": "Test Update",
@@ -520,7 +521,7 @@ async def test_json_state_message(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
update.DOMAIN: {
"state_topic": "test/state-topic",
"value_template": '{{ {"installed_version": value_json.installed, '
@@ -561,7 +562,7 @@ async def test_json_state_message_with_template(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
update.DOMAIN: {
"state_topic": "test/installed-version",
"latest_version_topic": "test/latest-version",
@@ -695,7 +696,7 @@ async def test_discovery_update_attr(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
update.DOMAIN: [
{
"name": "Bear",
@@ -725,7 +726,7 @@ async def test_discovery_removal_update(
hass: HomeAssistant, mqtt_mock_entry: MqttMockHAClientGenerator
) -> None:
"""Test removal of discovered update."""
data = json.dumps(DEFAULT_CONFIG[mqtt.DOMAIN][update.DOMAIN])
data = json.dumps(DEFAULT_CONFIG[DOMAIN][update.DOMAIN])
await help_test_discovery_removal(hass, mqtt_mock_entry, update.DOMAIN, data)
+7 -6
View File
@@ -11,6 +11,7 @@ from unittest.mock import MagicMock, patch
import pytest
from homeassistant.components import mqtt
from homeassistant.components.mqtt.const import DOMAIN
from homeassistant.components.mqtt.models import MessageCallbackType
from homeassistant.components.mqtt.util import EnsureJobAfterCooldown
from homeassistant.config_entries import ConfigEntryDisabler, ConfigEntryState
@@ -222,7 +223,7 @@ async def test_waiting_for_client_not_loaded(
await hass.async_block_till_done()
entry = MockConfigEntry(
domain=mqtt.DOMAIN,
domain=DOMAIN,
data={"broker": "test-broker"},
state=ConfigEntryState.NOT_LOADED,
version=mqtt.CONFIG_ENTRY_VERSION,
@@ -263,7 +264,7 @@ async def test_waiting_for_client_loaded(
assert await mqtt.async_wait_for_mqtt_client(hass)
unsub = await mqtt.async_subscribe(hass, "test_topic", lambda msg: None)
entry = hass.config_entries.async_entries(mqtt.DOMAIN)[0]
entry = hass.config_entries.async_entries(DOMAIN)[0]
assert entry.state is ConfigEntryState.LOADED
await _async_just_in_time_subscribe()
@@ -281,7 +282,7 @@ async def test_waiting_for_client_entry_fails(
await hass.async_block_till_done()
entry = MockConfigEntry(
domain=mqtt.DOMAIN,
domain=DOMAIN,
data={"broker": "test-broker"},
state=ConfigEntryState.NOT_LOADED,
version=mqtt.CONFIG_ENTRY_VERSION,
@@ -311,7 +312,7 @@ async def test_waiting_for_client_setup_fails(
await hass.async_block_till_done()
entry = MockConfigEntry(
domain=mqtt.DOMAIN,
domain=DOMAIN,
data={"broker": "test-broker"},
state=ConfigEntryState.NOT_LOADED,
version=mqtt.CONFIG_ENTRY_VERSION,
@@ -340,7 +341,7 @@ async def test_waiting_for_client_timeout(
await hass.async_block_till_done()
entry = MockConfigEntry(
domain=mqtt.DOMAIN,
domain=DOMAIN,
data={"broker": "test-broker"},
state=ConfigEntryState.NOT_LOADED,
version=mqtt.CONFIG_ENTRY_VERSION,
@@ -361,7 +362,7 @@ async def test_waiting_for_client_with_disabled_entry(
await hass.async_block_till_done()
entry = MockConfigEntry(
domain=mqtt.DOMAIN,
domain=DOMAIN,
data={"broker": "test-broker"},
state=ConfigEntryState.NOT_LOADED,
version=mqtt.CONFIG_ENTRY_VERSION,
+16 -12
View File
@@ -7,9 +7,13 @@ from unittest.mock import call, patch
import pytest
from homeassistant.components import mqtt, vacuum
from homeassistant.components import vacuum
from homeassistant.components.mqtt import vacuum as mqttvacuum
from homeassistant.components.mqtt.const import CONF_COMMAND_TOPIC, CONF_STATE_TOPIC
from homeassistant.components.mqtt.const import (
CONF_COMMAND_TOPIC,
CONF_STATE_TOPIC,
DOMAIN,
)
from homeassistant.components.mqtt.vacuum import (
ALL_SERVICES,
MQTT_VACUUM_ATTRIBUTES_BLOCKED,
@@ -80,7 +84,7 @@ SEND_COMMAND_TOPIC = "vacuum/send_command"
STATE_TOPIC = "vacuum/state"
DEFAULT_CONFIG = {
mqtt.DOMAIN: {
DOMAIN: {
vacuum.DOMAIN: {
CONF_NAME: "mqtttest",
CONF_COMMAND_TOPIC: COMMAND_TOPIC,
@@ -93,7 +97,7 @@ DEFAULT_CONFIG = {
}
CONFIG_CLEAN_SEGMENTS = {
mqtt.DOMAIN: {
DOMAIN: {
vacuum.DOMAIN: {
CONF_NAME: "test",
CONF_STATE_TOPIC: STATE_TOPIC,
@@ -103,7 +107,7 @@ CONFIG_CLEAN_SEGMENTS = {
}
}
DEFAULT_CONFIG_2 = {mqtt.DOMAIN: {vacuum.DOMAIN: {"name": "test"}}}
DEFAULT_CONFIG_2 = {DOMAIN: {vacuum.DOMAIN: {"name": "test"}}}
CONFIG_ALL_SERVICES = help_custom_config(
vacuum.DOMAIN,
@@ -363,10 +367,10 @@ async def test_clean_segments_command(
mqtt_mock_entry: MqttMockHAClientGenerator,
) -> None:
"""Test cleaning segments and repair flow."""
config_entry = hass.config_entries.async_entries(mqtt.DOMAIN)[0]
config_entry = hass.config_entries.async_entries(DOMAIN)[0]
entity_registry.async_get_or_create(
vacuum.DOMAIN,
mqtt.DOMAIN,
DOMAIN,
"veryunique",
config_entry=config_entry,
suggested_object_id="test",
@@ -549,7 +553,7 @@ async def test_removing_clean_segments_command_topic_resets_feature(
"""
await mqtt_mock_entry()
config_with_clean_segments_command_topic = CONFIG_CLEAN_SEGMENTS[mqtt.DOMAIN][
config_with_clean_segments_command_topic = CONFIG_CLEAN_SEGMENTS[DOMAIN][
vacuum.DOMAIN
]
async_fire_mqtt_message(
@@ -617,7 +621,7 @@ async def test_clean_area_feature_preserved_on_config_update(
"""
await mqtt_mock_entry()
config = CONFIG_CLEAN_SEGMENTS[mqtt.DOMAIN][vacuum.DOMAIN]
config = CONFIG_CLEAN_SEGMENTS[DOMAIN][vacuum.DOMAIN]
async_fire_mqtt_message(
hass,
"homeassistant/vacuum/bla/config",
@@ -865,7 +869,7 @@ async def test_discovery_update_attr(
"hass_config",
[
{
mqtt.DOMAIN: {
DOMAIN: {
vacuum.DOMAIN: [
{
"name": "Test 1",
@@ -1036,7 +1040,7 @@ async def test_publishing_with_custom_encoding(
"""Test publishing MQTT payload with different encoding."""
domain = vacuum.DOMAIN
config = deepcopy(DEFAULT_CONFIG)
config[mqtt.DOMAIN][domain]["supported_features"] = [
config[DOMAIN][domain]["supported_features"] = [
"clean_spot",
"fan_speed",
"locate",
@@ -1101,7 +1105,7 @@ async def test_encoding_subscribable_topics(
hass,
mqtt_mock_entry,
vacuum.DOMAIN,
DEFAULT_CONFIG[mqtt.DOMAIN][vacuum.DOMAIN],
DEFAULT_CONFIG[DOMAIN][vacuum.DOMAIN],
topic,
value,
attribute,

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