mirror of
https://github.com/home-assistant/core.git
synced 2025-07-13 16:27:08 +00:00
Bump aioshelly to 9.0.0 (#114025)
* Update Shelly to use initialize from aioshelly * Save indentation in _async_device_connect * Use firmware_supported property from aioshelly * Review comments * Bump aioshelly * Fix lint errors * Test RPC initialized update
This commit is contained in:
parent
33412dd9f6
commit
291df6dafe
@ -3,23 +3,22 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import contextlib
|
import contextlib
|
||||||
from typing import Any, Final
|
from typing import Final
|
||||||
|
|
||||||
from aioshelly.block_device import BlockDevice, BlockUpdateType
|
from aioshelly.block_device import BlockDevice
|
||||||
from aioshelly.common import ConnectionOptions
|
from aioshelly.common import ConnectionOptions
|
||||||
from aioshelly.const import DEFAULT_COAP_PORT, RPC_GENERATIONS
|
from aioshelly.const import DEFAULT_COAP_PORT, RPC_GENERATIONS
|
||||||
from aioshelly.exceptions import (
|
from aioshelly.exceptions import (
|
||||||
DeviceConnectionError,
|
DeviceConnectionError,
|
||||||
FirmwareUnsupported,
|
|
||||||
InvalidAuthError,
|
InvalidAuthError,
|
||||||
MacAddressMismatchError,
|
MacAddressMismatchError,
|
||||||
)
|
)
|
||||||
from aioshelly.rpc_device import RpcDevice, RpcUpdateType
|
from aioshelly.rpc_device import RpcDevice
|
||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
|
|
||||||
from homeassistant.config_entries import ConfigEntry
|
from homeassistant.config_entries import ConfigEntry
|
||||||
from homeassistant.const import CONF_HOST, CONF_PASSWORD, CONF_USERNAME, Platform
|
from homeassistant.const import CONF_HOST, CONF_PASSWORD, CONF_USERNAME, Platform
|
||||||
from homeassistant.core import HomeAssistant, callback
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.exceptions import ConfigEntryAuthFailed, ConfigEntryNotReady
|
from homeassistant.exceptions import ConfigEntryAuthFailed, ConfigEntryNotReady
|
||||||
from homeassistant.helpers import issue_registry as ir
|
from homeassistant.helpers import issue_registry as ir
|
||||||
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
||||||
@ -53,12 +52,9 @@ from .coordinator import (
|
|||||||
)
|
)
|
||||||
from .utils import (
|
from .utils import (
|
||||||
async_create_issue_unsupported_firmware,
|
async_create_issue_unsupported_firmware,
|
||||||
async_shutdown_device,
|
|
||||||
get_block_device_sleep_period,
|
|
||||||
get_coap_context,
|
get_coap_context,
|
||||||
get_device_entry_gen,
|
get_device_entry_gen,
|
||||||
get_http_port,
|
get_http_port,
|
||||||
get_rpc_device_wakeup_period,
|
|
||||||
get_ws_context,
|
get_ws_context,
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -154,7 +150,6 @@ async def _async_setup_block_entry(hass: HomeAssistant, entry: ConfigEntry) -> b
|
|||||||
async_get_clientsession(hass),
|
async_get_clientsession(hass),
|
||||||
coap_context,
|
coap_context,
|
||||||
options,
|
options,
|
||||||
False,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
dev_reg = dr_async_get(hass)
|
dev_reg = dr_async_get(hass)
|
||||||
@ -186,57 +181,38 @@ async def _async_setup_block_entry(hass: HomeAssistant, entry: ConfigEntry) -> b
|
|||||||
data[CONF_SLEEP_PERIOD] = sleep_period = BLOCK_EXPECTED_SLEEP_PERIOD
|
data[CONF_SLEEP_PERIOD] = sleep_period = BLOCK_EXPECTED_SLEEP_PERIOD
|
||||||
hass.config_entries.async_update_entry(entry, data=data)
|
hass.config_entries.async_update_entry(entry, data=data)
|
||||||
|
|
||||||
async def _async_block_device_setup() -> None:
|
|
||||||
"""Set up a block based device that is online."""
|
|
||||||
shelly_entry_data.block = ShellyBlockCoordinator(hass, entry, device)
|
|
||||||
shelly_entry_data.block.async_setup()
|
|
||||||
|
|
||||||
platforms = BLOCK_SLEEPING_PLATFORMS
|
|
||||||
|
|
||||||
if not entry.data.get(CONF_SLEEP_PERIOD):
|
|
||||||
shelly_entry_data.rest = ShellyRestCoordinator(hass, device, entry)
|
|
||||||
platforms = BLOCK_PLATFORMS
|
|
||||||
|
|
||||||
await hass.config_entries.async_forward_entry_setups(entry, platforms)
|
|
||||||
|
|
||||||
@callback
|
|
||||||
def _async_device_online(_: Any, update_type: BlockUpdateType) -> None:
|
|
||||||
LOGGER.debug("Device %s is online, resuming setup", entry.title)
|
|
||||||
shelly_entry_data.device = None
|
|
||||||
|
|
||||||
if sleep_period is None:
|
|
||||||
data = {**entry.data}
|
|
||||||
data[CONF_SLEEP_PERIOD] = get_block_device_sleep_period(device.settings)
|
|
||||||
data["model"] = device.settings["device"]["type"]
|
|
||||||
hass.config_entries.async_update_entry(entry, data=data)
|
|
||||||
|
|
||||||
hass.async_create_task(_async_block_device_setup(), eager_start=True)
|
|
||||||
|
|
||||||
if sleep_period == 0:
|
if sleep_period == 0:
|
||||||
# Not a sleeping device, finish setup
|
# Not a sleeping device, finish setup
|
||||||
LOGGER.debug("Setting up online block device %s", entry.title)
|
LOGGER.debug("Setting up online block device %s", entry.title)
|
||||||
try:
|
try:
|
||||||
await device.initialize()
|
await device.initialize()
|
||||||
|
if not device.firmware_supported:
|
||||||
|
async_create_issue_unsupported_firmware(hass, entry)
|
||||||
|
raise ConfigEntryNotReady
|
||||||
except (DeviceConnectionError, MacAddressMismatchError) as err:
|
except (DeviceConnectionError, MacAddressMismatchError) as err:
|
||||||
raise ConfigEntryNotReady(repr(err)) from err
|
raise ConfigEntryNotReady(repr(err)) from err
|
||||||
except InvalidAuthError as err:
|
except InvalidAuthError as err:
|
||||||
raise ConfigEntryAuthFailed(repr(err)) from err
|
raise ConfigEntryAuthFailed(repr(err)) from err
|
||||||
except FirmwareUnsupported as err:
|
|
||||||
async_create_issue_unsupported_firmware(hass, entry)
|
|
||||||
raise ConfigEntryNotReady from err
|
|
||||||
|
|
||||||
await _async_block_device_setup()
|
shelly_entry_data.block = ShellyBlockCoordinator(hass, entry, device)
|
||||||
|
shelly_entry_data.block.async_setup()
|
||||||
|
shelly_entry_data.rest = ShellyRestCoordinator(hass, device, entry)
|
||||||
|
await hass.config_entries.async_forward_entry_setups(entry, BLOCK_PLATFORMS)
|
||||||
elif sleep_period is None or device_entry is None:
|
elif sleep_period is None or device_entry is None:
|
||||||
# Need to get sleep info or first time sleeping device setup, wait for device
|
# Need to get sleep info or first time sleeping device setup, wait for device
|
||||||
shelly_entry_data.device = device
|
|
||||||
LOGGER.debug(
|
LOGGER.debug(
|
||||||
"Setup for device %s will resume when device is online", entry.title
|
"Setup for device %s will resume when device is online", entry.title
|
||||||
)
|
)
|
||||||
device.subscribe_updates(_async_device_online)
|
shelly_entry_data.block = ShellyBlockCoordinator(hass, entry, device)
|
||||||
|
shelly_entry_data.block.async_setup(BLOCK_SLEEPING_PLATFORMS)
|
||||||
else:
|
else:
|
||||||
# Restore sensors for sleeping device
|
# Restore sensors for sleeping device
|
||||||
LOGGER.debug("Setting up offline block device %s", entry.title)
|
LOGGER.debug("Setting up offline block device %s", entry.title)
|
||||||
await _async_block_device_setup()
|
shelly_entry_data.block = ShellyBlockCoordinator(hass, entry, device)
|
||||||
|
shelly_entry_data.block.async_setup()
|
||||||
|
await hass.config_entries.async_forward_entry_setups(
|
||||||
|
entry, BLOCK_SLEEPING_PLATFORMS
|
||||||
|
)
|
||||||
|
|
||||||
ir.async_delete_issue(
|
ir.async_delete_issue(
|
||||||
hass, DOMAIN, FIRMWARE_UNSUPPORTED_ISSUE_ID.format(unique=entry.unique_id)
|
hass, DOMAIN, FIRMWARE_UNSUPPORTED_ISSUE_ID.format(unique=entry.unique_id)
|
||||||
@ -260,7 +236,6 @@ async def _async_setup_rpc_entry(hass: HomeAssistant, entry: ConfigEntry) -> boo
|
|||||||
async_get_clientsession(hass),
|
async_get_clientsession(hass),
|
||||||
ws_context,
|
ws_context,
|
||||||
options,
|
options,
|
||||||
False,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
dev_reg = dr_async_get(hass)
|
dev_reg = dr_async_get(hass)
|
||||||
@ -276,58 +251,38 @@ async def _async_setup_rpc_entry(hass: HomeAssistant, entry: ConfigEntry) -> boo
|
|||||||
sleep_period = entry.data.get(CONF_SLEEP_PERIOD)
|
sleep_period = entry.data.get(CONF_SLEEP_PERIOD)
|
||||||
shelly_entry_data = get_entry_data(hass)[entry.entry_id]
|
shelly_entry_data = get_entry_data(hass)[entry.entry_id]
|
||||||
|
|
||||||
async def _async_rpc_device_setup() -> None:
|
|
||||||
"""Set up a RPC based device that is online."""
|
|
||||||
shelly_entry_data.rpc = ShellyRpcCoordinator(hass, entry, device)
|
|
||||||
shelly_entry_data.rpc.async_setup()
|
|
||||||
|
|
||||||
platforms = RPC_SLEEPING_PLATFORMS
|
|
||||||
|
|
||||||
if not entry.data.get(CONF_SLEEP_PERIOD):
|
|
||||||
shelly_entry_data.rpc_poll = ShellyRpcPollingCoordinator(
|
|
||||||
hass, entry, device
|
|
||||||
)
|
|
||||||
platforms = RPC_PLATFORMS
|
|
||||||
|
|
||||||
await hass.config_entries.async_forward_entry_setups(entry, platforms)
|
|
||||||
|
|
||||||
@callback
|
|
||||||
def _async_device_online(_: Any, update_type: RpcUpdateType) -> None:
|
|
||||||
LOGGER.debug("Device %s is online, resuming setup", entry.title)
|
|
||||||
shelly_entry_data.device = None
|
|
||||||
|
|
||||||
if sleep_period is None:
|
|
||||||
data = {**entry.data}
|
|
||||||
data[CONF_SLEEP_PERIOD] = get_rpc_device_wakeup_period(device.status)
|
|
||||||
hass.config_entries.async_update_entry(entry, data=data)
|
|
||||||
|
|
||||||
hass.async_create_task(_async_rpc_device_setup(), eager_start=True)
|
|
||||||
|
|
||||||
if sleep_period == 0:
|
if sleep_period == 0:
|
||||||
# Not a sleeping device, finish setup
|
# Not a sleeping device, finish setup
|
||||||
LOGGER.debug("Setting up online RPC device %s", entry.title)
|
LOGGER.debug("Setting up online RPC device %s", entry.title)
|
||||||
try:
|
try:
|
||||||
await device.initialize()
|
await device.initialize()
|
||||||
except FirmwareUnsupported as err:
|
if not device.firmware_supported:
|
||||||
async_create_issue_unsupported_firmware(hass, entry)
|
async_create_issue_unsupported_firmware(hass, entry)
|
||||||
raise ConfigEntryNotReady from err
|
raise ConfigEntryNotReady
|
||||||
except (DeviceConnectionError, MacAddressMismatchError) as err:
|
except (DeviceConnectionError, MacAddressMismatchError) as err:
|
||||||
raise ConfigEntryNotReady(repr(err)) from err
|
raise ConfigEntryNotReady(repr(err)) from err
|
||||||
except InvalidAuthError as err:
|
except InvalidAuthError as err:
|
||||||
raise ConfigEntryAuthFailed(repr(err)) from err
|
raise ConfigEntryAuthFailed(repr(err)) from err
|
||||||
|
|
||||||
await _async_rpc_device_setup()
|
shelly_entry_data.rpc = ShellyRpcCoordinator(hass, entry, device)
|
||||||
|
shelly_entry_data.rpc.async_setup()
|
||||||
|
shelly_entry_data.rpc_poll = ShellyRpcPollingCoordinator(hass, entry, device)
|
||||||
|
await hass.config_entries.async_forward_entry_setups(entry, RPC_PLATFORMS)
|
||||||
elif sleep_period is None or device_entry is None:
|
elif sleep_period is None or device_entry is None:
|
||||||
# Need to get sleep info or first time sleeping device setup, wait for device
|
# Need to get sleep info or first time sleeping device setup, wait for device
|
||||||
shelly_entry_data.device = device
|
|
||||||
LOGGER.debug(
|
LOGGER.debug(
|
||||||
"Setup for device %s will resume when device is online", entry.title
|
"Setup for device %s will resume when device is online", entry.title
|
||||||
)
|
)
|
||||||
device.subscribe_updates(_async_device_online)
|
shelly_entry_data.rpc = ShellyRpcCoordinator(hass, entry, device)
|
||||||
|
shelly_entry_data.rpc.async_setup(RPC_SLEEPING_PLATFORMS)
|
||||||
else:
|
else:
|
||||||
# Restore sensors for sleeping device
|
# Restore sensors for sleeping device
|
||||||
LOGGER.debug("Setting up offline block device %s", entry.title)
|
LOGGER.debug("Setting up offline RPC device %s", entry.title)
|
||||||
await _async_rpc_device_setup()
|
shelly_entry_data.rpc = ShellyRpcCoordinator(hass, entry, device)
|
||||||
|
shelly_entry_data.rpc.async_setup()
|
||||||
|
await hass.config_entries.async_forward_entry_setups(
|
||||||
|
entry, RPC_SLEEPING_PLATFORMS
|
||||||
|
)
|
||||||
|
|
||||||
ir.async_delete_issue(
|
ir.async_delete_issue(
|
||||||
hass, DOMAIN, FIRMWARE_UNSUPPORTED_ISSUE_ID.format(unique=entry.unique_id)
|
hass, DOMAIN, FIRMWARE_UNSUPPORTED_ISSUE_ID.format(unique=entry.unique_id)
|
||||||
@ -339,11 +294,6 @@ async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
|||||||
"""Unload a config entry."""
|
"""Unload a config entry."""
|
||||||
shelly_entry_data = get_entry_data(hass)[entry.entry_id]
|
shelly_entry_data = get_entry_data(hass)[entry.entry_id]
|
||||||
|
|
||||||
# If device is present, block/rpc coordinator is not setup yet
|
|
||||||
if (device := shelly_entry_data.device) is not None:
|
|
||||||
await async_shutdown_device(device)
|
|
||||||
return True
|
|
||||||
|
|
||||||
platforms = RPC_SLEEPING_PLATFORMS
|
platforms = RPC_SLEEPING_PLATFORMS
|
||||||
if not entry.data.get(CONF_SLEEP_PERIOD):
|
if not entry.data.get(CONF_SLEEP_PERIOD):
|
||||||
platforms = RPC_PLATFORMS
|
platforms = RPC_PLATFORMS
|
||||||
|
@ -11,7 +11,6 @@ from aioshelly.const import BLOCK_GENERATIONS, DEFAULT_HTTP_PORT, RPC_GENERATION
|
|||||||
from aioshelly.exceptions import (
|
from aioshelly.exceptions import (
|
||||||
CustomPortNotSupported,
|
CustomPortNotSupported,
|
||||||
DeviceConnectionError,
|
DeviceConnectionError,
|
||||||
FirmwareUnsupported,
|
|
||||||
InvalidAuthError,
|
InvalidAuthError,
|
||||||
)
|
)
|
||||||
from aioshelly.rpc_device import RpcDevice
|
from aioshelly.rpc_device import RpcDevice
|
||||||
@ -103,6 +102,7 @@ async def validate_input(
|
|||||||
ws_context,
|
ws_context,
|
||||||
options,
|
options,
|
||||||
)
|
)
|
||||||
|
await rpc_device.initialize()
|
||||||
await rpc_device.shutdown()
|
await rpc_device.shutdown()
|
||||||
|
|
||||||
sleep_period = get_rpc_device_wakeup_period(rpc_device.status)
|
sleep_period = get_rpc_device_wakeup_period(rpc_device.status)
|
||||||
@ -121,6 +121,7 @@ async def validate_input(
|
|||||||
coap_context,
|
coap_context,
|
||||||
options,
|
options,
|
||||||
)
|
)
|
||||||
|
await block_device.initialize()
|
||||||
block_device.shutdown()
|
block_device.shutdown()
|
||||||
return {
|
return {
|
||||||
"title": block_device.name,
|
"title": block_device.name,
|
||||||
@ -154,8 +155,6 @@ class ShellyConfigFlow(ConfigFlow, domain=DOMAIN):
|
|||||||
self.info = await self._async_get_info(host, port)
|
self.info = await self._async_get_info(host, port)
|
||||||
except DeviceConnectionError:
|
except DeviceConnectionError:
|
||||||
errors["base"] = "cannot_connect"
|
errors["base"] = "cannot_connect"
|
||||||
except FirmwareUnsupported:
|
|
||||||
return self.async_abort(reason="unsupported_firmware")
|
|
||||||
except Exception: # pylint: disable=broad-except
|
except Exception: # pylint: disable=broad-except
|
||||||
LOGGER.exception("Unexpected exception")
|
LOGGER.exception("Unexpected exception")
|
||||||
errors["base"] = "unknown"
|
errors["base"] = "unknown"
|
||||||
@ -287,8 +286,6 @@ class ShellyConfigFlow(ConfigFlow, domain=DOMAIN):
|
|||||||
self.info = await self._async_get_info(host, DEFAULT_HTTP_PORT)
|
self.info = await self._async_get_info(host, DEFAULT_HTTP_PORT)
|
||||||
except DeviceConnectionError:
|
except DeviceConnectionError:
|
||||||
return self.async_abort(reason="cannot_connect")
|
return self.async_abort(reason="cannot_connect")
|
||||||
except FirmwareUnsupported:
|
|
||||||
return self.async_abort(reason="unsupported_firmware")
|
|
||||||
|
|
||||||
if not mac:
|
if not mac:
|
||||||
# We could not get the mac address from the name
|
# We could not get the mac address from the name
|
||||||
@ -366,14 +363,14 @@ class ShellyConfigFlow(ConfigFlow, domain=DOMAIN):
|
|||||||
if user_input is not None:
|
if user_input is not None:
|
||||||
try:
|
try:
|
||||||
info = await self._async_get_info(host, port)
|
info = await self._async_get_info(host, port)
|
||||||
except (DeviceConnectionError, InvalidAuthError, FirmwareUnsupported):
|
except (DeviceConnectionError, InvalidAuthError):
|
||||||
return self.async_abort(reason="reauth_unsuccessful")
|
return self.async_abort(reason="reauth_unsuccessful")
|
||||||
|
|
||||||
if get_device_entry_gen(self.entry) != 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, port, info, user_input)
|
await validate_input(self.hass, host, port, info, user_input)
|
||||||
except (DeviceConnectionError, InvalidAuthError, FirmwareUnsupported):
|
except (DeviceConnectionError, InvalidAuthError):
|
||||||
return self.async_abort(reason="reauth_unsuccessful")
|
return self.async_abort(reason="reauth_unsuccessful")
|
||||||
|
|
||||||
return self.async_update_reload_and_abort(
|
return self.async_update_reload_and_abort(
|
||||||
|
@ -15,7 +15,12 @@ from aioshelly.exceptions import DeviceConnectionError, InvalidAuthError, RpcCal
|
|||||||
from aioshelly.rpc_device import RpcDevice, RpcUpdateType
|
from aioshelly.rpc_device import RpcDevice, RpcUpdateType
|
||||||
|
|
||||||
from homeassistant.config_entries import ConfigEntry, ConfigEntryState
|
from homeassistant.config_entries import ConfigEntry, ConfigEntryState
|
||||||
from homeassistant.const import ATTR_DEVICE_ID, CONF_HOST, EVENT_HOMEASSISTANT_STOP
|
from homeassistant.const import (
|
||||||
|
ATTR_DEVICE_ID,
|
||||||
|
CONF_HOST,
|
||||||
|
EVENT_HOMEASSISTANT_STOP,
|
||||||
|
Platform,
|
||||||
|
)
|
||||||
from homeassistant.core import CALLBACK_TYPE, Event, HomeAssistant, callback
|
from homeassistant.core import CALLBACK_TYPE, Event, HomeAssistant, callback
|
||||||
from homeassistant.helpers import issue_registry as ir
|
from homeassistant.helpers import issue_registry as ir
|
||||||
from homeassistant.helpers.debounce import Debouncer
|
from homeassistant.helpers.debounce import Debouncer
|
||||||
@ -58,7 +63,9 @@ from .const import (
|
|||||||
BLEScannerMode,
|
BLEScannerMode,
|
||||||
)
|
)
|
||||||
from .utils import (
|
from .utils import (
|
||||||
|
async_create_issue_unsupported_firmware,
|
||||||
async_shutdown_device,
|
async_shutdown_device,
|
||||||
|
get_block_device_sleep_period,
|
||||||
get_device_entry_gen,
|
get_device_entry_gen,
|
||||||
get_http_port,
|
get_http_port,
|
||||||
get_rpc_device_wakeup_period,
|
get_rpc_device_wakeup_period,
|
||||||
@ -73,7 +80,6 @@ class ShellyEntryData:
|
|||||||
"""Class for sharing data within a given config entry."""
|
"""Class for sharing data within a given config entry."""
|
||||||
|
|
||||||
block: ShellyBlockCoordinator | None = None
|
block: ShellyBlockCoordinator | None = None
|
||||||
device: BlockDevice | RpcDevice | None = None
|
|
||||||
rest: ShellyRestCoordinator | None = None
|
rest: ShellyRestCoordinator | None = None
|
||||||
rpc: ShellyRpcCoordinator | None = None
|
rpc: ShellyRpcCoordinator | None = None
|
||||||
rpc_poll: ShellyRpcPollingCoordinator | None = None
|
rpc_poll: ShellyRpcPollingCoordinator | None = None
|
||||||
@ -98,6 +104,7 @@ class ShellyCoordinatorBase(DataUpdateCoordinator[None], Generic[_DeviceT]):
|
|||||||
self.entry = entry
|
self.entry = entry
|
||||||
self.device = device
|
self.device = device
|
||||||
self.device_id: str | None = None
|
self.device_id: str | None = None
|
||||||
|
self._pending_platforms: list[Platform] | None = None
|
||||||
device_name = device.name if device.initialized else entry.title
|
device_name = device.name if device.initialized else entry.title
|
||||||
interval_td = timedelta(seconds=update_interval)
|
interval_td = timedelta(seconds=update_interval)
|
||||||
super().__init__(hass, LOGGER, name=device_name, update_interval=interval_td)
|
super().__init__(hass, LOGGER, name=device_name, update_interval=interval_td)
|
||||||
@ -131,8 +138,9 @@ class ShellyCoordinatorBase(DataUpdateCoordinator[None], Generic[_DeviceT]):
|
|||||||
"""Sleep period of the device."""
|
"""Sleep period of the device."""
|
||||||
return self.entry.data.get(CONF_SLEEP_PERIOD, 0)
|
return self.entry.data.get(CONF_SLEEP_PERIOD, 0)
|
||||||
|
|
||||||
def async_setup(self) -> None:
|
def async_setup(self, pending_platforms: list[Platform] | None = None) -> None:
|
||||||
"""Set up the coordinator."""
|
"""Set up the coordinator."""
|
||||||
|
self._pending_platforms = pending_platforms
|
||||||
dev_reg = dr_async_get(self.hass)
|
dev_reg = dr_async_get(self.hass)
|
||||||
device_entry = dev_reg.async_get_or_create(
|
device_entry = dev_reg.async_get_or_create(
|
||||||
config_entry_id=self.entry.entry_id,
|
config_entry_id=self.entry.entry_id,
|
||||||
@ -146,6 +154,45 @@ class ShellyCoordinatorBase(DataUpdateCoordinator[None], Generic[_DeviceT]):
|
|||||||
)
|
)
|
||||||
self.device_id = device_entry.id
|
self.device_id = device_entry.id
|
||||||
|
|
||||||
|
async def _async_device_connect(self) -> None:
|
||||||
|
"""Connect to a Shelly Block device."""
|
||||||
|
LOGGER.debug("Connecting to Shelly Device - %s", self.name)
|
||||||
|
try:
|
||||||
|
await self.device.initialize()
|
||||||
|
update_device_fw_info(self.hass, self.device, self.entry)
|
||||||
|
except DeviceConnectionError as err:
|
||||||
|
raise UpdateFailed(f"Device disconnected: {repr(err)}") from err
|
||||||
|
except InvalidAuthError:
|
||||||
|
self.entry.async_start_reauth(self.hass)
|
||||||
|
return
|
||||||
|
|
||||||
|
if not self.device.firmware_supported:
|
||||||
|
async_create_issue_unsupported_firmware(self.hass, self.entry)
|
||||||
|
return
|
||||||
|
|
||||||
|
if not self._pending_platforms:
|
||||||
|
return
|
||||||
|
|
||||||
|
LOGGER.debug("Device %s is online, resuming setup", self.entry.title)
|
||||||
|
platforms = self._pending_platforms
|
||||||
|
self._pending_platforms = None
|
||||||
|
|
||||||
|
data = {**self.entry.data}
|
||||||
|
|
||||||
|
# Update sleep_period
|
||||||
|
old_sleep_period = data[CONF_SLEEP_PERIOD]
|
||||||
|
if isinstance(self.device, RpcDevice):
|
||||||
|
new_sleep_period = get_rpc_device_wakeup_period(self.device.status)
|
||||||
|
elif isinstance(self.device, BlockDevice):
|
||||||
|
new_sleep_period = get_block_device_sleep_period(self.device.settings)
|
||||||
|
|
||||||
|
if new_sleep_period != old_sleep_period:
|
||||||
|
data[CONF_SLEEP_PERIOD] = new_sleep_period
|
||||||
|
self.hass.config_entries.async_update_entry(self.entry, data=data)
|
||||||
|
|
||||||
|
# Resume platform setup
|
||||||
|
await self.hass.config_entries.async_forward_entry_setups(self.entry, platforms)
|
||||||
|
|
||||||
async def _async_reload_entry(self) -> None:
|
async def _async_reload_entry(self) -> None:
|
||||||
"""Reload entry."""
|
"""Reload entry."""
|
||||||
self._debounced_reload.async_cancel()
|
self._debounced_reload.async_cancel()
|
||||||
@ -179,7 +226,7 @@ class ShellyBlockCoordinator(ShellyCoordinatorBase[BlockDevice]):
|
|||||||
|
|
||||||
self._last_cfg_changed: int | None = None
|
self._last_cfg_changed: int | None = None
|
||||||
self._last_mode: str | None = None
|
self._last_mode: str | None = None
|
||||||
self._last_effect: int | None = None
|
self._last_effect: str | None = None
|
||||||
self._last_input_events_count: dict = {}
|
self._last_input_events_count: dict = {}
|
||||||
self._last_target_temp: float | None = None
|
self._last_target_temp: float | None = None
|
||||||
self._push_update_failures: int = 0
|
self._push_update_failures: int = 0
|
||||||
@ -211,15 +258,14 @@ class ShellyBlockCoordinator(ShellyCoordinatorBase[BlockDevice]):
|
|||||||
if not self.device.initialized:
|
if not self.device.initialized:
|
||||||
return
|
return
|
||||||
|
|
||||||
assert self.device.blocks
|
|
||||||
|
|
||||||
# For buttons which are battery powered - set initial value for last_event_count
|
# For buttons which are battery powered - set initial value for last_event_count
|
||||||
if self.model in SHBTN_MODELS and self._last_input_events_count.get(1) is None:
|
if self.model in SHBTN_MODELS and self._last_input_events_count.get(1) is None:
|
||||||
for block in self.device.blocks:
|
for block in self.device.blocks:
|
||||||
if block.type != "device":
|
if block.type != "device":
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if len(block.wakeupEvent) == 1 and block.wakeupEvent[0] == "button":
|
wakeup_event = cast(list, block.wakeupEvent)
|
||||||
|
if len(wakeup_event) == 1 and wakeup_event[0] == "button":
|
||||||
self._last_input_events_count[1] = -1
|
self._last_input_events_count[1] = -1
|
||||||
|
|
||||||
break
|
break
|
||||||
@ -228,7 +274,7 @@ class ShellyBlockCoordinator(ShellyCoordinatorBase[BlockDevice]):
|
|||||||
cfg_changed = 0
|
cfg_changed = 0
|
||||||
for block in self.device.blocks:
|
for block in self.device.blocks:
|
||||||
if block.type == "device" and block.cfgChanged is not None:
|
if block.type == "device" and block.cfgChanged is not None:
|
||||||
cfg_changed = block.cfgChanged
|
cfg_changed = cast(int, block.cfgChanged)
|
||||||
|
|
||||||
# Shelly TRV sends information about changing the configuration for no
|
# Shelly TRV sends information about changing the configuration for no
|
||||||
# reason, reloading the config entry is not needed for it.
|
# reason, reloading the config entry is not needed for it.
|
||||||
@ -314,14 +360,16 @@ class ShellyBlockCoordinator(ShellyCoordinatorBase[BlockDevice]):
|
|||||||
self, device_: BlockDevice, update_type: BlockUpdateType
|
self, device_: BlockDevice, update_type: BlockUpdateType
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Handle device update."""
|
"""Handle device update."""
|
||||||
if update_type == BlockUpdateType.COAP_PERIODIC:
|
if update_type is BlockUpdateType.ONLINE:
|
||||||
|
self.hass.async_create_task(self._async_device_connect(), eager_start=True)
|
||||||
|
elif update_type is BlockUpdateType.COAP_PERIODIC:
|
||||||
self._push_update_failures = 0
|
self._push_update_failures = 0
|
||||||
ir.async_delete_issue(
|
ir.async_delete_issue(
|
||||||
self.hass,
|
self.hass,
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
PUSH_UPDATE_ISSUE_ID.format(unique=self.mac),
|
PUSH_UPDATE_ISSUE_ID.format(unique=self.mac),
|
||||||
)
|
)
|
||||||
elif update_type == BlockUpdateType.COAP_REPLY:
|
elif update_type is BlockUpdateType.COAP_REPLY:
|
||||||
self._push_update_failures += 1
|
self._push_update_failures += 1
|
||||||
if self._push_update_failures == MAX_PUSH_UPDATE_FAILURES:
|
if self._push_update_failures == MAX_PUSH_UPDATE_FAILURES:
|
||||||
LOGGER.debug(
|
LOGGER.debug(
|
||||||
@ -346,9 +394,9 @@ class ShellyBlockCoordinator(ShellyCoordinatorBase[BlockDevice]):
|
|||||||
)
|
)
|
||||||
self.async_set_updated_data(None)
|
self.async_set_updated_data(None)
|
||||||
|
|
||||||
def async_setup(self) -> None:
|
def async_setup(self, pending_platforms: list[Platform] | None = None) -> None:
|
||||||
"""Set up the coordinator."""
|
"""Set up the coordinator."""
|
||||||
super().async_setup()
|
super().async_setup(pending_platforms)
|
||||||
self.device.subscribe_updates(self._async_handle_update)
|
self.device.subscribe_updates(self._async_handle_update)
|
||||||
|
|
||||||
def shutdown(self) -> None:
|
def shutdown(self) -> None:
|
||||||
@ -538,14 +586,7 @@ class ShellyRpcCoordinator(ShellyCoordinatorBase[RpcDevice]):
|
|||||||
if self.device.connected:
|
if self.device.connected:
|
||||||
return
|
return
|
||||||
|
|
||||||
LOGGER.debug("Reconnecting to Shelly RPC Device - %s", self.name)
|
await self._async_device_connect()
|
||||||
try:
|
|
||||||
await self.device.initialize()
|
|
||||||
update_device_fw_info(self.hass, self.device, self.entry)
|
|
||||||
except DeviceConnectionError as err:
|
|
||||||
raise UpdateFailed(f"Device disconnected: {repr(err)}") from err
|
|
||||||
except InvalidAuthError:
|
|
||||||
await self.async_shutdown_device_and_start_reauth()
|
|
||||||
|
|
||||||
async def _async_disconnected(self) -> None:
|
async def _async_disconnected(self) -> None:
|
||||||
"""Handle device disconnected."""
|
"""Handle device disconnected."""
|
||||||
@ -612,7 +653,9 @@ class ShellyRpcCoordinator(ShellyCoordinatorBase[RpcDevice]):
|
|||||||
self, device_: RpcDevice, update_type: RpcUpdateType
|
self, device_: RpcDevice, update_type: RpcUpdateType
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Handle device update."""
|
"""Handle device update."""
|
||||||
if update_type is RpcUpdateType.INITIALIZED:
|
if update_type is RpcUpdateType.ONLINE:
|
||||||
|
self.hass.async_create_task(self._async_device_connect(), eager_start=True)
|
||||||
|
elif update_type is RpcUpdateType.INITIALIZED:
|
||||||
self.hass.async_create_task(self._async_connected(), eager_start=True)
|
self.hass.async_create_task(self._async_connected(), eager_start=True)
|
||||||
self.async_set_updated_data(None)
|
self.async_set_updated_data(None)
|
||||||
elif update_type is RpcUpdateType.DISCONNECTED:
|
elif update_type is RpcUpdateType.DISCONNECTED:
|
||||||
@ -624,9 +667,9 @@ class ShellyRpcCoordinator(ShellyCoordinatorBase[RpcDevice]):
|
|||||||
elif update_type is RpcUpdateType.EVENT and (event := self.device.event):
|
elif update_type is RpcUpdateType.EVENT and (event := self.device.event):
|
||||||
self._async_device_event_handler(event)
|
self._async_device_event_handler(event)
|
||||||
|
|
||||||
def async_setup(self) -> None:
|
def async_setup(self, pending_platforms: list[Platform] | None = None) -> None:
|
||||||
"""Set up the coordinator."""
|
"""Set up the coordinator."""
|
||||||
super().async_setup()
|
super().async_setup(pending_platforms)
|
||||||
self.device.subscribe_updates(self._async_handle_update)
|
self.device.subscribe_updates(self._async_handle_update)
|
||||||
if self.device.initialized:
|
if self.device.initialized:
|
||||||
# If we are already initialized, we are connected
|
# If we are already initialized, we are connected
|
||||||
|
@ -74,7 +74,7 @@ def async_setup_block_attribute_entities(
|
|||||||
|
|
||||||
for block in coordinator.device.blocks:
|
for block in coordinator.device.blocks:
|
||||||
for sensor_id in block.sensor_ids:
|
for sensor_id in block.sensor_ids:
|
||||||
description = sensors.get((block.type, sensor_id))
|
description = sensors.get((cast(str, block.type), sensor_id))
|
||||||
if description is None:
|
if description is None:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
@ -78,7 +78,7 @@ def async_setup_block_entry(
|
|||||||
for block in coordinator.device.blocks:
|
for block in coordinator.device.blocks:
|
||||||
if block.type == "light":
|
if block.type == "light":
|
||||||
blocks.append(block)
|
blocks.append(block)
|
||||||
elif block.type == "relay":
|
elif block.type == "relay" and block.channel is not None:
|
||||||
if not is_block_channel_type_light(
|
if not is_block_channel_type_light(
|
||||||
coordinator.device.settings, int(block.channel)
|
coordinator.device.settings, int(block.channel)
|
||||||
):
|
):
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
"iot_class": "local_push",
|
"iot_class": "local_push",
|
||||||
"loggers": ["aioshelly"],
|
"loggers": ["aioshelly"],
|
||||||
"quality_scale": "platinum",
|
"quality_scale": "platinum",
|
||||||
"requirements": ["aioshelly==8.2.0"],
|
"requirements": ["aioshelly==9.0.0"],
|
||||||
"zeroconf": [
|
"zeroconf": [
|
||||||
{
|
{
|
||||||
"type": "_http._tcp.local.",
|
"type": "_http._tcp.local.",
|
||||||
|
@ -38,7 +38,6 @@
|
|||||||
},
|
},
|
||||||
"abort": {
|
"abort": {
|
||||||
"already_configured": "[%key:common::config_flow::abort::already_configured_device%]",
|
"already_configured": "[%key:common::config_flow::abort::already_configured_device%]",
|
||||||
"unsupported_firmware": "The device is using an unsupported firmware version.",
|
|
||||||
"reauth_successful": "[%key:common::config_flow::abort::reauth_successful%]",
|
"reauth_successful": "[%key:common::config_flow::abort::reauth_successful%]",
|
||||||
"reauth_unsuccessful": "Re-authentication was unsuccessful, please remove the integration and set it up again."
|
"reauth_unsuccessful": "Re-authentication was unsuccessful, please remove the integration and set it up again."
|
||||||
}
|
}
|
||||||
|
@ -104,8 +104,12 @@ def async_setup_block_entry(
|
|||||||
relay_blocks = []
|
relay_blocks = []
|
||||||
assert coordinator.device.blocks
|
assert coordinator.device.blocks
|
||||||
for block in coordinator.device.blocks:
|
for block in coordinator.device.blocks:
|
||||||
if block.type != "relay" or is_block_channel_type_light(
|
if (
|
||||||
|
block.type != "relay"
|
||||||
|
or block.channel is not None
|
||||||
|
and is_block_channel_type_light(
|
||||||
coordinator.device.settings, int(block.channel)
|
coordinator.device.settings, int(block.channel)
|
||||||
|
)
|
||||||
):
|
):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
@ -368,7 +368,7 @@ aioruuvigateway==0.1.0
|
|||||||
aiosenz==1.0.0
|
aiosenz==1.0.0
|
||||||
|
|
||||||
# homeassistant.components.shelly
|
# homeassistant.components.shelly
|
||||||
aioshelly==8.2.0
|
aioshelly==9.0.0
|
||||||
|
|
||||||
# homeassistant.components.skybell
|
# homeassistant.components.skybell
|
||||||
aioskybell==22.7.0
|
aioskybell==22.7.0
|
||||||
|
@ -341,7 +341,7 @@ aioruuvigateway==0.1.0
|
|||||||
aiosenz==1.0.0
|
aiosenz==1.0.0
|
||||||
|
|
||||||
# homeassistant.components.shelly
|
# homeassistant.components.shelly
|
||||||
aioshelly==8.2.0
|
aioshelly==9.0.0
|
||||||
|
|
||||||
# homeassistant.components.skybell
|
# homeassistant.components.skybell
|
||||||
aioskybell==22.7.0
|
aioskybell==22.7.0
|
||||||
|
@ -319,6 +319,11 @@ async def mock_block_device():
|
|||||||
{}, BlockUpdateType.COAP_REPLY
|
{}, BlockUpdateType.COAP_REPLY
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def online():
|
||||||
|
block_device_mock.return_value.subscribe_updates.call_args[0][0](
|
||||||
|
{}, BlockUpdateType.ONLINE
|
||||||
|
)
|
||||||
|
|
||||||
device = Mock(
|
device = Mock(
|
||||||
spec=BlockDevice,
|
spec=BlockDevice,
|
||||||
blocks=MOCK_BLOCKS,
|
blocks=MOCK_BLOCKS,
|
||||||
@ -337,6 +342,7 @@ async def mock_block_device():
|
|||||||
block_device_mock.return_value.mock_update_reply = Mock(
|
block_device_mock.return_value.mock_update_reply = Mock(
|
||||||
side_effect=update_reply
|
side_effect=update_reply
|
||||||
)
|
)
|
||||||
|
block_device_mock.return_value.mock_online = Mock(side_effect=online)
|
||||||
|
|
||||||
yield block_device_mock.return_value
|
yield block_device_mock.return_value
|
||||||
|
|
||||||
@ -376,16 +382,28 @@ async def mock_rpc_device():
|
|||||||
{}, RpcUpdateType.EVENT
|
{}, RpcUpdateType.EVENT
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def online():
|
||||||
|
rpc_device_mock.return_value.subscribe_updates.call_args[0][0](
|
||||||
|
{}, RpcUpdateType.ONLINE
|
||||||
|
)
|
||||||
|
|
||||||
def disconnected():
|
def disconnected():
|
||||||
rpc_device_mock.return_value.subscribe_updates.call_args[0][0](
|
rpc_device_mock.return_value.subscribe_updates.call_args[0][0](
|
||||||
{}, RpcUpdateType.DISCONNECTED
|
{}, RpcUpdateType.DISCONNECTED
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def initialized():
|
||||||
|
rpc_device_mock.return_value.subscribe_updates.call_args[0][0](
|
||||||
|
{}, RpcUpdateType.INITIALIZED
|
||||||
|
)
|
||||||
|
|
||||||
device = _mock_rpc_device()
|
device = _mock_rpc_device()
|
||||||
rpc_device_mock.return_value = device
|
rpc_device_mock.return_value = device
|
||||||
rpc_device_mock.return_value.mock_disconnected = Mock(side_effect=disconnected)
|
rpc_device_mock.return_value.mock_disconnected = Mock(side_effect=disconnected)
|
||||||
rpc_device_mock.return_value.mock_update = Mock(side_effect=update)
|
rpc_device_mock.return_value.mock_update = Mock(side_effect=update)
|
||||||
rpc_device_mock.return_value.mock_event = Mock(side_effect=event)
|
rpc_device_mock.return_value.mock_event = Mock(side_effect=event)
|
||||||
|
rpc_device_mock.return_value.mock_online = Mock(side_effect=online)
|
||||||
|
rpc_device_mock.return_value.mock_initialized = Mock(side_effect=initialized)
|
||||||
|
|
||||||
yield rpc_device_mock.return_value
|
yield rpc_device_mock.return_value
|
||||||
|
|
||||||
|
@ -144,7 +144,7 @@ async def test_block_sleeping_binary_sensor(
|
|||||||
assert hass.states.get(entity_id) is None
|
assert hass.states.get(entity_id) is None
|
||||||
|
|
||||||
# Make device online
|
# Make device online
|
||||||
mock_block_device.mock_update()
|
mock_block_device.mock_online()
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
assert hass.states.get(entity_id).state == STATE_OFF
|
assert hass.states.get(entity_id).state == STATE_OFF
|
||||||
@ -180,7 +180,7 @@ async def test_block_restored_sleeping_binary_sensor(
|
|||||||
|
|
||||||
# Make device online
|
# Make device online
|
||||||
monkeypatch.setattr(mock_block_device, "initialized", True)
|
monkeypatch.setattr(mock_block_device, "initialized", True)
|
||||||
mock_block_device.mock_update()
|
mock_block_device.mock_online()
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
assert hass.states.get(entity_id).state == STATE_OFF
|
assert hass.states.get(entity_id).state == STATE_OFF
|
||||||
@ -206,7 +206,7 @@ async def test_block_restored_sleeping_binary_sensor_no_last_state(
|
|||||||
|
|
||||||
# Make device online
|
# Make device online
|
||||||
monkeypatch.setattr(mock_block_device, "initialized", True)
|
monkeypatch.setattr(mock_block_device, "initialized", True)
|
||||||
mock_block_device.mock_update()
|
mock_block_device.mock_online()
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
assert hass.states.get(entity_id).state == STATE_OFF
|
assert hass.states.get(entity_id).state == STATE_OFF
|
||||||
@ -263,6 +263,7 @@ async def test_rpc_sleeping_binary_sensor(
|
|||||||
) -> None:
|
) -> None:
|
||||||
"""Test RPC online sleeping binary sensor."""
|
"""Test RPC online sleeping binary sensor."""
|
||||||
entity_id = f"{BINARY_SENSOR_DOMAIN}.test_name_cloud"
|
entity_id = f"{BINARY_SENSOR_DOMAIN}.test_name_cloud"
|
||||||
|
monkeypatch.setitem(mock_rpc_device.status["sys"], "wakeup_period", 1000)
|
||||||
config_entry = await init_integration(hass, 2, sleep_period=1000)
|
config_entry = await init_integration(hass, 2, sleep_period=1000)
|
||||||
|
|
||||||
# Sensor should be created when device is online
|
# Sensor should be created when device is online
|
||||||
@ -273,7 +274,7 @@ async def test_rpc_sleeping_binary_sensor(
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Make device online
|
# Make device online
|
||||||
mock_rpc_device.mock_update()
|
mock_rpc_device.mock_online()
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
assert hass.states.get(entity_id).state == STATE_OFF
|
assert hass.states.get(entity_id).state == STATE_OFF
|
||||||
@ -344,6 +345,10 @@ async def test_rpc_restored_sleeping_binary_sensor_no_last_state(
|
|||||||
|
|
||||||
# Make device online
|
# Make device online
|
||||||
monkeypatch.setattr(mock_rpc_device, "initialized", True)
|
monkeypatch.setattr(mock_rpc_device, "initialized", True)
|
||||||
|
mock_rpc_device.mock_online()
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
# Mock update
|
||||||
mock_rpc_device.mock_update()
|
mock_rpc_device.mock_update()
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
@ -64,7 +64,7 @@ async def test_climate_hvac_mode(
|
|||||||
await init_integration(hass, 1, sleep_period=1000, model=MODEL_VALVE)
|
await init_integration(hass, 1, sleep_period=1000, model=MODEL_VALVE)
|
||||||
|
|
||||||
# Make device online
|
# Make device online
|
||||||
mock_block_device.mock_update()
|
mock_block_device.mock_online()
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
# Test initial hvac mode - off
|
# Test initial hvac mode - off
|
||||||
@ -125,7 +125,7 @@ async def test_climate_set_temperature(
|
|||||||
await init_integration(hass, 1, sleep_period=1000)
|
await init_integration(hass, 1, sleep_period=1000)
|
||||||
|
|
||||||
# Make device online
|
# Make device online
|
||||||
mock_block_device.mock_update()
|
mock_block_device.mock_online()
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
state = hass.states.get(ENTITY_ID)
|
state = hass.states.get(ENTITY_ID)
|
||||||
@ -192,7 +192,7 @@ async def test_climate_set_preset_mode(
|
|||||||
await init_integration(hass, 1, sleep_period=1000, model=MODEL_VALVE)
|
await init_integration(hass, 1, sleep_period=1000, model=MODEL_VALVE)
|
||||||
|
|
||||||
# Make device online
|
# Make device online
|
||||||
mock_block_device.mock_update()
|
mock_block_device.mock_online()
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
state = hass.states.get(ENTITY_ID)
|
state = hass.states.get(ENTITY_ID)
|
||||||
@ -278,7 +278,7 @@ async def test_block_restored_climate(
|
|||||||
|
|
||||||
# Make device online
|
# Make device online
|
||||||
monkeypatch.setattr(mock_block_device, "initialized", True)
|
monkeypatch.setattr(mock_block_device, "initialized", True)
|
||||||
mock_block_device.mock_update()
|
mock_block_device.mock_online()
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
assert hass.states.get(entity_id).state == HVACMode.OFF
|
assert hass.states.get(entity_id).state == HVACMode.OFF
|
||||||
@ -349,7 +349,7 @@ async def test_block_restored_climate_us_customery(
|
|||||||
monkeypatch.setattr(mock_block_device, "initialized", True)
|
monkeypatch.setattr(mock_block_device, "initialized", True)
|
||||||
monkeypatch.setattr(mock_block_device.blocks[SENSOR_BLOCK_ID], "targetTemp", 4.0)
|
monkeypatch.setattr(mock_block_device.blocks[SENSOR_BLOCK_ID], "targetTemp", 4.0)
|
||||||
monkeypatch.setattr(mock_block_device.blocks[SENSOR_BLOCK_ID], "temp", 18.2)
|
monkeypatch.setattr(mock_block_device.blocks[SENSOR_BLOCK_ID], "temp", 18.2)
|
||||||
mock_block_device.mock_update()
|
mock_block_device.mock_online()
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
assert hass.states.get(entity_id).state == HVACMode.OFF
|
assert hass.states.get(entity_id).state == HVACMode.OFF
|
||||||
@ -451,7 +451,7 @@ async def test_block_set_mode_connection_error(
|
|||||||
await init_integration(hass, 1, sleep_period=1000)
|
await init_integration(hass, 1, sleep_period=1000)
|
||||||
|
|
||||||
# Make device online
|
# Make device online
|
||||||
mock_block_device.mock_update()
|
mock_block_device.mock_online()
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
with pytest.raises(HomeAssistantError):
|
with pytest.raises(HomeAssistantError):
|
||||||
@ -476,7 +476,7 @@ async def test_block_set_mode_auth_error(
|
|||||||
entry = await init_integration(hass, 1, sleep_period=1000)
|
entry = await init_integration(hass, 1, sleep_period=1000)
|
||||||
|
|
||||||
# Make device online
|
# Make device online
|
||||||
mock_block_device.mock_update()
|
mock_block_device.mock_online()
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
assert entry.state is ConfigEntryState.LOADED
|
assert entry.state is ConfigEntryState.LOADED
|
||||||
@ -534,7 +534,7 @@ async def test_block_restored_climate_auth_error(
|
|||||||
type(mock_block_device).settings = PropertyMock(
|
type(mock_block_device).settings = PropertyMock(
|
||||||
return_value={}, side_effect=InvalidAuthError
|
return_value={}, side_effect=InvalidAuthError
|
||||||
)
|
)
|
||||||
mock_block_device.mock_update()
|
mock_block_device.mock_online()
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
assert entry.state is ConfigEntryState.LOADED
|
assert entry.state is ConfigEntryState.LOADED
|
||||||
@ -561,7 +561,7 @@ async def test_device_not_calibrated(
|
|||||||
await init_integration(hass, 1, sleep_period=1000, model=MODEL_VALVE)
|
await init_integration(hass, 1, sleep_period=1000, model=MODEL_VALVE)
|
||||||
|
|
||||||
# Make device online
|
# Make device online
|
||||||
mock_block_device.mock_update()
|
mock_block_device.mock_online()
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
mock_status = MOCK_STATUS_COAP.copy()
|
mock_status = MOCK_STATUS_COAP.copy()
|
||||||
|
@ -10,7 +10,6 @@ from aioshelly.const import DEFAULT_HTTP_PORT, MODEL_1, MODEL_PLUS_2PM
|
|||||||
from aioshelly.exceptions import (
|
from aioshelly.exceptions import (
|
||||||
CustomPortNotSupported,
|
CustomPortNotSupported,
|
||||||
DeviceConnectionError,
|
DeviceConnectionError,
|
||||||
FirmwareUnsupported,
|
|
||||||
InvalidAuthError,
|
InvalidAuthError,
|
||||||
)
|
)
|
||||||
import pytest
|
import pytest
|
||||||
@ -433,25 +432,6 @@ async def test_user_setup_ignored_device(
|
|||||||
assert len(mock_setup_entry.mock_calls) == 1
|
assert len(mock_setup_entry.mock_calls) == 1
|
||||||
|
|
||||||
|
|
||||||
async def test_form_firmware_unsupported(hass: HomeAssistant) -> None:
|
|
||||||
"""Test we abort if device firmware is unsupported."""
|
|
||||||
result = await hass.config_entries.flow.async_init(
|
|
||||||
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
|
||||||
)
|
|
||||||
|
|
||||||
with patch(
|
|
||||||
"homeassistant.components.shelly.config_flow.get_info",
|
|
||||||
side_effect=FirmwareUnsupported,
|
|
||||||
):
|
|
||||||
result2 = await hass.config_entries.flow.async_configure(
|
|
||||||
result["flow_id"],
|
|
||||||
{"host": "1.1.1.1"},
|
|
||||||
)
|
|
||||||
|
|
||||||
assert result2["type"] is FlowResultType.ABORT
|
|
||||||
assert result2["reason"] == "unsupported_firmware"
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
("exc", "base_error"),
|
("exc", "base_error"),
|
||||||
[
|
[
|
||||||
@ -757,22 +737,6 @@ async def test_zeroconf_with_wifi_ap_ip(hass: HomeAssistant) -> None:
|
|||||||
assert entry.data["host"] == "2.2.2.2"
|
assert entry.data["host"] == "2.2.2.2"
|
||||||
|
|
||||||
|
|
||||||
async def test_zeroconf_firmware_unsupported(hass: HomeAssistant) -> None:
|
|
||||||
"""Test we abort if device firmware is unsupported."""
|
|
||||||
with patch(
|
|
||||||
"homeassistant.components.shelly.config_flow.get_info",
|
|
||||||
side_effect=FirmwareUnsupported,
|
|
||||||
):
|
|
||||||
result = await hass.config_entries.flow.async_init(
|
|
||||||
DOMAIN,
|
|
||||||
data=DISCOVERY_INFO,
|
|
||||||
context={"source": config_entries.SOURCE_ZEROCONF},
|
|
||||||
)
|
|
||||||
|
|
||||||
assert result["type"] is FlowResultType.ABORT
|
|
||||||
assert result["reason"] == "unsupported_firmware"
|
|
||||||
|
|
||||||
|
|
||||||
async def test_zeroconf_cannot_connect(hass: HomeAssistant) -> None:
|
async def test_zeroconf_cannot_connect(hass: HomeAssistant) -> None:
|
||||||
"""Test we get the form."""
|
"""Test we get the form."""
|
||||||
with patch(
|
with patch(
|
||||||
@ -927,11 +891,7 @@ async def test_reauth_unsuccessful(
|
|||||||
assert result["reason"] == "reauth_unsuccessful"
|
assert result["reason"] == "reauth_unsuccessful"
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
async def test_reauth_get_info_error(hass: HomeAssistant) -> None:
|
||||||
"error",
|
|
||||||
[DeviceConnectionError, FirmwareUnsupported],
|
|
||||||
)
|
|
||||||
async def test_reauth_get_info_error(hass: HomeAssistant, error: Exception) -> None:
|
|
||||||
"""Test reauthentication flow failed with error in get_info()."""
|
"""Test reauthentication flow failed with error in get_info()."""
|
||||||
entry = MockConfigEntry(
|
entry = MockConfigEntry(
|
||||||
domain="shelly", unique_id="test-mac", data={"host": "0.0.0.0", "gen": 2}
|
domain="shelly", unique_id="test-mac", data={"host": "0.0.0.0", "gen": 2}
|
||||||
@ -940,7 +900,7 @@ async def test_reauth_get_info_error(hass: HomeAssistant, error: Exception) -> N
|
|||||||
|
|
||||||
with patch(
|
with patch(
|
||||||
"homeassistant.components.shelly.config_flow.get_info",
|
"homeassistant.components.shelly.config_flow.get_info",
|
||||||
side_effect=error,
|
side_effect=DeviceConnectionError,
|
||||||
):
|
):
|
||||||
result = await hass.config_entries.flow.async_init(
|
result = await hass.config_entries.flow.async_init(
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
@ -1154,6 +1114,7 @@ async def test_zeroconf_sleeping_device_not_triggers_refresh(
|
|||||||
caplog: pytest.LogCaptureFixture,
|
caplog: pytest.LogCaptureFixture,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test zeroconf discovery does not triggers refresh for sleeping device."""
|
"""Test zeroconf discovery does not triggers refresh for sleeping device."""
|
||||||
|
monkeypatch.setitem(mock_rpc_device.status["sys"], "wakeup_period", 1000)
|
||||||
entry = MockConfigEntry(
|
entry = MockConfigEntry(
|
||||||
domain="shelly",
|
domain="shelly",
|
||||||
unique_id="AABBCCDDEEFF",
|
unique_id="AABBCCDDEEFF",
|
||||||
@ -1163,10 +1124,11 @@ async def test_zeroconf_sleeping_device_not_triggers_refresh(
|
|||||||
await hass.config_entries.async_setup(entry.entry_id)
|
await hass.config_entries.async_setup(entry.entry_id)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
mock_rpc_device.mock_update()
|
mock_rpc_device.mock_online()
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
assert "online, resuming setup" in caplog.text
|
assert "online, resuming setup" in caplog.text
|
||||||
|
assert len(mock_rpc_device.initialize.mock_calls) == 1
|
||||||
|
|
||||||
with patch(
|
with patch(
|
||||||
"homeassistant.components.shelly.config_flow.get_info",
|
"homeassistant.components.shelly.config_flow.get_info",
|
||||||
@ -1186,7 +1148,7 @@ async def test_zeroconf_sleeping_device_not_triggers_refresh(
|
|||||||
hass, dt_util.utcnow() + timedelta(seconds=ENTRY_RELOAD_COOLDOWN)
|
hass, dt_util.utcnow() + timedelta(seconds=ENTRY_RELOAD_COOLDOWN)
|
||||||
)
|
)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
assert len(mock_rpc_device.initialize.mock_calls) == 0
|
assert len(mock_rpc_device.initialize.mock_calls) == 1
|
||||||
assert "device did not update" not in caplog.text
|
assert "device did not update" not in caplog.text
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,14 +1,10 @@
|
|||||||
"""Tests for Shelly coordinator."""
|
"""Tests for Shelly coordinator."""
|
||||||
|
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
from unittest.mock import AsyncMock, Mock, patch
|
from unittest.mock import AsyncMock, Mock, call, patch
|
||||||
|
|
||||||
from aioshelly.const import MODEL_BULB, MODEL_BUTTON1
|
from aioshelly.const import MODEL_BULB, MODEL_BUTTON1
|
||||||
from aioshelly.exceptions import (
|
from aioshelly.exceptions import DeviceConnectionError, InvalidAuthError
|
||||||
DeviceConnectionError,
|
|
||||||
FirmwareUnsupported,
|
|
||||||
InvalidAuthError,
|
|
||||||
)
|
|
||||||
from freezegun.api import FrozenDateTimeFactory
|
from freezegun.api import FrozenDateTimeFactory
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
@ -29,13 +25,13 @@ from homeassistant.components.shelly.const import (
|
|||||||
from homeassistant.config_entries import SOURCE_REAUTH, ConfigEntryState
|
from homeassistant.config_entries import SOURCE_REAUTH, ConfigEntryState
|
||||||
from homeassistant.const import ATTR_DEVICE_ID, STATE_ON, STATE_UNAVAILABLE
|
from homeassistant.const import ATTR_DEVICE_ID, STATE_ON, STATE_UNAVAILABLE
|
||||||
from homeassistant.core import Event, HomeAssistant
|
from homeassistant.core import Event, HomeAssistant
|
||||||
|
from homeassistant.helpers import issue_registry as ir
|
||||||
from homeassistant.helpers.device_registry import (
|
from homeassistant.helpers.device_registry import (
|
||||||
CONNECTION_NETWORK_MAC,
|
CONNECTION_NETWORK_MAC,
|
||||||
async_entries_for_config_entry,
|
async_entries_for_config_entry,
|
||||||
async_get as async_get_dev_reg,
|
async_get as async_get_dev_reg,
|
||||||
format_mac,
|
format_mac,
|
||||||
)
|
)
|
||||||
import homeassistant.helpers.issue_registry as ir
|
|
||||||
|
|
||||||
from . import (
|
from . import (
|
||||||
MOCK_MAC,
|
MOCK_MAC,
|
||||||
@ -216,28 +212,25 @@ async def test_block_rest_update_auth_error(
|
|||||||
assert flow["context"].get("entry_id") == entry.entry_id
|
assert flow["context"].get("entry_id") == entry.entry_id
|
||||||
|
|
||||||
|
|
||||||
async def test_block_firmware_unsupported(
|
async def test_block_sleeping_device_firmware_unsupported(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
freezer: FrozenDateTimeFactory,
|
|
||||||
mock_block_device: Mock,
|
mock_block_device: Mock,
|
||||||
monkeypatch: pytest.MonkeyPatch,
|
monkeypatch: pytest.MonkeyPatch,
|
||||||
|
issue_registry: ir.IssueRegistry,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test block device polling authentication error."""
|
"""Test block sleeping device firmware not supported."""
|
||||||
monkeypatch.setattr(
|
monkeypatch.setattr(mock_block_device, "firmware_supported", False)
|
||||||
mock_block_device,
|
entry = await init_integration(hass, 1, sleep_period=3600)
|
||||||
"update",
|
|
||||||
AsyncMock(side_effect=FirmwareUnsupported),
|
|
||||||
)
|
|
||||||
entry = await init_integration(hass, 1)
|
|
||||||
|
|
||||||
assert entry.state is ConfigEntryState.LOADED
|
# Make device online
|
||||||
|
mock_block_device.mock_online()
|
||||||
# Move time to generate polling
|
|
||||||
freezer.tick(timedelta(seconds=UPDATE_PERIOD_MULTIPLIER * 15))
|
|
||||||
async_fire_time_changed(hass)
|
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
assert entry.state is ConfigEntryState.LOADED
|
assert entry.state is ConfigEntryState.LOADED
|
||||||
|
assert (
|
||||||
|
DOMAIN,
|
||||||
|
"firmware_unsupported_123456789ABC",
|
||||||
|
) in issue_registry.issues
|
||||||
|
|
||||||
|
|
||||||
async def test_block_polling_connection_error(
|
async def test_block_polling_connection_error(
|
||||||
@ -290,20 +283,28 @@ async def test_block_rest_update_connection_error(
|
|||||||
|
|
||||||
|
|
||||||
async def test_block_sleeping_device_no_periodic_updates(
|
async def test_block_sleeping_device_no_periodic_updates(
|
||||||
hass: HomeAssistant, freezer: FrozenDateTimeFactory, mock_block_device: Mock
|
hass: HomeAssistant,
|
||||||
|
freezer: FrozenDateTimeFactory,
|
||||||
|
mock_block_device: Mock,
|
||||||
|
monkeypatch: pytest.MonkeyPatch,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test block sleeping device no periodic updates."""
|
"""Test block sleeping device no periodic updates."""
|
||||||
entity_id = f"{SENSOR_DOMAIN}.test_name_temperature"
|
entity_id = f"{SENSOR_DOMAIN}.test_name_temperature"
|
||||||
await init_integration(hass, 1, sleep_period=1000)
|
monkeypatch.setitem(
|
||||||
|
mock_block_device.settings,
|
||||||
|
"sleep_mode",
|
||||||
|
{"period": 60, "unit": "m"},
|
||||||
|
)
|
||||||
|
await init_integration(hass, 1, sleep_period=3600)
|
||||||
|
|
||||||
# Make device online
|
# Make device online
|
||||||
mock_block_device.mock_update()
|
mock_block_device.mock_online()
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
assert get_entity_state(hass, entity_id) == "22.1"
|
assert get_entity_state(hass, entity_id) == "22.1"
|
||||||
|
|
||||||
# Move time to generate polling
|
# Move time to generate polling
|
||||||
freezer.tick(timedelta(seconds=UPDATE_PERIOD_MULTIPLIER * 1000))
|
freezer.tick(timedelta(seconds=UPDATE_PERIOD_MULTIPLIER * 3600))
|
||||||
async_fire_time_changed(hass)
|
async_fire_time_changed(hass)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
@ -352,7 +353,7 @@ async def test_block_button_click_event(
|
|||||||
entry = await init_integration(hass, 1, model=MODEL_BUTTON1, sleep_period=1000)
|
entry = await init_integration(hass, 1, model=MODEL_BUTTON1, sleep_period=1000)
|
||||||
|
|
||||||
# Make device online
|
# Make device online
|
||||||
mock_block_device.mock_update()
|
mock_block_device.mock_online()
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
dev_reg = async_get_dev_reg(hass)
|
dev_reg = async_get_dev_reg(hass)
|
||||||
@ -529,6 +530,7 @@ async def test_rpc_update_entry_sleep_period(
|
|||||||
monkeypatch: pytest.MonkeyPatch,
|
monkeypatch: pytest.MonkeyPatch,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test RPC update entry sleep period."""
|
"""Test RPC update entry sleep period."""
|
||||||
|
monkeypatch.setitem(mock_rpc_device.status["sys"], "wakeup_period", 600)
|
||||||
entry = await init_integration(hass, 2, sleep_period=600)
|
entry = await init_integration(hass, 2, sleep_period=600)
|
||||||
register_entity(
|
register_entity(
|
||||||
hass,
|
hass,
|
||||||
@ -539,7 +541,7 @@ async def test_rpc_update_entry_sleep_period(
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Make device online
|
# Make device online
|
||||||
mock_rpc_device.mock_update()
|
mock_rpc_device.mock_online()
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
assert entry.data["sleep_period"] == 600
|
assert entry.data["sleep_period"] == 600
|
||||||
@ -554,10 +556,14 @@ async def test_rpc_update_entry_sleep_period(
|
|||||||
|
|
||||||
|
|
||||||
async def test_rpc_sleeping_device_no_periodic_updates(
|
async def test_rpc_sleeping_device_no_periodic_updates(
|
||||||
hass: HomeAssistant, freezer: FrozenDateTimeFactory, mock_rpc_device: Mock
|
hass: HomeAssistant,
|
||||||
|
freezer: FrozenDateTimeFactory,
|
||||||
|
mock_rpc_device: Mock,
|
||||||
|
monkeypatch: pytest.MonkeyPatch,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test RPC sleeping device no periodic updates."""
|
"""Test RPC sleeping device no periodic updates."""
|
||||||
entity_id = f"{SENSOR_DOMAIN}.test_name_temperature"
|
entity_id = f"{SENSOR_DOMAIN}.test_name_temperature"
|
||||||
|
monkeypatch.setitem(mock_rpc_device.status["sys"], "wakeup_period", 1000)
|
||||||
entry = await init_integration(hass, 2, sleep_period=1000)
|
entry = await init_integration(hass, 2, sleep_period=1000)
|
||||||
register_entity(
|
register_entity(
|
||||||
hass,
|
hass,
|
||||||
@ -568,7 +574,7 @@ async def test_rpc_sleeping_device_no_periodic_updates(
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Make device online
|
# Make device online
|
||||||
mock_rpc_device.mock_update()
|
mock_rpc_device.mock_online()
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
assert get_entity_state(hass, entity_id) == "22.9"
|
assert get_entity_state(hass, entity_id) == "22.9"
|
||||||
@ -581,25 +587,25 @@ async def test_rpc_sleeping_device_no_periodic_updates(
|
|||||||
assert get_entity_state(hass, entity_id) is STATE_UNAVAILABLE
|
assert get_entity_state(hass, entity_id) is STATE_UNAVAILABLE
|
||||||
|
|
||||||
|
|
||||||
async def test_rpc_firmware_unsupported(
|
async def test_rpc_sleeping_device_firmware_unsupported(
|
||||||
hass: HomeAssistant, freezer: FrozenDateTimeFactory, mock_rpc_device: Mock
|
hass: HomeAssistant,
|
||||||
|
mock_rpc_device: Mock,
|
||||||
|
monkeypatch: pytest.MonkeyPatch,
|
||||||
|
issue_registry: ir.IssueRegistry,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test RPC update entry unsupported firmware."""
|
"""Test RPC sleeping device firmware not supported."""
|
||||||
entry = await init_integration(hass, 2)
|
monkeypatch.setattr(mock_rpc_device, "firmware_supported", False)
|
||||||
register_entity(
|
entry = await init_integration(hass, 2, sleep_period=3600)
|
||||||
hass,
|
|
||||||
SENSOR_DOMAIN,
|
|
||||||
"test_name_temperature",
|
|
||||||
"temperature:0-temperature_0",
|
|
||||||
entry,
|
|
||||||
)
|
|
||||||
|
|
||||||
# Move time to generate sleep period update
|
# Make device online
|
||||||
freezer.tick(timedelta(seconds=600 * SLEEP_PERIOD_MULTIPLIER))
|
mock_rpc_device.mock_online()
|
||||||
async_fire_time_changed(hass)
|
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
assert entry.state is ConfigEntryState.LOADED
|
assert entry.state is ConfigEntryState.LOADED
|
||||||
|
assert (
|
||||||
|
DOMAIN,
|
||||||
|
"firmware_unsupported_123456789ABC",
|
||||||
|
) in issue_registry.issues
|
||||||
|
|
||||||
|
|
||||||
async def test_rpc_reconnect_auth_error(
|
async def test_rpc_reconnect_auth_error(
|
||||||
@ -753,11 +759,12 @@ async def test_rpc_update_entry_fw_ver(
|
|||||||
hass: HomeAssistant, mock_rpc_device: Mock, monkeypatch: pytest.MonkeyPatch
|
hass: HomeAssistant, mock_rpc_device: Mock, monkeypatch: pytest.MonkeyPatch
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test RPC update entry firmware version."""
|
"""Test RPC update entry firmware version."""
|
||||||
|
monkeypatch.setitem(mock_rpc_device.status["sys"], "wakeup_period", 600)
|
||||||
entry = await init_integration(hass, 2, sleep_period=600)
|
entry = await init_integration(hass, 2, sleep_period=600)
|
||||||
dev_reg = async_get_dev_reg(hass)
|
dev_reg = async_get_dev_reg(hass)
|
||||||
|
|
||||||
# Make device online
|
# Make device online
|
||||||
mock_rpc_device.mock_update()
|
mock_rpc_device.mock_online()
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
assert entry.unique_id
|
assert entry.unique_id
|
||||||
@ -779,3 +786,23 @@ async def test_rpc_update_entry_fw_ver(
|
|||||||
)
|
)
|
||||||
assert device
|
assert device
|
||||||
assert device.sw_version == "99.0.0"
|
assert device.sw_version == "99.0.0"
|
||||||
|
|
||||||
|
|
||||||
|
async def test_rpc_runs_connected_events_when_initialized(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
mock_rpc_device: Mock,
|
||||||
|
monkeypatch: pytest.MonkeyPatch,
|
||||||
|
) -> None:
|
||||||
|
"""Test RPC runs connected events when initialized."""
|
||||||
|
monkeypatch.setattr(mock_rpc_device, "initialized", False)
|
||||||
|
await init_integration(hass, 2)
|
||||||
|
|
||||||
|
assert call.script_list() not in mock_rpc_device.mock_calls
|
||||||
|
|
||||||
|
# Mock initialized event
|
||||||
|
monkeypatch.setattr(mock_rpc_device, "initialized", True)
|
||||||
|
mock_rpc_device.mock_initialized()
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
# BLE script list is called during connected events
|
||||||
|
assert call.script_list() in mock_rpc_device.mock_calls
|
||||||
|
@ -8,7 +8,6 @@ from aioshelly.common import ConnectionOptions
|
|||||||
from aioshelly.const import MODEL_PLUS_2PM
|
from aioshelly.const import MODEL_PLUS_2PM
|
||||||
from aioshelly.exceptions import (
|
from aioshelly.exceptions import (
|
||||||
DeviceConnectionError,
|
DeviceConnectionError,
|
||||||
FirmwareUnsupported,
|
|
||||||
InvalidAuthError,
|
InvalidAuthError,
|
||||||
MacAddressMismatchError,
|
MacAddressMismatchError,
|
||||||
)
|
)
|
||||||
@ -27,6 +26,7 @@ from homeassistant.components.shelly.const import (
|
|||||||
from homeassistant.config_entries import SOURCE_REAUTH, ConfigEntryState
|
from homeassistant.config_entries import SOURCE_REAUTH, ConfigEntryState
|
||||||
from homeassistant.const import CONF_HOST, CONF_PORT, STATE_ON, STATE_UNAVAILABLE
|
from homeassistant.const import CONF_HOST, CONF_PORT, STATE_ON, STATE_UNAVAILABLE
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
|
from homeassistant.helpers import issue_registry as ir
|
||||||
from homeassistant.helpers.device_registry import (
|
from homeassistant.helpers.device_registry import (
|
||||||
CONNECTION_NETWORK_MAC,
|
CONNECTION_NETWORK_MAC,
|
||||||
DeviceRegistry,
|
DeviceRegistry,
|
||||||
@ -145,27 +145,46 @@ async def test_setup_entry_not_shelly(
|
|||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("gen", [1, 2, 3])
|
@pytest.mark.parametrize("gen", [1, 2, 3])
|
||||||
@pytest.mark.parametrize("side_effect", [DeviceConnectionError, FirmwareUnsupported])
|
|
||||||
async def test_device_connection_error(
|
async def test_device_connection_error(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
gen: int,
|
gen: int,
|
||||||
side_effect: Exception,
|
|
||||||
mock_block_device: Mock,
|
mock_block_device: Mock,
|
||||||
mock_rpc_device: Mock,
|
mock_rpc_device: Mock,
|
||||||
monkeypatch: pytest.MonkeyPatch,
|
monkeypatch: pytest.MonkeyPatch,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test device connection error."""
|
"""Test device connection error."""
|
||||||
monkeypatch.setattr(
|
monkeypatch.setattr(
|
||||||
mock_block_device, "initialize", AsyncMock(side_effect=side_effect)
|
mock_block_device, "initialize", AsyncMock(side_effect=DeviceConnectionError)
|
||||||
)
|
)
|
||||||
monkeypatch.setattr(
|
monkeypatch.setattr(
|
||||||
mock_rpc_device, "initialize", AsyncMock(side_effect=side_effect)
|
mock_rpc_device, "initialize", AsyncMock(side_effect=DeviceConnectionError)
|
||||||
)
|
)
|
||||||
|
|
||||||
entry = await init_integration(hass, gen)
|
entry = await init_integration(hass, gen)
|
||||||
assert entry.state is ConfigEntryState.SETUP_RETRY
|
assert entry.state is ConfigEntryState.SETUP_RETRY
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("gen", [1, 2, 3])
|
||||||
|
async def test_device_unsupported_firmware(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
gen: int,
|
||||||
|
mock_block_device: Mock,
|
||||||
|
mock_rpc_device: Mock,
|
||||||
|
monkeypatch: pytest.MonkeyPatch,
|
||||||
|
issue_registry: ir.IssueRegistry,
|
||||||
|
) -> None:
|
||||||
|
"""Test device init with unsupported firmware."""
|
||||||
|
monkeypatch.setattr(mock_block_device, "firmware_supported", False)
|
||||||
|
monkeypatch.setattr(mock_rpc_device, "firmware_supported", False)
|
||||||
|
|
||||||
|
entry = await init_integration(hass, gen)
|
||||||
|
assert entry.state is ConfigEntryState.SETUP_RETRY
|
||||||
|
assert (
|
||||||
|
DOMAIN,
|
||||||
|
"firmware_unsupported_123456789ABC",
|
||||||
|
) in issue_registry.issues
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("gen", [1, 2, 3])
|
@pytest.mark.parametrize("gen", [1, 2, 3])
|
||||||
async def test_mac_mismatch_error(
|
async def test_mac_mismatch_error(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
@ -217,12 +236,13 @@ async def test_device_auth_error(
|
|||||||
assert flow["context"].get("entry_id") == entry.entry_id
|
assert flow["context"].get("entry_id") == entry.entry_id
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(("entry_sleep", "device_sleep"), [(None, 0), (1000, 1000)])
|
@pytest.mark.parametrize(("entry_sleep", "device_sleep"), [(None, 0), (3600, 3600)])
|
||||||
async def test_sleeping_block_device_online(
|
async def test_sleeping_block_device_online(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
entry_sleep: int | None,
|
entry_sleep: int | None,
|
||||||
device_sleep: int,
|
device_sleep: int,
|
||||||
mock_block_device: Mock,
|
mock_block_device: Mock,
|
||||||
|
monkeypatch: pytest.MonkeyPatch,
|
||||||
device_reg: DeviceRegistry,
|
device_reg: DeviceRegistry,
|
||||||
caplog: pytest.LogCaptureFixture,
|
caplog: pytest.LogCaptureFixture,
|
||||||
) -> None:
|
) -> None:
|
||||||
@ -234,10 +254,17 @@ async def test_sleeping_block_device_online(
|
|||||||
connections={(CONNECTION_NETWORK_MAC, format_mac(MOCK_MAC))},
|
connections={(CONNECTION_NETWORK_MAC, format_mac(MOCK_MAC))},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
monkeypatch.setitem(
|
||||||
|
mock_block_device.settings,
|
||||||
|
"sleep_mode",
|
||||||
|
{"period": int(device_sleep / 60), "unit": "m"},
|
||||||
|
)
|
||||||
entry = await init_integration(hass, 1, sleep_period=entry_sleep)
|
entry = await init_integration(hass, 1, sleep_period=entry_sleep)
|
||||||
assert "will resume when device is online" in caplog.text
|
assert "will resume when device is online" in caplog.text
|
||||||
|
|
||||||
mock_block_device.mock_update()
|
mock_block_device.mock_online()
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
assert "online, resuming setup" in caplog.text
|
assert "online, resuming setup" in caplog.text
|
||||||
assert entry.data["sleep_period"] == device_sleep
|
assert entry.data["sleep_period"] == device_sleep
|
||||||
|
|
||||||
@ -248,13 +275,17 @@ async def test_sleeping_rpc_device_online(
|
|||||||
entry_sleep: int | None,
|
entry_sleep: int | None,
|
||||||
device_sleep: int,
|
device_sleep: int,
|
||||||
mock_rpc_device: Mock,
|
mock_rpc_device: Mock,
|
||||||
|
monkeypatch: pytest.MonkeyPatch,
|
||||||
caplog: pytest.LogCaptureFixture,
|
caplog: pytest.LogCaptureFixture,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test sleeping RPC device online."""
|
"""Test sleeping RPC device online."""
|
||||||
|
monkeypatch.setitem(mock_rpc_device.status["sys"], "wakeup_period", device_sleep)
|
||||||
entry = await init_integration(hass, 2, sleep_period=entry_sleep)
|
entry = await init_integration(hass, 2, sleep_period=entry_sleep)
|
||||||
assert "will resume when device is online" in caplog.text
|
assert "will resume when device is online" in caplog.text
|
||||||
|
|
||||||
mock_rpc_device.mock_update()
|
mock_rpc_device.mock_online()
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
assert "online, resuming setup" in caplog.text
|
assert "online, resuming setup" in caplog.text
|
||||||
assert entry.data["sleep_period"] == device_sleep
|
assert entry.data["sleep_period"] == device_sleep
|
||||||
|
|
||||||
@ -270,7 +301,9 @@ async def test_sleeping_rpc_device_online_new_firmware(
|
|||||||
assert "will resume when device is online" in caplog.text
|
assert "will resume when device is online" in caplog.text
|
||||||
|
|
||||||
mutate_rpc_device_status(monkeypatch, mock_rpc_device, "sys", "wakeup_period", 1500)
|
mutate_rpc_device_status(monkeypatch, mock_rpc_device, "sys", "wakeup_period", 1500)
|
||||||
mock_rpc_device.mock_update()
|
mock_rpc_device.mock_online()
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
assert "online, resuming setup" in caplog.text
|
assert "online, resuming setup" in caplog.text
|
||||||
assert entry.data["sleep_period"] == 1500
|
assert entry.data["sleep_period"] == 1500
|
||||||
|
|
||||||
@ -413,9 +446,12 @@ async def test_entry_missing_port(hass: HomeAssistant) -> None:
|
|||||||
}
|
}
|
||||||
entry = MockConfigEntry(domain=DOMAIN, data=data, unique_id=MOCK_MAC)
|
entry = MockConfigEntry(domain=DOMAIN, data=data, unique_id=MOCK_MAC)
|
||||||
entry.add_to_hass(hass)
|
entry.add_to_hass(hass)
|
||||||
with patch(
|
with (
|
||||||
|
patch("homeassistant.components.shelly.RpcDevice.initialize"),
|
||||||
|
patch(
|
||||||
"homeassistant.components.shelly.RpcDevice.create", return_value=Mock()
|
"homeassistant.components.shelly.RpcDevice.create", return_value=Mock()
|
||||||
) as rpc_device_mock:
|
) as rpc_device_mock,
|
||||||
|
):
|
||||||
await hass.config_entries.async_setup(entry.entry_id)
|
await hass.config_entries.async_setup(entry.entry_id)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
@ -435,9 +471,12 @@ async def test_rpc_entry_custom_port(hass: HomeAssistant) -> None:
|
|||||||
}
|
}
|
||||||
entry = MockConfigEntry(domain=DOMAIN, data=data, unique_id=MOCK_MAC)
|
entry = MockConfigEntry(domain=DOMAIN, data=data, unique_id=MOCK_MAC)
|
||||||
entry.add_to_hass(hass)
|
entry.add_to_hass(hass)
|
||||||
with patch(
|
with (
|
||||||
|
patch("homeassistant.components.shelly.RpcDevice.initialize"),
|
||||||
|
patch(
|
||||||
"homeassistant.components.shelly.RpcDevice.create", return_value=Mock()
|
"homeassistant.components.shelly.RpcDevice.create", return_value=Mock()
|
||||||
) as rpc_device_mock:
|
) as rpc_device_mock,
|
||||||
|
):
|
||||||
await hass.config_entries.async_setup(entry.entry_id)
|
await hass.config_entries.async_setup(entry.entry_id)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
@ -33,12 +33,17 @@ async def test_block_number_update(
|
|||||||
) -> None:
|
) -> None:
|
||||||
"""Test block device number update."""
|
"""Test block device number update."""
|
||||||
entity_id = "number.test_name_valve_position"
|
entity_id = "number.test_name_valve_position"
|
||||||
await init_integration(hass, 1, sleep_period=1000)
|
monkeypatch.setitem(
|
||||||
|
mock_block_device.settings,
|
||||||
|
"sleep_mode",
|
||||||
|
{"period": 60, "unit": "m"},
|
||||||
|
)
|
||||||
|
await init_integration(hass, 1, sleep_period=3600)
|
||||||
|
|
||||||
assert hass.states.get(entity_id) is None
|
assert hass.states.get(entity_id) is None
|
||||||
|
|
||||||
# Make device online
|
# Make device online
|
||||||
mock_block_device.mock_update()
|
mock_block_device.mock_online()
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
assert hass.states.get(entity_id).state == "50"
|
assert hass.states.get(entity_id).state == "50"
|
||||||
@ -93,7 +98,7 @@ async def test_block_restored_number(
|
|||||||
|
|
||||||
# Make device online
|
# Make device online
|
||||||
monkeypatch.setattr(mock_block_device, "initialized", True)
|
monkeypatch.setattr(mock_block_device, "initialized", True)
|
||||||
mock_block_device.mock_update()
|
mock_block_device.mock_online()
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
assert hass.states.get(entity_id).state == "50"
|
assert hass.states.get(entity_id).state == "50"
|
||||||
@ -130,20 +135,27 @@ async def test_block_restored_number_no_last_state(
|
|||||||
|
|
||||||
# Make device online
|
# Make device online
|
||||||
monkeypatch.setattr(mock_block_device, "initialized", True)
|
monkeypatch.setattr(mock_block_device, "initialized", True)
|
||||||
mock_block_device.mock_update()
|
mock_block_device.mock_online()
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
assert hass.states.get(entity_id).state == "50"
|
assert hass.states.get(entity_id).state == "50"
|
||||||
|
|
||||||
|
|
||||||
async def test_block_number_set_value(
|
async def test_block_number_set_value(
|
||||||
hass: HomeAssistant, mock_block_device: Mock
|
hass: HomeAssistant,
|
||||||
|
mock_block_device: Mock,
|
||||||
|
monkeypatch: pytest.MonkeyPatch,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test block device number set value."""
|
"""Test block device number set value."""
|
||||||
await init_integration(hass, 1, sleep_period=1000)
|
monkeypatch.setitem(
|
||||||
|
mock_block_device.settings,
|
||||||
|
"sleep_mode",
|
||||||
|
{"period": 60, "unit": "m"},
|
||||||
|
)
|
||||||
|
await init_integration(hass, 1, sleep_period=3600)
|
||||||
|
|
||||||
# Make device online
|
# Make device online
|
||||||
mock_block_device.mock_update()
|
mock_block_device.mock_online()
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
mock_block_device.reset_mock()
|
mock_block_device.reset_mock()
|
||||||
@ -162,15 +174,20 @@ async def test_block_set_value_connection_error(
|
|||||||
hass: HomeAssistant, mock_block_device: Mock, monkeypatch: pytest.MonkeyPatch
|
hass: HomeAssistant, mock_block_device: Mock, monkeypatch: pytest.MonkeyPatch
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test block device set value connection error."""
|
"""Test block device set value connection error."""
|
||||||
|
monkeypatch.setitem(
|
||||||
|
mock_block_device.settings,
|
||||||
|
"sleep_mode",
|
||||||
|
{"period": 60, "unit": "m"},
|
||||||
|
)
|
||||||
monkeypatch.setattr(
|
monkeypatch.setattr(
|
||||||
mock_block_device,
|
mock_block_device,
|
||||||
"http_request",
|
"http_request",
|
||||||
AsyncMock(side_effect=DeviceConnectionError),
|
AsyncMock(side_effect=DeviceConnectionError),
|
||||||
)
|
)
|
||||||
await init_integration(hass, 1, sleep_period=1000)
|
await init_integration(hass, 1, sleep_period=3600)
|
||||||
|
|
||||||
# Make device online
|
# Make device online
|
||||||
mock_block_device.mock_update()
|
mock_block_device.mock_online()
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
with pytest.raises(HomeAssistantError):
|
with pytest.raises(HomeAssistantError):
|
||||||
@ -186,15 +203,20 @@ async def test_block_set_value_auth_error(
|
|||||||
hass: HomeAssistant, mock_block_device: Mock, monkeypatch: pytest.MonkeyPatch
|
hass: HomeAssistant, mock_block_device: Mock, monkeypatch: pytest.MonkeyPatch
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test block device set value authentication error."""
|
"""Test block device set value authentication error."""
|
||||||
|
monkeypatch.setitem(
|
||||||
|
mock_block_device.settings,
|
||||||
|
"sleep_mode",
|
||||||
|
{"period": 60, "unit": "m"},
|
||||||
|
)
|
||||||
monkeypatch.setattr(
|
monkeypatch.setattr(
|
||||||
mock_block_device,
|
mock_block_device,
|
||||||
"http_request",
|
"http_request",
|
||||||
AsyncMock(side_effect=InvalidAuthError),
|
AsyncMock(side_effect=InvalidAuthError),
|
||||||
)
|
)
|
||||||
entry = await init_integration(hass, 1, sleep_period=1000)
|
entry = await init_integration(hass, 1, sleep_period=3600)
|
||||||
|
|
||||||
# Make device online
|
# Make device online
|
||||||
mock_block_device.mock_update()
|
mock_block_device.mock_online()
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
assert entry.state is ConfigEntryState.LOADED
|
assert entry.state is ConfigEntryState.LOADED
|
||||||
|
@ -164,7 +164,7 @@ async def test_block_sleeping_sensor(
|
|||||||
assert hass.states.get(entity_id) is None
|
assert hass.states.get(entity_id) is None
|
||||||
|
|
||||||
# Make device online
|
# Make device online
|
||||||
mock_block_device.mock_update()
|
mock_block_device.mock_online()
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
assert hass.states.get(entity_id).state == "22.1"
|
assert hass.states.get(entity_id).state == "22.1"
|
||||||
@ -206,7 +206,7 @@ async def test_block_restored_sleeping_sensor(
|
|||||||
|
|
||||||
# Make device online
|
# Make device online
|
||||||
monkeypatch.setattr(mock_block_device, "initialized", True)
|
monkeypatch.setattr(mock_block_device, "initialized", True)
|
||||||
mock_block_device.mock_update()
|
mock_block_device.mock_online()
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
assert hass.states.get(entity_id).state == "22.1"
|
assert hass.states.get(entity_id).state == "22.1"
|
||||||
@ -232,7 +232,7 @@ async def test_block_restored_sleeping_sensor_no_last_state(
|
|||||||
|
|
||||||
# Make device online
|
# Make device online
|
||||||
monkeypatch.setattr(mock_block_device, "initialized", True)
|
monkeypatch.setattr(mock_block_device, "initialized", True)
|
||||||
mock_block_device.mock_update()
|
mock_block_device.mock_online()
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
assert hass.states.get(entity_id).state == "22.1"
|
assert hass.states.get(entity_id).state == "22.1"
|
||||||
@ -305,7 +305,7 @@ async def test_block_not_matched_restored_sleeping_sensor(
|
|||||||
mock_block_device.blocks[SENSOR_BLOCK_ID], "description", "other_desc"
|
mock_block_device.blocks[SENSOR_BLOCK_ID], "description", "other_desc"
|
||||||
)
|
)
|
||||||
monkeypatch.setattr(mock_block_device, "initialized", True)
|
monkeypatch.setattr(mock_block_device, "initialized", True)
|
||||||
mock_block_device.mock_update()
|
mock_block_device.mock_online()
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
assert hass.states.get(entity_id).state == "20.4"
|
assert hass.states.get(entity_id).state == "20.4"
|
||||||
@ -448,6 +448,7 @@ async def test_rpc_sleeping_sensor(
|
|||||||
) -> None:
|
) -> None:
|
||||||
"""Test RPC online sleeping sensor."""
|
"""Test RPC online sleeping sensor."""
|
||||||
entity_id = f"{SENSOR_DOMAIN}.test_name_temperature"
|
entity_id = f"{SENSOR_DOMAIN}.test_name_temperature"
|
||||||
|
monkeypatch.setitem(mock_rpc_device.status["sys"], "wakeup_period", 1000)
|
||||||
entry = await init_integration(hass, 2, sleep_period=1000)
|
entry = await init_integration(hass, 2, sleep_period=1000)
|
||||||
|
|
||||||
# Sensor should be created when device is online
|
# Sensor should be created when device is online
|
||||||
@ -462,7 +463,7 @@ async def test_rpc_sleeping_sensor(
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Make device online
|
# Make device online
|
||||||
mock_rpc_device.mock_update()
|
mock_rpc_device.mock_online()
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
assert hass.states.get(entity_id).state == "22.9"
|
assert hass.states.get(entity_id).state == "22.9"
|
||||||
@ -501,6 +502,10 @@ async def test_rpc_restored_sleeping_sensor(
|
|||||||
|
|
||||||
# Make device online
|
# Make device online
|
||||||
monkeypatch.setattr(mock_rpc_device, "initialized", True)
|
monkeypatch.setattr(mock_rpc_device, "initialized", True)
|
||||||
|
mock_rpc_device.mock_online()
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
# Mock update
|
||||||
mock_rpc_device.mock_update()
|
mock_rpc_device.mock_update()
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
@ -533,6 +538,10 @@ async def test_rpc_restored_sleeping_sensor_no_last_state(
|
|||||||
|
|
||||||
# Make device online
|
# Make device online
|
||||||
monkeypatch.setattr(mock_rpc_device, "initialized", True)
|
monkeypatch.setattr(mock_rpc_device, "initialized", True)
|
||||||
|
mock_rpc_device.mock_online()
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
# Mock update
|
||||||
mock_rpc_device.mock_update()
|
mock_rpc_device.mock_update()
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
@ -583,19 +592,21 @@ async def test_rpc_sleeping_update_entity_service(
|
|||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
mock_rpc_device: Mock,
|
mock_rpc_device: Mock,
|
||||||
entity_registry: EntityRegistry,
|
entity_registry: EntityRegistry,
|
||||||
|
monkeypatch: pytest.MonkeyPatch,
|
||||||
caplog: pytest.LogCaptureFixture,
|
caplog: pytest.LogCaptureFixture,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test RPC sleeping device when the update_entity service is used."""
|
"""Test RPC sleeping device when the update_entity service is used."""
|
||||||
await async_setup_component(hass, "homeassistant", {})
|
await async_setup_component(hass, "homeassistant", {})
|
||||||
|
|
||||||
entity_id = f"{SENSOR_DOMAIN}.test_name_temperature"
|
entity_id = f"{SENSOR_DOMAIN}.test_name_temperature"
|
||||||
|
monkeypatch.setitem(mock_rpc_device.status["sys"], "wakeup_period", 1000)
|
||||||
await init_integration(hass, 2, sleep_period=1000)
|
await init_integration(hass, 2, sleep_period=1000)
|
||||||
|
|
||||||
# Entity should be created when device is online
|
# Entity should be created when device is online
|
||||||
assert hass.states.get(entity_id) is None
|
assert hass.states.get(entity_id) is None
|
||||||
|
|
||||||
# Make device online
|
# Make device online
|
||||||
mock_rpc_device.mock_update()
|
mock_rpc_device.mock_online()
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
state = hass.states.get(entity_id)
|
state = hass.states.get(entity_id)
|
||||||
@ -627,19 +638,25 @@ async def test_block_sleeping_update_entity_service(
|
|||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
mock_block_device: Mock,
|
mock_block_device: Mock,
|
||||||
entity_registry: EntityRegistry,
|
entity_registry: EntityRegistry,
|
||||||
|
monkeypatch: pytest.MonkeyPatch,
|
||||||
caplog: pytest.LogCaptureFixture,
|
caplog: pytest.LogCaptureFixture,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test block sleeping device when the update_entity service is used."""
|
"""Test block sleeping device when the update_entity service is used."""
|
||||||
await async_setup_component(hass, "homeassistant", {})
|
await async_setup_component(hass, "homeassistant", {})
|
||||||
|
|
||||||
entity_id = f"{SENSOR_DOMAIN}.test_name_temperature"
|
entity_id = f"{SENSOR_DOMAIN}.test_name_temperature"
|
||||||
await init_integration(hass, 1, sleep_period=1000)
|
monkeypatch.setitem(
|
||||||
|
mock_block_device.settings,
|
||||||
|
"sleep_mode",
|
||||||
|
{"period": 60, "unit": "m"},
|
||||||
|
)
|
||||||
|
await init_integration(hass, 1, sleep_period=3600)
|
||||||
|
|
||||||
# Sensor should be created when device is online
|
# Sensor should be created when device is online
|
||||||
assert hass.states.get(entity_id) is None
|
assert hass.states.get(entity_id) is None
|
||||||
|
|
||||||
# Make device online
|
# Make device online
|
||||||
mock_block_device.mock_update()
|
mock_block_device.mock_online()
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
assert hass.states.get(entity_id).state == "22.1"
|
assert hass.states.get(entity_id).state == "22.1"
|
||||||
|
@ -335,6 +335,7 @@ async def test_rpc_sleeping_update(
|
|||||||
monkeypatch: pytest.MonkeyPatch,
|
monkeypatch: pytest.MonkeyPatch,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test RPC sleeping device update entity."""
|
"""Test RPC sleeping device update entity."""
|
||||||
|
monkeypatch.setitem(mock_rpc_device.status["sys"], "wakeup_period", 1000)
|
||||||
monkeypatch.setitem(mock_rpc_device.shelly, "ver", "1")
|
monkeypatch.setitem(mock_rpc_device.shelly, "ver", "1")
|
||||||
monkeypatch.setitem(
|
monkeypatch.setitem(
|
||||||
mock_rpc_device.status["sys"],
|
mock_rpc_device.status["sys"],
|
||||||
@ -350,7 +351,7 @@ async def test_rpc_sleeping_update(
|
|||||||
assert hass.states.get(entity_id) is None
|
assert hass.states.get(entity_id) is None
|
||||||
|
|
||||||
# Make device online
|
# Make device online
|
||||||
mock_rpc_device.mock_update()
|
mock_rpc_device.mock_online()
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
state = hass.states.get(entity_id)
|
state = hass.states.get(entity_id)
|
||||||
@ -411,6 +412,10 @@ async def test_rpc_restored_sleeping_update(
|
|||||||
|
|
||||||
# Make device online
|
# Make device online
|
||||||
monkeypatch.setattr(mock_rpc_device, "initialized", True)
|
monkeypatch.setattr(mock_rpc_device, "initialized", True)
|
||||||
|
mock_rpc_device.mock_online()
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
# Mock update
|
||||||
mock_rpc_device.mock_update()
|
mock_rpc_device.mock_update()
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
@ -456,6 +461,10 @@ async def test_rpc_restored_sleeping_update_no_last_state(
|
|||||||
|
|
||||||
# Make device online
|
# Make device online
|
||||||
monkeypatch.setattr(mock_rpc_device, "initialized", True)
|
monkeypatch.setattr(mock_rpc_device, "initialized", True)
|
||||||
|
mock_rpc_device.mock_online()
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
# Mock update
|
||||||
mock_rpc_device.mock_update()
|
mock_rpc_device.mock_update()
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user