diff --git a/homeassistant/components/enigma2/media_player.py b/homeassistant/components/enigma2/media_player.py index 432823d781bfe8..e4283eeef9dba3 100644 --- a/homeassistant/components/enigma2/media_player.py +++ b/homeassistant/components/enigma2/media_player.py @@ -1,6 +1,7 @@ """Support for Enigma2 media players.""" from __future__ import annotations +from aiohttp.client_exceptions import ClientConnectorError from openwebif.api import OpenWebIfDevice from openwebif.enums import RemoteControlCodes import voluptuous as vol @@ -20,6 +21,7 @@ CONF_USERNAME, ) from homeassistant.core import HomeAssistant +from homeassistant.exceptions import PlatformNotReady import homeassistant.helpers.config_validation as cv from homeassistant.helpers.config_validation import PLATFORM_SCHEMA from homeassistant.helpers.entity_platform import AddEntitiesCallback @@ -96,9 +98,13 @@ async def async_setup_platform( source_bouquet=config.get(CONF_SOURCE_BOUQUET), ) - async_add_entities( - [Enigma2Device(config[CONF_NAME], device, await device.get_about())] - ) + try: + about = await device.get_about() + except ClientConnectorError as err: + await device.close() + raise PlatformNotReady from err + + async_add_entities([Enigma2Device(config[CONF_NAME], device, about)]) class Enigma2Device(MediaPlayerEntity): @@ -169,8 +175,8 @@ async def async_media_next_track(self) -> None: await self._device.send_remote_control_action(RemoteControlCodes.CHANNEL_UP) async def async_media_previous_track(self) -> None: - """Send next track command.""" - self._device.send_remote_control_action(RemoteControlCodes.CHANNEL_DOWN) + """Send previous track command.""" + await self._device.send_remote_control_action(RemoteControlCodes.CHANNEL_DOWN) async def async_mute_volume(self, mute: bool) -> None: """Mute or unmute.""" diff --git a/homeassistant/components/shelly/config_flow.py b/homeassistant/components/shelly/config_flow.py index 29daf05016370e..59ae6eed1965ac 100644 --- a/homeassistant/components/shelly/config_flow.py +++ b/homeassistant/components/shelly/config_flow.py @@ -36,6 +36,7 @@ from .utils import ( get_block_device_sleep_period, get_coap_context, + get_device_entry_gen, get_info_auth, get_info_gen, get_model_name, @@ -322,7 +323,7 @@ async def async_step_reauth_confirm( except (DeviceConnectionError, InvalidAuthError, FirmwareUnsupported): return self.async_abort(reason="reauth_unsuccessful") - if self.entry.data.get(CONF_GEN, 1) != 1: + if get_device_entry_gen(self.entry) != 1: user_input[CONF_USERNAME] = "admin" try: await validate_input(self.hass, host, info, user_input) @@ -335,7 +336,7 @@ async def async_step_reauth_confirm( await self.hass.config_entries.async_reload(self.entry.entry_id) return self.async_abort(reason="reauth_successful") - if self.entry.data.get(CONF_GEN, 1) in BLOCK_GENERATIONS: + if get_device_entry_gen(self.entry) in BLOCK_GENERATIONS: schema = { vol.Required(CONF_USERNAME): str, vol.Required(CONF_PASSWORD): str, @@ -364,7 +365,7 @@ def async_get_options_flow(config_entry: ConfigEntry) -> OptionsFlowHandler: def async_supports_options_flow(cls, config_entry: ConfigEntry) -> bool: """Return options flow support for this handler.""" return ( - config_entry.data.get(CONF_GEN) in RPC_GENERATIONS + get_device_entry_gen(config_entry) in RPC_GENERATIONS and not config_entry.data.get(CONF_SLEEP_PERIOD) and config_entry.data.get("model") != MODEL_WALL_DISPLAY ) diff --git a/homeassistant/components/shelly/coordinator.py b/homeassistant/components/shelly/coordinator.py index 77fa0bd2efd166..7f88cce1134b55 100644 --- a/homeassistant/components/shelly/coordinator.py +++ b/homeassistant/components/shelly/coordinator.py @@ -33,7 +33,6 @@ ATTR_GENERATION, BATTERY_DEVICES_WITH_PERMANENT_CONNECTION, CONF_BLE_SCANNER_MODE, - CONF_GEN, CONF_SLEEP_PERIOD, DATA_CONFIG_ENTRY, DOMAIN, @@ -58,7 +57,11 @@ UPDATE_PERIOD_MULTIPLIER, BLEScannerMode, ) -from .utils import get_rpc_device_wakeup_period, update_device_fw_info +from .utils import ( + get_device_entry_gen, + get_rpc_device_wakeup_period, + update_device_fw_info, +) _DeviceT = TypeVar("_DeviceT", bound="BlockDevice|RpcDevice") @@ -136,7 +139,7 @@ def async_setup(self) -> None: manufacturer="Shelly", model=aioshelly.const.MODEL_NAMES.get(self.model, self.model), sw_version=self.sw_version, - hw_version=f"gen{self.entry.data[CONF_GEN]} ({self.model})", + hw_version=f"gen{get_device_entry_gen(self.entry)} ({self.model})", configuration_url=f"http://{self.entry.data[CONF_HOST]}", ) self.device_id = device_entry.id diff --git a/homeassistant/components/streamlabswater/__init__.py b/homeassistant/components/streamlabswater/__init__.py index 82e8777a7e1ae5..c3bbe5a96d4ee9 100644 --- a/homeassistant/components/streamlabswater/__init__.py +++ b/homeassistant/components/streamlabswater/__init__.py @@ -107,9 +107,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: def set_away_mode(service: ServiceCall) -> None: """Set the StreamLabsWater Away Mode.""" away_mode = service.data.get(ATTR_AWAY_MODE) - location_id = ( - service.data.get(CONF_LOCATION_ID) or list(coordinator.data.values())[0] - ) + location_id = service.data.get(CONF_LOCATION_ID) or list(coordinator.data)[0] client.update_location(location_id, away_mode) hass.services.async_register( diff --git a/homeassistant/components/system_bridge/media_player.py b/homeassistant/components/system_bridge/media_player.py index ea9e8ab070d576..02670d36fe3013 100644 --- a/homeassistant/components/system_bridge/media_player.py +++ b/homeassistant/components/system_bridge/media_player.py @@ -118,10 +118,8 @@ def supported_features(self) -> MediaPlayerEntityFeature: features |= MediaPlayerEntityFeature.PREVIOUS_TRACK if data.media.is_next_enabled: features |= MediaPlayerEntityFeature.NEXT_TRACK - if data.media.is_pause_enabled: - features |= MediaPlayerEntityFeature.PAUSE - if data.media.is_play_enabled: - features |= MediaPlayerEntityFeature.PLAY + if data.media.is_pause_enabled or data.media.is_play_enabled: + features |= MediaPlayerEntityFeature.PAUSE | MediaPlayerEntityFeature.PLAY if data.media.is_stop_enabled: features |= MediaPlayerEntityFeature.STOP diff --git a/homeassistant/components/zha/sensor.py b/homeassistant/components/zha/sensor.py index 027e710e30c762..ea5d09dd6f4d56 100644 --- a/homeassistant/components/zha/sensor.py +++ b/homeassistant/components/zha/sensor.py @@ -216,9 +216,9 @@ async def async_added_to_hass(self) -> None: async def async_will_remove_from_hass(self) -> None: """Disconnect entity object when removed.""" - assert self._cancel_refresh_handle - self._cancel_refresh_handle() - self._cancel_refresh_handle = None + if self._cancel_refresh_handle is not None: + self._cancel_refresh_handle() + self._cancel_refresh_handle = None self.debug("stopped polling during device removal") await super().async_will_remove_from_hass() diff --git a/homeassistant/const.py b/homeassistant/const.py index cea73ec243b47b..c91743e7ba9726 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -16,7 +16,7 @@ APPLICATION_NAME: Final = "HomeAssistant" MAJOR_VERSION: Final = 2024 MINOR_VERSION: Final = 1 -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, 11, 0) diff --git a/pyproject.toml b/pyproject.toml index 3bec11ced3bbe2..bbf45725716efa 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "homeassistant" -version = "2024.1.1" +version = "2024.1.2" license = {text = "Apache-2.0"} description = "Open-source home automation platform running on Python 3." readme = "README.rst" diff --git a/tests/components/shelly/__init__.py b/tests/components/shelly/__init__.py index 0384e9255a38fc..26040e13557796 100644 --- a/tests/components/shelly/__init__.py +++ b/tests/components/shelly/__init__.py @@ -12,6 +12,7 @@ import pytest from homeassistant.components.shelly.const import ( + CONF_GEN, CONF_SLEEP_PERIOD, DOMAIN, REST_SENSORS_UPDATE_INTERVAL, @@ -30,7 +31,7 @@ async def init_integration( hass: HomeAssistant, - gen: int, + gen: int | None, model=MODEL_25, sleep_period=0, options: dict[str, Any] | None = None, @@ -41,8 +42,9 @@ async def init_integration( CONF_HOST: "192.168.1.37", CONF_SLEEP_PERIOD: sleep_period, "model": model, - "gen": gen, } + if gen is not None: + data[CONF_GEN] = gen entry = MockConfigEntry( domain=DOMAIN, data=data, unique_id=MOCK_MAC, options=options diff --git a/tests/components/shelly/test_init.py b/tests/components/shelly/test_init.py index 8f6599b39e46e9..643fc775cc4240 100644 --- a/tests/components/shelly/test_init.py +++ b/tests/components/shelly/test_init.py @@ -301,3 +301,11 @@ async def test_no_attempt_to_stop_scanner_with_sleepy_devices( mock_rpc_device.mock_update() await hass.async_block_till_done() assert not mock_stop_scanner.call_count + + +async def test_entry_missing_gen(hass: HomeAssistant, mock_block_device) -> None: + """Test successful Gen1 device init when gen is missing in entry data.""" + entry = await init_integration(hass, None) + + assert entry.state is ConfigEntryState.LOADED + assert hass.states.get("switch.test_name_channel_1").state is STATE_ON