diff --git a/homeassistant/bootstrap.py b/homeassistant/bootstrap.py index 7e5aa853f12..6a667884962 100644 --- a/homeassistant/bootstrap.py +++ b/homeassistant/bootstrap.py @@ -391,6 +391,7 @@ def async_enable_logging( logging.getLogger("requests").setLevel(logging.WARNING) logging.getLogger("urllib3").setLevel(logging.WARNING) logging.getLogger("aiohttp.access").setLevel(logging.WARNING) + logging.getLogger("httpx").setLevel(logging.WARNING) sys.excepthook = lambda *args: logging.getLogger(None).exception( "Uncaught exception", exc_info=args # type: ignore[arg-type] diff --git a/homeassistant/components/abode/sensor.py b/homeassistant/components/abode/sensor.py index 87a9f8e9a27..546d57ab3e7 100644 --- a/homeassistant/components/abode/sensor.py +++ b/homeassistant/components/abode/sensor.py @@ -12,6 +12,7 @@ from homeassistant.components.sensor import ( SensorEntityDescription, ) from homeassistant.config_entries import ConfigEntry +from homeassistant.const import LIGHT_LUX from homeassistant.core import HomeAssistant from homeassistant.helpers.entity_platform import AddEntitiesCallback @@ -71,7 +72,7 @@ class AbodeSensor(AbodeDevice, SensorEntity): elif description.key == CONST.HUMI_STATUS_KEY: self._attr_native_unit_of_measurement = device.humidity_unit elif description.key == CONST.LUX_STATUS_KEY: - self._attr_native_unit_of_measurement = device.lux_unit + self._attr_native_unit_of_measurement = LIGHT_LUX @property def native_value(self) -> float | None: diff --git a/homeassistant/components/airzone_cloud/manifest.json b/homeassistant/components/airzone_cloud/manifest.json index b2899a7c80c..e64a5d9a7e2 100644 --- a/homeassistant/components/airzone_cloud/manifest.json +++ b/homeassistant/components/airzone_cloud/manifest.json @@ -6,5 +6,5 @@ "documentation": "https://www.home-assistant.io/integrations/airzone_cloud", "iot_class": "cloud_polling", "loggers": ["aioairzone_cloud"], - "requirements": ["aioairzone-cloud==0.1.7"] + "requirements": ["aioairzone-cloud==0.1.8"] } diff --git a/homeassistant/components/ambiclimate/climate.py b/homeassistant/components/ambiclimate/climate.py index 2bb2b441430..516ed319d01 100644 --- a/homeassistant/components/ambiclimate/climate.py +++ b/homeassistant/components/ambiclimate/climate.py @@ -98,7 +98,7 @@ async def async_setup_entry( tasks = [] for heater in data_connection.get_devices(): - tasks.append(heater.update_device_info()) + tasks.append(asyncio.create_task(heater.update_device_info())) await asyncio.wait(tasks) devs = [] diff --git a/homeassistant/components/flexit/climate.py b/homeassistant/components/flexit/climate.py index ac8f4b4da8c..838d2c934f9 100644 --- a/homeassistant/components/flexit/climate.py +++ b/homeassistant/components/flexit/climate.py @@ -192,7 +192,7 @@ class Flexit(ClimateEntity): result = float( await self._async_read_int16_from_register(register_type, register) ) - if result == -1: + if not result: return -1 return result / 10.0 @@ -200,6 +200,6 @@ class Flexit(ClimateEntity): result = await self._hub.async_pymodbus_call( self._slave, register, value, CALL_TYPE_WRITE_REGISTER ) - if result == -1: + if not result: return False return True diff --git a/homeassistant/components/frontend/manifest.json b/homeassistant/components/frontend/manifest.json index af8898f28e2..00753021b4c 100644 --- a/homeassistant/components/frontend/manifest.json +++ b/homeassistant/components/frontend/manifest.json @@ -20,5 +20,5 @@ "documentation": "https://www.home-assistant.io/integrations/frontend", "integration_type": "system", "quality_scale": "internal", - "requirements": ["home-assistant-frontend==20230607.0"] + "requirements": ["home-assistant-frontend==20230608.0"] } diff --git a/homeassistant/components/homekit_controller/manifest.json b/homeassistant/components/homekit_controller/manifest.json index 89261df8751..19167e762e9 100644 --- a/homeassistant/components/homekit_controller/manifest.json +++ b/homeassistant/components/homekit_controller/manifest.json @@ -14,6 +14,6 @@ "documentation": "https://www.home-assistant.io/integrations/homekit_controller", "iot_class": "local_push", "loggers": ["aiohomekit", "commentjson"], - "requirements": ["aiohomekit==2.6.4"], + "requirements": ["aiohomekit==2.6.5"], "zeroconf": ["_hap._tcp.local.", "_hap._udp.local."] } diff --git a/homeassistant/components/imap/coordinator.py b/homeassistant/components/imap/coordinator.py index d41aaf8c497..bf7f173e647 100644 --- a/homeassistant/components/imap/coordinator.py +++ b/homeassistant/components/imap/coordinator.py @@ -120,7 +120,7 @@ class ImapMessage: @property def subject(self) -> str: """Decode the message subject.""" - decoded_header = decode_header(self.email_message["Subject"]) + decoded_header = decode_header(self.email_message["Subject"] or "") subject_header = make_header(decoded_header) return str(subject_header) diff --git a/homeassistant/components/input_select/__init__.py b/homeassistant/components/input_select/__init__.py index 186ab84fb81..2c5a1c87f29 100644 --- a/homeassistant/components/input_select/__init__.py +++ b/homeassistant/components/input_select/__init__.py @@ -302,12 +302,9 @@ class InputSelect(collection.CollectionEntity, SelectEntity, RestoreEntity): async def async_select_option(self, option: str) -> None: """Select new option.""" if option not in self.options: - _LOGGER.warning( - "Invalid option: %s (possible options: %s)", - option, - ", ".join(self.options), + raise HomeAssistantError( + f"Invalid option: {option} (possible options: {', '.join(self.options)})" ) - return self._attr_current_option = option self.async_write_ha_state() diff --git a/homeassistant/components/insteon/binary_sensor.py b/homeassistant/components/insteon/binary_sensor.py index 9d1ec352bed..f895b9c7f6a 100644 --- a/homeassistant/components/insteon/binary_sensor.py +++ b/homeassistant/components/insteon/binary_sensor.py @@ -25,7 +25,7 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback from .const import SIGNAL_ADD_ENTITIES from .insteon_entity import InsteonEntity -from .utils import async_add_insteon_entities +from .utils import async_add_insteon_devices, async_add_insteon_entities SENSOR_TYPES = { OPEN_CLOSE_SENSOR: BinarySensorDeviceClass.OPENING, @@ -62,7 +62,12 @@ async def async_setup_entry( signal = f"{SIGNAL_ADD_ENTITIES}_{Platform.BINARY_SENSOR}" async_dispatcher_connect(hass, signal, async_add_insteon_binary_sensor_entities) - async_add_insteon_binary_sensor_entities() + async_add_insteon_devices( + hass, + Platform.BINARY_SENSOR, + InsteonBinarySensorEntity, + async_add_entities, + ) class InsteonBinarySensorEntity(InsteonEntity, BinarySensorEntity): diff --git a/homeassistant/components/insteon/climate.py b/homeassistant/components/insteon/climate.py index cf5f4ac2c0c..48ff898d6aa 100644 --- a/homeassistant/components/insteon/climate.py +++ b/homeassistant/components/insteon/climate.py @@ -23,7 +23,7 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback from .const import SIGNAL_ADD_ENTITIES from .insteon_entity import InsteonEntity -from .utils import async_add_insteon_entities +from .utils import async_add_insteon_devices, async_add_insteon_entities FAN_ONLY = "fan_only" @@ -71,7 +71,12 @@ async def async_setup_entry( signal = f"{SIGNAL_ADD_ENTITIES}_{Platform.CLIMATE}" async_dispatcher_connect(hass, signal, async_add_insteon_climate_entities) - async_add_insteon_climate_entities() + async_add_insteon_devices( + hass, + Platform.CLIMATE, + InsteonClimateEntity, + async_add_entities, + ) class InsteonClimateEntity(InsteonEntity, ClimateEntity): diff --git a/homeassistant/components/insteon/cover.py b/homeassistant/components/insteon/cover.py index 69a66d304ce..0756e603579 100644 --- a/homeassistant/components/insteon/cover.py +++ b/homeassistant/components/insteon/cover.py @@ -15,7 +15,7 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback from .const import SIGNAL_ADD_ENTITIES from .insteon_entity import InsteonEntity -from .utils import async_add_insteon_entities +from .utils import async_add_insteon_devices, async_add_insteon_entities async def async_setup_entry( @@ -34,7 +34,12 @@ async def async_setup_entry( signal = f"{SIGNAL_ADD_ENTITIES}_{Platform.COVER}" async_dispatcher_connect(hass, signal, async_add_insteon_cover_entities) - async_add_insteon_cover_entities() + async_add_insteon_devices( + hass, + Platform.COVER, + InsteonCoverEntity, + async_add_entities, + ) class InsteonCoverEntity(InsteonEntity, CoverEntity): diff --git a/homeassistant/components/insteon/fan.py b/homeassistant/components/insteon/fan.py index b0d664a821b..92f56098a91 100644 --- a/homeassistant/components/insteon/fan.py +++ b/homeassistant/components/insteon/fan.py @@ -17,7 +17,7 @@ from homeassistant.util.percentage import ( from .const import SIGNAL_ADD_ENTITIES from .insteon_entity import InsteonEntity -from .utils import async_add_insteon_entities +from .utils import async_add_insteon_devices, async_add_insteon_entities SPEED_RANGE = (1, 255) # off is not included @@ -38,7 +38,12 @@ async def async_setup_entry( signal = f"{SIGNAL_ADD_ENTITIES}_{Platform.FAN}" async_dispatcher_connect(hass, signal, async_add_insteon_fan_entities) - async_add_insteon_fan_entities() + async_add_insteon_devices( + hass, + Platform.FAN, + InsteonFanEntity, + async_add_entities, + ) class InsteonFanEntity(InsteonEntity, FanEntity): diff --git a/homeassistant/components/insteon/ipdb.py b/homeassistant/components/insteon/ipdb.py index ee799e103f9..de3ba7d55f2 100644 --- a/homeassistant/components/insteon/ipdb.py +++ b/homeassistant/components/insteon/ipdb.py @@ -1,4 +1,7 @@ """Utility methods for the Insteon platform.""" +from collections.abc import Iterable + +from pyinsteon.device_types.device_base import Device from pyinsteon.device_types.ipdb import ( AccessControl_Morningstar, ClimateControl_Thermostat, @@ -44,7 +47,7 @@ from pyinsteon.device_types.ipdb import ( from homeassistant.const import Platform -DEVICE_PLATFORM = { +DEVICE_PLATFORM: dict[Device, dict[Platform, Iterable[int]]] = { AccessControl_Morningstar: {Platform.LOCK: [1]}, DimmableLightingControl: {Platform.LIGHT: [1]}, DimmableLightingControl_Dial: {Platform.LIGHT: [1]}, @@ -101,11 +104,11 @@ DEVICE_PLATFORM = { } -def get_device_platforms(device): +def get_device_platforms(device) -> dict[Platform, Iterable[int]]: """Return the HA platforms for a device type.""" - return DEVICE_PLATFORM.get(type(device), {}).keys() + return DEVICE_PLATFORM.get(type(device), {}) -def get_platform_groups(device, domain) -> dict: - """Return the platforms that a device belongs in.""" - return DEVICE_PLATFORM.get(type(device), {}).get(domain, {}) # type: ignore[attr-defined] +def get_device_platform_groups(device: Device, platform: Platform) -> Iterable[int]: + """Return the list of device groups for a platform.""" + return get_device_platforms(device).get(platform, []) diff --git a/homeassistant/components/insteon/light.py b/homeassistant/components/insteon/light.py index 44574c696b4..1c12bc794f9 100644 --- a/homeassistant/components/insteon/light.py +++ b/homeassistant/components/insteon/light.py @@ -12,7 +12,7 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback from .const import SIGNAL_ADD_ENTITIES from .insteon_entity import InsteonEntity -from .utils import async_add_insteon_entities +from .utils import async_add_insteon_devices, async_add_insteon_entities MAX_BRIGHTNESS = 255 @@ -37,7 +37,12 @@ async def async_setup_entry( signal = f"{SIGNAL_ADD_ENTITIES}_{Platform.LIGHT}" async_dispatcher_connect(hass, signal, async_add_insteon_light_entities) - async_add_insteon_light_entities() + async_add_insteon_devices( + hass, + Platform.LIGHT, + InsteonDimmerEntity, + async_add_entities, + ) class InsteonDimmerEntity(InsteonEntity, LightEntity): diff --git a/homeassistant/components/insteon/lock.py b/homeassistant/components/insteon/lock.py index 75487e7696c..27fb0fd42d8 100644 --- a/homeassistant/components/insteon/lock.py +++ b/homeassistant/components/insteon/lock.py @@ -11,7 +11,7 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback from .const import SIGNAL_ADD_ENTITIES from .insteon_entity import InsteonEntity -from .utils import async_add_insteon_entities +from .utils import async_add_insteon_devices, async_add_insteon_entities async def async_setup_entry( @@ -30,7 +30,12 @@ async def async_setup_entry( signal = f"{SIGNAL_ADD_ENTITIES}_{Platform.LOCK}" async_dispatcher_connect(hass, signal, async_add_insteon_lock_entities) - async_add_insteon_lock_entities() + async_add_insteon_devices( + hass, + Platform.LOCK, + InsteonLockEntity, + async_add_entities, + ) class InsteonLockEntity(InsteonEntity, LockEntity): diff --git a/homeassistant/components/insteon/switch.py b/homeassistant/components/insteon/switch.py index 8f7c396f213..8acde0429cd 100644 --- a/homeassistant/components/insteon/switch.py +++ b/homeassistant/components/insteon/switch.py @@ -10,7 +10,7 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback from .const import SIGNAL_ADD_ENTITIES from .insteon_entity import InsteonEntity -from .utils import async_add_insteon_entities +from .utils import async_add_insteon_devices, async_add_insteon_entities async def async_setup_entry( @@ -33,7 +33,12 @@ async def async_setup_entry( signal = f"{SIGNAL_ADD_ENTITIES}_{Platform.SWITCH}" async_dispatcher_connect(hass, signal, async_add_insteon_switch_entities) - async_add_insteon_switch_entities() + async_add_insteon_devices( + hass, + Platform.SWITCH, + InsteonSwitchEntity, + async_add_entities, + ) class InsteonSwitchEntity(InsteonEntity, SwitchEntity): diff --git a/homeassistant/components/insteon/utils.py b/homeassistant/components/insteon/utils.py index 58b2430092c..f9c22ef62a5 100644 --- a/homeassistant/components/insteon/utils.py +++ b/homeassistant/components/insteon/utils.py @@ -1,7 +1,10 @@ """Utilities used by insteon component.""" +from __future__ import annotations + import asyncio from collections.abc import Callable import logging +from typing import TYPE_CHECKING, Any from pyinsteon import devices from pyinsteon.address import Address @@ -30,6 +33,7 @@ from homeassistant.const import ( CONF_ENTITY_ID, CONF_PLATFORM, ENTITY_MATCH_ALL, + Platform, ) from homeassistant.core import HomeAssistant, ServiceCall, callback from homeassistant.helpers import device_registry as dr @@ -38,6 +42,7 @@ from homeassistant.helpers.dispatcher import ( async_dispatcher_send, dispatcher_send, ) +from homeassistant.helpers.entity_platform import AddEntitiesCallback from .const import ( CONF_CAT, @@ -78,7 +83,7 @@ from .const import ( SRV_X10_ALL_LIGHTS_ON, SRV_X10_ALL_UNITS_OFF, ) -from .ipdb import get_device_platforms, get_platform_groups +from .ipdb import get_device_platform_groups, get_device_platforms from .schemas import ( ADD_ALL_LINK_SCHEMA, ADD_DEFAULT_LINKS_SCHEMA, @@ -89,6 +94,9 @@ from .schemas import ( X10_HOUSECODE_SCHEMA, ) +if TYPE_CHECKING: + from .insteon_entity import InsteonEntity + _LOGGER = logging.getLogger(__name__) @@ -132,6 +140,9 @@ def add_insteon_events(hass: HomeAssistant, device: Device) -> None: _LOGGER.debug("Firing event %s with %s", event, schema) hass.bus.async_fire(event, schema) + if str(device.address).startswith("X10"): + return + for name_or_group, event in device.events.items(): if isinstance(name_or_group, int): for _, event in device.events[name_or_group].items(): @@ -158,8 +169,10 @@ def register_new_device_callback(hass): await device.async_status() platforms = get_device_platforms(device) for platform in platforms: + groups = get_device_platform_groups(device, platform) signal = f"{SIGNAL_ADD_ENTITIES}_{platform}" - dispatcher_send(hass, signal, {"address": device.address}) + dispatcher_send(hass, signal, {"address": device.address, "groups": groups}) + add_insteon_events(hass, device) devices.subscribe(async_new_insteon_device, force_strong_ref=True) @@ -383,20 +396,38 @@ def print_aldb_to_log(aldb): @callback def async_add_insteon_entities( - hass, platform, entity_type, async_add_entities, discovery_info -): - """Add Insteon devices to a platform.""" - new_entities = [] - device_list = [discovery_info.get("address")] if discovery_info else devices - - for address in device_list: - device = devices[address] - groups = get_platform_groups(device, platform) - for group in groups: - new_entities.append(entity_type(device, group)) + hass: HomeAssistant, + platform: Platform, + entity_type: type[InsteonEntity], + async_add_entities: AddEntitiesCallback, + discovery_info: dict[str, Any], +) -> None: + """Add an Insteon group to a platform.""" + address = discovery_info["address"] + device = devices[address] + new_entities = [ + entity_type(device=device, group=group) for group in discovery_info["groups"] + ] async_add_entities(new_entities) +@callback +def async_add_insteon_devices( + hass: HomeAssistant, + platform: Platform, + entity_type: type[InsteonEntity], + async_add_entities: AddEntitiesCallback, +) -> None: + """Add all entities to a platform.""" + for address in devices: + device = devices[address] + groups = get_device_platform_groups(device, platform) + discovery_info = {"address": address, "groups": groups} + async_add_insteon_entities( + hass, platform, entity_type, async_add_entities, discovery_info + ) + + def get_usb_ports() -> dict[str, str]: """Return a dict of USB ports and their friendly names.""" ports = list_ports.comports() diff --git a/homeassistant/components/lastfm/config_flow.py b/homeassistant/components/lastfm/config_flow.py index f7d7a9fd314..54406a6e03b 100644 --- a/homeassistant/components/lastfm/config_flow.py +++ b/homeassistant/components/lastfm/config_flow.py @@ -3,7 +3,7 @@ from __future__ import annotations from typing import Any -from pylast import LastFMNetwork, User, WSError +from pylast import LastFMNetwork, PyLastError, User, WSError import voluptuous as vol from homeassistant.config_entries import ( @@ -128,11 +128,14 @@ class LastFmConfigFlowHandler(ConfigFlow, domain=DOMAIN): main_user, _ = get_lastfm_user( self.data[CONF_API_KEY], self.data[CONF_MAIN_USER] ) + friends_response = await self.hass.async_add_executor_job( + main_user.get_friends + ) friends = [ SelectOptionDict(value=friend.name, label=friend.get_name(True)) - for friend in main_user.get_friends() + for friend in friends_response ] - except WSError: + except PyLastError: friends = [] return self.async_show_form( step_id="friends", @@ -197,11 +200,14 @@ class LastFmOptionsFlowHandler(OptionsFlowWithConfigEntry): self.options[CONF_API_KEY], self.options[CONF_MAIN_USER], ) + friends_response = await self.hass.async_add_executor_job( + main_user.get_friends + ) friends = [ SelectOptionDict(value=friend.name, label=friend.get_name(True)) - for friend in main_user.get_friends() + for friend in friends_response ] - except WSError: + except PyLastError: friends = [] else: friends = [] diff --git a/homeassistant/components/logger/__init__.py b/homeassistant/components/logger/__init__.py index fe29447aeba..b1086d7f780 100644 --- a/homeassistant/components/logger/__init__.py +++ b/homeassistant/components/logger/__init__.py @@ -13,7 +13,6 @@ from homeassistant.helpers.typing import ConfigType from . import websocket_api from .const import ( ATTR_LEVEL, - DEFAULT_LOGSEVERITY, DOMAIN, LOGGER_DEFAULT, LOGGER_FILTERS, @@ -39,9 +38,7 @@ CONFIG_SCHEMA = vol.Schema( { DOMAIN: vol.Schema( { - vol.Optional( - LOGGER_DEFAULT, default=DEFAULT_LOGSEVERITY - ): _VALID_LOG_LEVEL, + vol.Optional(LOGGER_DEFAULT): _VALID_LOG_LEVEL, vol.Optional(LOGGER_LOGS): vol.Schema({cv.string: _VALID_LOG_LEVEL}), vol.Optional(LOGGER_FILTERS): vol.Schema({cv.string: [cv.is_regex]}), } diff --git a/homeassistant/components/logger/helpers.py b/homeassistant/components/logger/helpers.py index 0f1751c1b2e..dcd4348a561 100644 --- a/homeassistant/components/logger/helpers.py +++ b/homeassistant/components/logger/helpers.py @@ -119,7 +119,7 @@ class LoggerSettings: self._yaml_config = yaml_config self._default_level = logging.INFO - if DOMAIN in yaml_config: + if DOMAIN in yaml_config and LOGGER_DEFAULT in yaml_config[DOMAIN]: self._default_level = yaml_config[DOMAIN][LOGGER_DEFAULT] self._store: Store[dict[str, dict[str, dict[str, Any]]]] = Store( hass, STORAGE_VERSION, STORAGE_KEY diff --git a/homeassistant/components/media_source/local_source.py b/homeassistant/components/media_source/local_source.py index c29794ae8d7..89437a6b2e0 100644 --- a/homeassistant/components/media_source/local_source.py +++ b/homeassistant/components/media_source/local_source.py @@ -38,7 +38,7 @@ def async_setup(hass: HomeAssistant) -> None: class LocalSource(MediaSource): """Provide local directories as media sources.""" - name: str = "Local Media" + name: str = "My media" def __init__(self, hass: HomeAssistant) -> None: """Initialize local source.""" diff --git a/homeassistant/components/melnor/manifest.json b/homeassistant/components/melnor/manifest.json index 185899a9656..45dce207f7e 100644 --- a/homeassistant/components/melnor/manifest.json +++ b/homeassistant/components/melnor/manifest.json @@ -12,5 +12,5 @@ "dependencies": ["bluetooth_adapters"], "documentation": "https://www.home-assistant.io/integrations/melnor", "iot_class": "local_polling", - "requirements": ["melnor-bluetooth==0.0.24"] + "requirements": ["melnor-bluetooth==0.0.25"] } diff --git a/homeassistant/components/opensky/manifest.json b/homeassistant/components/opensky/manifest.json index 854f2ec840b..cda86006bbd 100644 --- a/homeassistant/components/opensky/manifest.json +++ b/homeassistant/components/opensky/manifest.json @@ -4,5 +4,5 @@ "codeowners": ["@joostlek"], "documentation": "https://www.home-assistant.io/integrations/opensky", "iot_class": "cloud_polling", - "requirements": ["python-opensky==0.0.7"] + "requirements": ["python-opensky==0.0.9"] } diff --git a/homeassistant/components/opensky/sensor.py b/homeassistant/components/opensky/sensor.py index f3704f8d547..cdedd0c9620 100644 --- a/homeassistant/components/opensky/sensor.py +++ b/homeassistant/components/opensky/sensor.py @@ -78,7 +78,7 @@ def setup_platform( latitude = config.get(CONF_LATITUDE, hass.config.latitude) longitude = config.get(CONF_LONGITUDE, hass.config.longitude) radius = config.get(CONF_RADIUS, 0) - bounding_box = OpenSky.get_bounding_box(latitude, longitude, radius) + bounding_box = OpenSky.get_bounding_box(latitude, longitude, radius * 1000) session = async_get_clientsession(hass) opensky = OpenSky(session=session) add_entities( diff --git a/homeassistant/components/otbr/manifest.json b/homeassistant/components/otbr/manifest.json index f04e15a549c..94659df8547 100644 --- a/homeassistant/components/otbr/manifest.json +++ b/homeassistant/components/otbr/manifest.json @@ -8,5 +8,5 @@ "documentation": "https://www.home-assistant.io/integrations/otbr", "integration_type": "service", "iot_class": "local_polling", - "requirements": ["python-otbr-api==2.1.0"] + "requirements": ["python-otbr-api==2.2.0"] } diff --git a/homeassistant/components/otbr/util.py b/homeassistant/components/otbr/util.py index 5caebba5eb5..2d6217ea585 100644 --- a/homeassistant/components/otbr/util.py +++ b/homeassistant/components/otbr/util.py @@ -95,6 +95,11 @@ class OTBRData: """Create an active operational dataset.""" return await self.api.create_active_dataset(dataset) + @_handle_otbr_error + async def delete_active_dataset(self) -> None: + """Delete the active operational dataset.""" + return await self.api.delete_active_dataset() + @_handle_otbr_error async def set_active_dataset_tlvs(self, dataset: bytes) -> None: """Set current active operational dataset in TLVS format.""" diff --git a/homeassistant/components/otbr/websocket_api.py b/homeassistant/components/otbr/websocket_api.py index 0dcce288348..06bbca3a4ab 100644 --- a/homeassistant/components/otbr/websocket_api.py +++ b/homeassistant/components/otbr/websocket_api.py @@ -81,6 +81,12 @@ async def websocket_create_network( connection.send_error(msg["id"], "set_enabled_failed", str(exc)) return + try: + await data.delete_active_dataset() + except HomeAssistantError as exc: + connection.send_error(msg["id"], "delete_active_dataset_failed", str(exc)) + return + try: await data.create_active_dataset( python_otbr_api.ActiveDataSet( diff --git a/homeassistant/components/overkiz/manifest.json b/homeassistant/components/overkiz/manifest.json index 2d81b7bab07..b03b60cd753 100644 --- a/homeassistant/components/overkiz/manifest.json +++ b/homeassistant/components/overkiz/manifest.json @@ -13,7 +13,7 @@ "integration_type": "hub", "iot_class": "cloud_polling", "loggers": ["boto3", "botocore", "pyhumps", "pyoverkiz", "s3transfer"], - "requirements": ["pyoverkiz==1.7.9"], + "requirements": ["pyoverkiz==1.8.0"], "zeroconf": [ { "type": "_kizbox._tcp.local.", diff --git a/homeassistant/components/pulseaudio_loopback/manifest.json b/homeassistant/components/pulseaudio_loopback/manifest.json index f04538c01bb..a67dc614c50 100644 --- a/homeassistant/components/pulseaudio_loopback/manifest.json +++ b/homeassistant/components/pulseaudio_loopback/manifest.json @@ -4,5 +4,5 @@ "codeowners": [], "documentation": "https://www.home-assistant.io/integrations/pulseaudio_loopback", "iot_class": "local_polling", - "requirements": ["pulsectl==20.2.4"] + "requirements": ["pulsectl==23.5.2"] } diff --git a/homeassistant/components/thread/manifest.json b/homeassistant/components/thread/manifest.json index 9a6a64481cd..0ce54496539 100644 --- a/homeassistant/components/thread/manifest.json +++ b/homeassistant/components/thread/manifest.json @@ -7,6 +7,6 @@ "documentation": "https://www.home-assistant.io/integrations/thread", "integration_type": "service", "iot_class": "local_polling", - "requirements": ["python-otbr-api==2.1.0", "pyroute2==0.7.5"], + "requirements": ["python-otbr-api==2.2.0", "pyroute2==0.7.5"], "zeroconf": ["_meshcop._udp.local."] } diff --git a/homeassistant/components/unifiprotect/manifest.json b/homeassistant/components/unifiprotect/manifest.json index 78e2ee3012c..a414c03a0d4 100644 --- a/homeassistant/components/unifiprotect/manifest.json +++ b/homeassistant/components/unifiprotect/manifest.json @@ -41,7 +41,7 @@ "iot_class": "local_push", "loggers": ["pyunifiprotect", "unifi_discovery"], "quality_scale": "platinum", - "requirements": ["pyunifiprotect==4.10.1", "unifi-discovery==1.1.7"], + "requirements": ["pyunifiprotect==4.10.2", "unifi-discovery==1.1.7"], "ssdp": [ { "manufacturer": "Ubiquiti Networks", diff --git a/homeassistant/const.py b/homeassistant/const.py index 9308d364ecb..3392b6dabd8 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -8,7 +8,7 @@ from .backports.enum import StrEnum APPLICATION_NAME: Final = "HomeAssistant" MAJOR_VERSION: Final = 2023 MINOR_VERSION: Final = 6 -PATCH_VERSION: Final = "0" +PATCH_VERSION: Final = "1" __short_version__: Final = f"{MAJOR_VERSION}.{MINOR_VERSION}" __version__: Final = f"{__short_version__}.{PATCH_VERSION}" REQUIRED_PYTHON_VER: Final[tuple[int, int, int]] = (3, 10, 0) diff --git a/homeassistant/package_constraints.txt b/homeassistant/package_constraints.txt index 22d47a0e430..a7688415905 100644 --- a/homeassistant/package_constraints.txt +++ b/homeassistant/package_constraints.txt @@ -25,7 +25,7 @@ ha-av==10.1.0 hass-nabucasa==0.67.1 hassil==1.0.6 home-assistant-bluetooth==1.10.0 -home-assistant-frontend==20230607.0 +home-assistant-frontend==20230608.0 home-assistant-intents==2023.6.5 httpx==0.24.1 ifaddr==0.2.0 @@ -128,9 +128,8 @@ authlib<1.0 # Version 2.0 added typing, prevent accidental fallbacks backoff>=2.0 -# Breaking change in version -# https://github.com/samuelcolvin/pydantic/issues/4092 -pydantic!=1.9.1 +# Require to avoid issues with decorators (#93904). v2 has breaking changes. +pydantic>=1.10.8,<2.0 # Breaks asyncio # https://github.com/pubnub/python/issues/130 diff --git a/homeassistant/setup.py b/homeassistant/setup.py index d4b9be05ef4..fc5aa8291b7 100644 --- a/homeassistant/setup.py +++ b/homeassistant/setup.py @@ -245,7 +245,10 @@ async def _async_setup_component( severity=IssueSeverity.ERROR, issue_domain=domain, translation_key="integration_key_no_support", - translation_placeholders={"domain": domain}, + translation_placeholders={ + "domain": domain, + "add_integration": f"/config/integrations/dashboard/add?domain={domain}", + }, ) start = timer() diff --git a/pyproject.toml b/pyproject.toml index 2ece07d96e6..ca4f61a5ccc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "homeassistant" -version = "2023.6.0" +version = "2023.6.1" license = {text = "Apache-2.0"} description = "Open-source home automation platform running on Python 3." readme = "README.rst" diff --git a/requirements_all.txt b/requirements_all.txt index 8bb4580aa61..eca5516f7ec 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -116,7 +116,7 @@ aio_georss_gdacs==0.8 aioairq==0.2.4 # homeassistant.components.airzone_cloud -aioairzone-cloud==0.1.7 +aioairzone-cloud==0.1.8 # homeassistant.components.airzone aioairzone==0.6.3 @@ -177,7 +177,7 @@ aioguardian==2022.07.0 aioharmony==0.2.10 # homeassistant.components.homekit_controller -aiohomekit==2.6.4 +aiohomekit==2.6.5 # homeassistant.components.emulated_hue # homeassistant.components.http @@ -924,7 +924,7 @@ hole==0.8.0 holidays==0.21.13 # homeassistant.components.frontend -home-assistant-frontend==20230607.0 +home-assistant-frontend==20230608.0 # homeassistant.components.conversation home-assistant-intents==2023.6.5 @@ -1122,7 +1122,7 @@ mcstatus==6.0.0 meater-python==0.0.8 # homeassistant.components.melnor -melnor-bluetooth==0.0.24 +melnor-bluetooth==0.0.25 # homeassistant.components.message_bird messagebird==1.2.0 @@ -1418,7 +1418,7 @@ psutil-home-assistant==0.0.1 psutil==5.9.5 # homeassistant.components.pulseaudio_loopback -pulsectl==20.2.4 +pulsectl==23.5.2 # homeassistant.components.androidtv pure-python-adb[async]==0.3.0.dev0 @@ -1872,7 +1872,7 @@ pyotgw==2.1.3 pyotp==2.8.0 # homeassistant.components.overkiz -pyoverkiz==1.7.9 +pyoverkiz==1.8.0 # homeassistant.components.openweathermap pyowm==3.2.0 @@ -2102,11 +2102,11 @@ python-mystrom==2.2.0 python-nest==4.2.0 # homeassistant.components.opensky -python-opensky==0.0.7 +python-opensky==0.0.9 # homeassistant.components.otbr # homeassistant.components.thread -python-otbr-api==2.1.0 +python-otbr-api==2.2.0 # homeassistant.components.picnic python-picnic-api==1.1.0 @@ -2168,7 +2168,7 @@ pytrafikverket==0.3.3 pyudev==0.23.2 # homeassistant.components.unifiprotect -pyunifiprotect==4.10.1 +pyunifiprotect==4.10.2 # homeassistant.components.uptimerobot pyuptimerobot==22.2.0 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index bc1cae28d09..7f48debc62b 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -106,7 +106,7 @@ aio_georss_gdacs==0.8 aioairq==0.2.4 # homeassistant.components.airzone_cloud -aioairzone-cloud==0.1.7 +aioairzone-cloud==0.1.8 # homeassistant.components.airzone aioairzone==0.6.3 @@ -164,7 +164,7 @@ aioguardian==2022.07.0 aioharmony==0.2.10 # homeassistant.components.homekit_controller -aiohomekit==2.6.4 +aiohomekit==2.6.5 # homeassistant.components.emulated_hue # homeassistant.components.http @@ -716,7 +716,7 @@ hole==0.8.0 holidays==0.21.13 # homeassistant.components.frontend -home-assistant-frontend==20230607.0 +home-assistant-frontend==20230608.0 # homeassistant.components.conversation home-assistant-intents==2023.6.5 @@ -848,7 +848,7 @@ mcstatus==6.0.0 meater-python==0.0.8 # homeassistant.components.melnor -melnor-bluetooth==0.0.24 +melnor-bluetooth==0.0.25 # homeassistant.components.meteo_france meteofrance-api==1.2.0 @@ -1382,7 +1382,7 @@ pyotgw==2.1.3 pyotp==2.8.0 # homeassistant.components.overkiz -pyoverkiz==1.7.9 +pyoverkiz==1.8.0 # homeassistant.components.openweathermap pyowm==3.2.0 @@ -1532,7 +1532,7 @@ python-nest==4.2.0 # homeassistant.components.otbr # homeassistant.components.thread -python-otbr-api==2.1.0 +python-otbr-api==2.2.0 # homeassistant.components.picnic python-picnic-api==1.1.0 @@ -1579,7 +1579,7 @@ pytrafikverket==0.3.3 pyudev==0.23.2 # homeassistant.components.unifiprotect -pyunifiprotect==4.10.1 +pyunifiprotect==4.10.2 # homeassistant.components.uptimerobot pyuptimerobot==22.2.0 diff --git a/script/gen_requirements_all.py b/script/gen_requirements_all.py index b51ddb46307..1b5969a6e86 100755 --- a/script/gen_requirements_all.py +++ b/script/gen_requirements_all.py @@ -132,9 +132,8 @@ authlib<1.0 # Version 2.0 added typing, prevent accidental fallbacks backoff>=2.0 -# Breaking change in version -# https://github.com/samuelcolvin/pydantic/issues/4092 -pydantic!=1.9.1 +# Require to avoid issues with decorators (#93904). v2 has breaking changes. +pydantic>=1.10.8,<2.0 # Breaks asyncio # https://github.com/pubnub/python/issues/130 diff --git a/tests/components/abode/test_sensor.py b/tests/components/abode/test_sensor.py index 5d074de214f..67892dfafb4 100644 --- a/tests/components/abode/test_sensor.py +++ b/tests/components/abode/test_sensor.py @@ -39,7 +39,7 @@ async def test_attributes(hass: HomeAssistant) -> None: state = hass.states.get("sensor.environment_sensor_lux") assert state.state == "1.0" - assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == "lux" + assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == "lx" state = hass.states.get("sensor.environment_sensor_temperature") # Abodepy device JSON reports 19.5, but Home Assistant shows 19.4 diff --git a/tests/components/imap/const.py b/tests/components/imap/const.py index 15b56547894..5dcce782a41 100644 --- a/tests/components/imap/const.py +++ b/tests/components/imap/const.py @@ -24,7 +24,12 @@ TEST_MESSAGE_HEADERS2 = ( b"Subject: Test subject\r\n" ) +TEST_MESSAGE_HEADERS3 = b"" + TEST_MESSAGE = TEST_MESSAGE_HEADERS1 + DATE_HEADER1 + TEST_MESSAGE_HEADERS2 +TEST_MESSAGE_NO_SUBJECT_TO_FROM = ( + TEST_MESSAGE_HEADERS1 + DATE_HEADER1 + TEST_MESSAGE_HEADERS3 +) TEST_MESSAGE_ALT = TEST_MESSAGE_HEADERS1 + DATE_HEADER2 + TEST_MESSAGE_HEADERS2 TEST_INVALID_DATE1 = ( TEST_MESSAGE_HEADERS1 + DATE_HEADER_INVALID1 + TEST_MESSAGE_HEADERS2 @@ -204,4 +209,19 @@ TEST_FETCH_RESPONSE_MULTIPART = ( ], ) + +TEST_FETCH_RESPONSE_NO_SUBJECT_TO_FROM = ( + "OK", + [ + b"1 FETCH (BODY[] {" + + str(len(TEST_MESSAGE_NO_SUBJECT_TO_FROM + TEST_CONTENT_TEXT_PLAIN)).encode( + "utf-8" + ) + + b"}", + bytearray(TEST_MESSAGE_NO_SUBJECT_TO_FROM + TEST_CONTENT_TEXT_PLAIN), + b")", + b"Fetch completed (0.0001 + 0.000 secs).", + ], +) + RESPONSE_BAD = ("BAD", []) diff --git a/tests/components/imap/test_init.py b/tests/components/imap/test_init.py index 712f159b4cb..2b7514cd3ea 100644 --- a/tests/components/imap/test_init.py +++ b/tests/components/imap/test_init.py @@ -1,6 +1,6 @@ """Test the imap entry initialization.""" import asyncio -from datetime import datetime, timedelta +from datetime import datetime, timedelta, timezone from typing import Any from unittest.mock import AsyncMock, MagicMock, patch @@ -22,6 +22,7 @@ from .const import ( TEST_FETCH_RESPONSE_INVALID_DATE2, TEST_FETCH_RESPONSE_INVALID_DATE3, TEST_FETCH_RESPONSE_MULTIPART, + TEST_FETCH_RESPONSE_NO_SUBJECT_TO_FROM, TEST_FETCH_RESPONSE_TEXT_BARE, TEST_FETCH_RESPONSE_TEXT_OTHER, TEST_FETCH_RESPONSE_TEXT_PLAIN, @@ -153,6 +154,44 @@ async def test_receiving_message_successfully( ) +@pytest.mark.parametrize("imap_search", [TEST_SEARCH_RESPONSE]) +@pytest.mark.parametrize("imap_fetch", [TEST_FETCH_RESPONSE_NO_SUBJECT_TO_FROM]) +@pytest.mark.parametrize("imap_has_capability", [True, False], ids=["push", "poll"]) +async def test_receiving_message_no_subject_to_from( + hass: HomeAssistant, mock_imap_protocol: MagicMock +) -> None: + """Test receiving a message successfully without subject, to and from in body.""" + event_called = async_capture_events(hass, "imap_content") + + config_entry = MockConfigEntry(domain=DOMAIN, data=MOCK_CONFIG) + config_entry.add_to_hass(hass) + assert await hass.config_entries.async_setup(config_entry.entry_id) + await hass.async_block_till_done() + # Make sure we have had one update (when polling) + async_fire_time_changed(hass, utcnow() + timedelta(seconds=5)) + await hass.async_block_till_done() + state = hass.states.get("sensor.imap_email_email_com") + # we should have received one message + assert state is not None + assert state.state == "1" + + # we should have received one event + assert len(event_called) == 1 + data: dict[str, Any] = event_called[0].data + assert data["server"] == "imap.server.com" + assert data["username"] == "email@email.com" + assert data["search"] == "UnSeen UnDeleted" + assert data["folder"] == "INBOX" + assert data["sender"] == "" + assert data["subject"] == "" + assert data["date"] == datetime( + 2023, 3, 24, 13, 52, tzinfo=timezone(timedelta(seconds=3600)) + ) + assert data["text"] == "Test body\r\n\r\n" + assert data["headers"]["Return-Path"] == ("",) + assert data["headers"]["Delivered-To"] == ("notify@example.com",) + + @pytest.mark.parametrize("imap_has_capability", [True, False], ids=["push", "poll"]) @pytest.mark.parametrize( ("imap_login_state", "success"), [(AUTH, True), (NONAUTH, False)] diff --git a/tests/components/input_select/test_init.py b/tests/components/input_select/test_init.py index 315392702eb..6908a1c532e 100644 --- a/tests/components/input_select/test_init.py +++ b/tests/components/input_select/test_init.py @@ -102,12 +102,13 @@ async def test_select_option(hass: HomeAssistant) -> None: state = hass.states.get(entity_id) assert state.state == "another option" - await hass.services.async_call( - DOMAIN, - SERVICE_SELECT_OPTION, - {ATTR_ENTITY_ID: entity_id, ATTR_OPTION: "non existing option"}, - blocking=True, - ) + with pytest.raises(HomeAssistantError): + await hass.services.async_call( + DOMAIN, + SERVICE_SELECT_OPTION, + {ATTR_ENTITY_ID: entity_id, ATTR_OPTION: "non existing option"}, + blocking=True, + ) state = hass.states.get(entity_id) assert state.state == "another option" @@ -305,12 +306,13 @@ async def test_set_options_service(hass: HomeAssistant) -> None: state = hass.states.get(entity_id) assert state.state == "test1" - await hass.services.async_call( - DOMAIN, - SERVICE_SELECT_OPTION, - {ATTR_ENTITY_ID: entity_id, ATTR_OPTION: "first option"}, - blocking=True, - ) + with pytest.raises(HomeAssistantError): + await hass.services.async_call( + DOMAIN, + SERVICE_SELECT_OPTION, + {ATTR_ENTITY_ID: entity_id, ATTR_OPTION: "first option"}, + blocking=True, + ) state = hass.states.get(entity_id) assert state.state == "test1" diff --git a/tests/components/input_select/test_reproduce_state.py b/tests/components/input_select/test_reproduce_state.py index d6e9274fa8d..a00b6b02ade 100644 --- a/tests/components/input_select/test_reproduce_state.py +++ b/tests/components/input_select/test_reproduce_state.py @@ -2,6 +2,7 @@ import pytest from homeassistant.core import HomeAssistant, State +from homeassistant.exceptions import HomeAssistantError from homeassistant.helpers.state import async_reproduce_state from homeassistant.setup import async_setup_component @@ -60,7 +61,8 @@ async def test_reproducing_states( assert hass.states.get(ENTITY).state == VALID_OPTION3 # Test setting state to invalid state - await async_reproduce_state(hass, [State(ENTITY, INVALID_OPTION)]) + with pytest.raises(HomeAssistantError): + await async_reproduce_state(hass, [State(ENTITY, INVALID_OPTION)]) # The entity state should be unchanged assert hass.states.get(ENTITY).state == VALID_OPTION3 diff --git a/tests/components/lastfm/__init__.py b/tests/components/lastfm/__init__.py index 568983f400d..7ee8665e28a 100644 --- a/tests/components/lastfm/__init__.py +++ b/tests/components/lastfm/__init__.py @@ -1,7 +1,7 @@ """The tests for lastfm.""" from unittest.mock import patch -from pylast import Track, WSError +from pylast import PyLastError, Track from homeassistant.components.lastfm.const import CONF_MAIN_USER, CONF_USERS from homeassistant.const import CONF_API_KEY @@ -65,7 +65,7 @@ class MockUser: def get_friends(self): """Get mock friends.""" if self._has_friends is False: - raise WSError("network", "status", "Page not found") + raise PyLastError("network", "status", "Page not found") return [MockUser(None, None, True, USERNAME_2)] diff --git a/tests/components/media_source/test_init.py b/tests/components/media_source/test_init.py index ec374e6a6e1..4e512608abf 100644 --- a/tests/components/media_source/test_init.py +++ b/tests/components/media_source/test_init.py @@ -95,7 +95,7 @@ async def test_async_browse_media(hass: HomeAssistant) -> None: media = await media_source.async_browse_media(hass, const.URI_SCHEME) assert isinstance(media, media_source.models.BrowseMediaSource) assert len(media.children) == 1 - assert media.children[0].title == "Local Media" + assert media.children[0].title == "My media" async def test_async_resolve_media(hass: HomeAssistant) -> None: diff --git a/tests/components/otbr/test_websocket_api.py b/tests/components/otbr/test_websocket_api.py index 1feebe9c02c..65bec9e8408 100644 --- a/tests/components/otbr/test_websocket_api.py +++ b/tests/components/otbr/test_websocket_api.py @@ -84,6 +84,8 @@ async def test_create_network( with patch( "python_otbr_api.OTBR.create_active_dataset" ) as create_dataset_mock, patch( + "python_otbr_api.OTBR.delete_active_dataset" + ) as delete_dataset_mock, patch( "python_otbr_api.OTBR.set_enabled" ) as set_enabled_mock, patch( "python_otbr_api.OTBR.get_active_dataset_tlvs", return_value=DATASET_CH16 @@ -99,6 +101,7 @@ async def test_create_network( create_dataset_mock.assert_called_once_with( python_otbr_api.models.ActiveDataSet(channel=15, network_name="home-assistant") ) + delete_dataset_mock.assert_called_once_with() assert len(set_enabled_mock.mock_calls) == 2 assert set_enabled_mock.mock_calls[0][1][0] is False assert set_enabled_mock.mock_calls[1][1][0] is True @@ -151,7 +154,7 @@ async def test_create_network_fails_2( ), patch( "python_otbr_api.OTBR.create_active_dataset", side_effect=python_otbr_api.OTBRError, - ): + ), patch("python_otbr_api.OTBR.delete_active_dataset"): await websocket_client.send_json_auto_id({"type": "otbr/create_network"}) msg = await websocket_client.receive_json() @@ -171,6 +174,8 @@ async def test_create_network_fails_3( side_effect=[None, python_otbr_api.OTBRError], ), patch( "python_otbr_api.OTBR.create_active_dataset", + ), patch( + "python_otbr_api.OTBR.delete_active_dataset" ): await websocket_client.send_json_auto_id({"type": "otbr/create_network"}) msg = await websocket_client.receive_json() @@ -191,6 +196,8 @@ async def test_create_network_fails_4( ), patch( "python_otbr_api.OTBR.get_active_dataset_tlvs", side_effect=python_otbr_api.OTBRError, + ), patch( + "python_otbr_api.OTBR.delete_active_dataset" ): await websocket_client.send_json_auto_id({"type": "otbr/create_network"}) msg = await websocket_client.receive_json() @@ -208,7 +215,9 @@ async def test_create_network_fails_5( """Test create network.""" with patch("python_otbr_api.OTBR.set_enabled"), patch( "python_otbr_api.OTBR.create_active_dataset" - ), patch("python_otbr_api.OTBR.get_active_dataset_tlvs", return_value=None): + ), patch("python_otbr_api.OTBR.get_active_dataset_tlvs", return_value=None), patch( + "python_otbr_api.OTBR.delete_active_dataset" + ): await websocket_client.send_json_auto_id({"type": "otbr/create_network"}) msg = await websocket_client.receive_json() @@ -216,6 +225,26 @@ async def test_create_network_fails_5( assert msg["error"]["code"] == "get_active_dataset_tlvs_empty" +async def test_create_network_fails_6( + hass: HomeAssistant, + aioclient_mock: AiohttpClientMocker, + otbr_config_entry, + websocket_client, +) -> None: + """Test create network.""" + with patch("python_otbr_api.OTBR.set_enabled"), patch( + "python_otbr_api.OTBR.create_active_dataset" + ), patch("python_otbr_api.OTBR.get_active_dataset_tlvs", return_value=None), patch( + "python_otbr_api.OTBR.delete_active_dataset", + side_effect=python_otbr_api.OTBRError, + ): + await websocket_client.send_json_auto_id({"type": "otbr/create_network"}) + msg = await websocket_client.receive_json() + + assert not msg["success"] + assert msg["error"]["code"] == "delete_active_dataset_failed" + + async def test_set_network( hass: HomeAssistant, aioclient_mock: AiohttpClientMocker, diff --git a/tests/components/roku/test_media_player.py b/tests/components/roku/test_media_player.py index 1363cf7e286..5d4568ce7ac 100644 --- a/tests/components/roku/test_media_player.py +++ b/tests/components/roku/test_media_player.py @@ -864,7 +864,7 @@ async def test_media_browse_local_source( assert msg["result"]["children"][0]["title"] == "Apps" assert msg["result"]["children"][0]["media_content_type"] == MediaType.APPS - assert msg["result"]["children"][1]["title"] == "Local Media" + assert msg["result"]["children"][1]["title"] == "My media" assert msg["result"]["children"][1]["media_class"] == MediaClass.DIRECTORY assert msg["result"]["children"][1]["media_content_type"] is None assert ( @@ -892,7 +892,7 @@ async def test_media_browse_local_source( assert msg["success"] assert msg["result"] - assert msg["result"]["title"] == "Local Media" + assert msg["result"]["title"] == "My media" assert msg["result"]["media_class"] == MediaClass.DIRECTORY assert msg["result"]["media_content_type"] is None assert len(msg["result"]["children"]) == 2