mirror of
https://github.com/home-assistant/core.git
synced 2025-07-28 07:37:34 +00:00
2024.1.2 (#107365)
This commit is contained in:
commit
4eddbe7b47
@ -1,6 +1,7 @@
|
|||||||
"""Support for Enigma2 media players."""
|
"""Support for Enigma2 media players."""
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from aiohttp.client_exceptions import ClientConnectorError
|
||||||
from openwebif.api import OpenWebIfDevice
|
from openwebif.api import OpenWebIfDevice
|
||||||
from openwebif.enums import RemoteControlCodes
|
from openwebif.enums import RemoteControlCodes
|
||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
@ -20,6 +21,7 @@ from homeassistant.const import (
|
|||||||
CONF_USERNAME,
|
CONF_USERNAME,
|
||||||
)
|
)
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
|
from homeassistant.exceptions import PlatformNotReady
|
||||||
import homeassistant.helpers.config_validation as cv
|
import homeassistant.helpers.config_validation as cv
|
||||||
from homeassistant.helpers.config_validation import PLATFORM_SCHEMA
|
from homeassistant.helpers.config_validation import PLATFORM_SCHEMA
|
||||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
@ -96,9 +98,13 @@ async def async_setup_platform(
|
|||||||
source_bouquet=config.get(CONF_SOURCE_BOUQUET),
|
source_bouquet=config.get(CONF_SOURCE_BOUQUET),
|
||||||
)
|
)
|
||||||
|
|
||||||
async_add_entities(
|
try:
|
||||||
[Enigma2Device(config[CONF_NAME], device, await device.get_about())]
|
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):
|
class Enigma2Device(MediaPlayerEntity):
|
||||||
@ -169,8 +175,8 @@ class Enigma2Device(MediaPlayerEntity):
|
|||||||
await self._device.send_remote_control_action(RemoteControlCodes.CHANNEL_UP)
|
await self._device.send_remote_control_action(RemoteControlCodes.CHANNEL_UP)
|
||||||
|
|
||||||
async def async_media_previous_track(self) -> None:
|
async def async_media_previous_track(self) -> None:
|
||||||
"""Send next track command."""
|
"""Send previous track command."""
|
||||||
self._device.send_remote_control_action(RemoteControlCodes.CHANNEL_DOWN)
|
await self._device.send_remote_control_action(RemoteControlCodes.CHANNEL_DOWN)
|
||||||
|
|
||||||
async def async_mute_volume(self, mute: bool) -> None:
|
async def async_mute_volume(self, mute: bool) -> None:
|
||||||
"""Mute or unmute."""
|
"""Mute or unmute."""
|
||||||
|
@ -36,6 +36,7 @@ from .coordinator import async_reconnect_soon
|
|||||||
from .utils import (
|
from .utils import (
|
||||||
get_block_device_sleep_period,
|
get_block_device_sleep_period,
|
||||||
get_coap_context,
|
get_coap_context,
|
||||||
|
get_device_entry_gen,
|
||||||
get_info_auth,
|
get_info_auth,
|
||||||
get_info_gen,
|
get_info_gen,
|
||||||
get_model_name,
|
get_model_name,
|
||||||
@ -322,7 +323,7 @@ class ShellyConfigFlow(ConfigFlow, domain=DOMAIN):
|
|||||||
except (DeviceConnectionError, InvalidAuthError, FirmwareUnsupported):
|
except (DeviceConnectionError, InvalidAuthError, FirmwareUnsupported):
|
||||||
return self.async_abort(reason="reauth_unsuccessful")
|
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"
|
user_input[CONF_USERNAME] = "admin"
|
||||||
try:
|
try:
|
||||||
await validate_input(self.hass, host, info, user_input)
|
await validate_input(self.hass, host, info, user_input)
|
||||||
@ -335,7 +336,7 @@ class ShellyConfigFlow(ConfigFlow, domain=DOMAIN):
|
|||||||
await self.hass.config_entries.async_reload(self.entry.entry_id)
|
await self.hass.config_entries.async_reload(self.entry.entry_id)
|
||||||
return self.async_abort(reason="reauth_successful")
|
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 = {
|
schema = {
|
||||||
vol.Required(CONF_USERNAME): str,
|
vol.Required(CONF_USERNAME): str,
|
||||||
vol.Required(CONF_PASSWORD): str,
|
vol.Required(CONF_PASSWORD): str,
|
||||||
@ -364,7 +365,7 @@ class ShellyConfigFlow(ConfigFlow, domain=DOMAIN):
|
|||||||
def async_supports_options_flow(cls, config_entry: ConfigEntry) -> bool:
|
def async_supports_options_flow(cls, config_entry: ConfigEntry) -> bool:
|
||||||
"""Return options flow support for this handler."""
|
"""Return options flow support for this handler."""
|
||||||
return (
|
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 not config_entry.data.get(CONF_SLEEP_PERIOD)
|
||||||
and config_entry.data.get("model") != MODEL_WALL_DISPLAY
|
and config_entry.data.get("model") != MODEL_WALL_DISPLAY
|
||||||
)
|
)
|
||||||
|
@ -33,7 +33,6 @@ from .const import (
|
|||||||
ATTR_GENERATION,
|
ATTR_GENERATION,
|
||||||
BATTERY_DEVICES_WITH_PERMANENT_CONNECTION,
|
BATTERY_DEVICES_WITH_PERMANENT_CONNECTION,
|
||||||
CONF_BLE_SCANNER_MODE,
|
CONF_BLE_SCANNER_MODE,
|
||||||
CONF_GEN,
|
|
||||||
CONF_SLEEP_PERIOD,
|
CONF_SLEEP_PERIOD,
|
||||||
DATA_CONFIG_ENTRY,
|
DATA_CONFIG_ENTRY,
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
@ -58,7 +57,11 @@ from .const import (
|
|||||||
UPDATE_PERIOD_MULTIPLIER,
|
UPDATE_PERIOD_MULTIPLIER,
|
||||||
BLEScannerMode,
|
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")
|
_DeviceT = TypeVar("_DeviceT", bound="BlockDevice|RpcDevice")
|
||||||
|
|
||||||
@ -136,7 +139,7 @@ class ShellyCoordinatorBase(DataUpdateCoordinator[None], Generic[_DeviceT]):
|
|||||||
manufacturer="Shelly",
|
manufacturer="Shelly",
|
||||||
model=aioshelly.const.MODEL_NAMES.get(self.model, self.model),
|
model=aioshelly.const.MODEL_NAMES.get(self.model, self.model),
|
||||||
sw_version=self.sw_version,
|
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]}",
|
configuration_url=f"http://{self.entry.data[CONF_HOST]}",
|
||||||
)
|
)
|
||||||
self.device_id = device_entry.id
|
self.device_id = device_entry.id
|
||||||
|
@ -107,9 +107,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
|||||||
def set_away_mode(service: ServiceCall) -> None:
|
def set_away_mode(service: ServiceCall) -> None:
|
||||||
"""Set the StreamLabsWater Away Mode."""
|
"""Set the StreamLabsWater Away Mode."""
|
||||||
away_mode = service.data.get(ATTR_AWAY_MODE)
|
away_mode = service.data.get(ATTR_AWAY_MODE)
|
||||||
location_id = (
|
location_id = service.data.get(CONF_LOCATION_ID) or list(coordinator.data)[0]
|
||||||
service.data.get(CONF_LOCATION_ID) or list(coordinator.data.values())[0]
|
|
||||||
)
|
|
||||||
client.update_location(location_id, away_mode)
|
client.update_location(location_id, away_mode)
|
||||||
|
|
||||||
hass.services.async_register(
|
hass.services.async_register(
|
||||||
|
@ -118,10 +118,8 @@ class SystemBridgeMediaPlayer(SystemBridgeEntity, MediaPlayerEntity):
|
|||||||
features |= MediaPlayerEntityFeature.PREVIOUS_TRACK
|
features |= MediaPlayerEntityFeature.PREVIOUS_TRACK
|
||||||
if data.media.is_next_enabled:
|
if data.media.is_next_enabled:
|
||||||
features |= MediaPlayerEntityFeature.NEXT_TRACK
|
features |= MediaPlayerEntityFeature.NEXT_TRACK
|
||||||
if data.media.is_pause_enabled:
|
if data.media.is_pause_enabled or data.media.is_play_enabled:
|
||||||
features |= MediaPlayerEntityFeature.PAUSE
|
features |= MediaPlayerEntityFeature.PAUSE | MediaPlayerEntityFeature.PLAY
|
||||||
if data.media.is_play_enabled:
|
|
||||||
features |= MediaPlayerEntityFeature.PLAY
|
|
||||||
if data.media.is_stop_enabled:
|
if data.media.is_stop_enabled:
|
||||||
features |= MediaPlayerEntityFeature.STOP
|
features |= MediaPlayerEntityFeature.STOP
|
||||||
|
|
||||||
|
@ -216,9 +216,9 @@ class PollableSensor(Sensor):
|
|||||||
|
|
||||||
async def async_will_remove_from_hass(self) -> None:
|
async def async_will_remove_from_hass(self) -> None:
|
||||||
"""Disconnect entity object when removed."""
|
"""Disconnect entity object when removed."""
|
||||||
assert self._cancel_refresh_handle
|
if self._cancel_refresh_handle is not None:
|
||||||
self._cancel_refresh_handle()
|
self._cancel_refresh_handle()
|
||||||
self._cancel_refresh_handle = None
|
self._cancel_refresh_handle = None
|
||||||
self.debug("stopped polling during device removal")
|
self.debug("stopped polling during device removal")
|
||||||
await super().async_will_remove_from_hass()
|
await super().async_will_remove_from_hass()
|
||||||
|
|
||||||
|
@ -16,7 +16,7 @@ from .helpers.deprecation import (
|
|||||||
APPLICATION_NAME: Final = "HomeAssistant"
|
APPLICATION_NAME: Final = "HomeAssistant"
|
||||||
MAJOR_VERSION: Final = 2024
|
MAJOR_VERSION: Final = 2024
|
||||||
MINOR_VERSION: Final = 1
|
MINOR_VERSION: Final = 1
|
||||||
PATCH_VERSION: Final = "1"
|
PATCH_VERSION: Final = "2"
|
||||||
__short_version__: Final = f"{MAJOR_VERSION}.{MINOR_VERSION}"
|
__short_version__: Final = f"{MAJOR_VERSION}.{MINOR_VERSION}"
|
||||||
__version__: Final = f"{__short_version__}.{PATCH_VERSION}"
|
__version__: Final = f"{__short_version__}.{PATCH_VERSION}"
|
||||||
REQUIRED_PYTHON_VER: Final[tuple[int, int, int]] = (3, 11, 0)
|
REQUIRED_PYTHON_VER: Final[tuple[int, int, int]] = (3, 11, 0)
|
||||||
|
@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|||||||
|
|
||||||
[project]
|
[project]
|
||||||
name = "homeassistant"
|
name = "homeassistant"
|
||||||
version = "2024.1.1"
|
version = "2024.1.2"
|
||||||
license = {text = "Apache-2.0"}
|
license = {text = "Apache-2.0"}
|
||||||
description = "Open-source home automation platform running on Python 3."
|
description = "Open-source home automation platform running on Python 3."
|
||||||
readme = "README.rst"
|
readme = "README.rst"
|
||||||
|
@ -12,6 +12,7 @@ from freezegun.api import FrozenDateTimeFactory
|
|||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from homeassistant.components.shelly.const import (
|
from homeassistant.components.shelly.const import (
|
||||||
|
CONF_GEN,
|
||||||
CONF_SLEEP_PERIOD,
|
CONF_SLEEP_PERIOD,
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
REST_SENSORS_UPDATE_INTERVAL,
|
REST_SENSORS_UPDATE_INTERVAL,
|
||||||
@ -30,7 +31,7 @@ MOCK_MAC = "123456789ABC"
|
|||||||
|
|
||||||
async def init_integration(
|
async def init_integration(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
gen: int,
|
gen: int | None,
|
||||||
model=MODEL_25,
|
model=MODEL_25,
|
||||||
sleep_period=0,
|
sleep_period=0,
|
||||||
options: dict[str, Any] | None = None,
|
options: dict[str, Any] | None = None,
|
||||||
@ -41,8 +42,9 @@ async def init_integration(
|
|||||||
CONF_HOST: "192.168.1.37",
|
CONF_HOST: "192.168.1.37",
|
||||||
CONF_SLEEP_PERIOD: sleep_period,
|
CONF_SLEEP_PERIOD: sleep_period,
|
||||||
"model": model,
|
"model": model,
|
||||||
"gen": gen,
|
|
||||||
}
|
}
|
||||||
|
if gen is not None:
|
||||||
|
data[CONF_GEN] = gen
|
||||||
|
|
||||||
entry = MockConfigEntry(
|
entry = MockConfigEntry(
|
||||||
domain=DOMAIN, data=data, unique_id=MOCK_MAC, options=options
|
domain=DOMAIN, data=data, unique_id=MOCK_MAC, options=options
|
||||||
|
@ -301,3 +301,11 @@ async def test_no_attempt_to_stop_scanner_with_sleepy_devices(
|
|||||||
mock_rpc_device.mock_update()
|
mock_rpc_device.mock_update()
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
assert not mock_stop_scanner.call_count
|
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
|
||||||
|
Loading…
x
Reference in New Issue
Block a user