This commit is contained in:
Paulus Schoutsen 2023-01-10 15:58:26 -05:00 committed by GitHub
commit b297b78086
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
24 changed files with 65 additions and 108 deletions

View File

@ -2,7 +2,7 @@
"domain": "emulated_kasa", "domain": "emulated_kasa",
"name": "Emulated Kasa", "name": "Emulated Kasa",
"documentation": "https://www.home-assistant.io/integrations/emulated_kasa", "documentation": "https://www.home-assistant.io/integrations/emulated_kasa",
"requirements": ["sense_energy==0.11.0"], "requirements": ["sense_energy==0.11.1"],
"codeowners": ["@kbickar"], "codeowners": ["@kbickar"],
"quality_scale": "internal", "quality_scale": "internal",
"iot_class": "local_push", "iot_class": "local_push",

View File

@ -2,7 +2,7 @@
"domain": "frontend", "domain": "frontend",
"name": "Home Assistant Frontend", "name": "Home Assistant Frontend",
"documentation": "https://www.home-assistant.io/integrations/frontend", "documentation": "https://www.home-assistant.io/integrations/frontend",
"requirements": ["home-assistant-frontend==20230104.0"], "requirements": ["home-assistant-frontend==20230110.0"],
"dependencies": [ "dependencies": [
"api", "api",
"auth", "auth",

View File

@ -4,7 +4,7 @@
"config_flow": true, "config_flow": true,
"dependencies": ["application_credentials"], "dependencies": ["application_credentials"],
"documentation": "https://www.home-assistant.io/integrations/calendar.google/", "documentation": "https://www.home-assistant.io/integrations/calendar.google/",
"requirements": ["gcal-sync==4.1.1", "oauth2client==4.1.3"], "requirements": ["gcal-sync==4.1.2", "oauth2client==4.1.3"],
"codeowners": ["@allenporter"], "codeowners": ["@allenporter"],
"iot_class": "cloud_polling", "iot_class": "cloud_polling",
"loggers": ["googleapiclient"] "loggers": ["googleapiclient"]

View File

@ -58,8 +58,8 @@ SENSOR_TYPES = {
key="signal", key="signal",
name="signal strength", name="signal strength",
native_unit_of_measurement=PERCENTAGE, native_unit_of_measurement=PERCENTAGE,
device_class=SensorDeviceClass.SIGNAL_STRENGTH,
entity_category=EntityCategory.DIAGNOSTIC, entity_category=EntityCategory.DIAGNOSTIC,
icon="mdi:wifi",
), ),
"ssid": SensorEntityDescription( "ssid": SensorEntityDescription(
key="ssid", key="ssid",

View File

@ -31,7 +31,7 @@ from .const import (
DOMAIN, DOMAIN,
LOGGER, LOGGER,
) )
from .coordinator import InvalidApiKeyMonitor, OpenUvCoordinator from .coordinator import OpenUvCoordinator
PLATFORMS = [Platform.BINARY_SENSOR, Platform.SENSOR] PLATFORMS = [Platform.BINARY_SENSOR, Platform.SENSOR]
@ -45,6 +45,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
entry.data.get(CONF_LONGITUDE, hass.config.longitude), entry.data.get(CONF_LONGITUDE, hass.config.longitude),
altitude=entry.data.get(CONF_ELEVATION, hass.config.elevation), altitude=entry.data.get(CONF_ELEVATION, hass.config.elevation),
session=websession, session=websession,
check_status_before_request=True,
) )
async def async_update_protection_data() -> dict[str, Any]: async def async_update_protection_data() -> dict[str, Any]:
@ -53,16 +54,14 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
high = entry.options.get(CONF_TO_WINDOW, DEFAULT_TO_WINDOW) high = entry.options.get(CONF_TO_WINDOW, DEFAULT_TO_WINDOW)
return await client.uv_protection_window(low=low, high=high) return await client.uv_protection_window(low=low, high=high)
invalid_api_key_monitor = InvalidApiKeyMonitor(hass, entry)
coordinators: dict[str, OpenUvCoordinator] = { coordinators: dict[str, OpenUvCoordinator] = {
coordinator_name: OpenUvCoordinator( coordinator_name: OpenUvCoordinator(
hass, hass,
entry=entry,
name=coordinator_name, name=coordinator_name,
latitude=client.latitude, latitude=client.latitude,
longitude=client.longitude, longitude=client.longitude,
update_method=update_method, update_method=update_method,
invalid_api_key_monitor=invalid_api_key_monitor,
) )
for coordinator_name, update_method in ( for coordinator_name, update_method in (
(DATA_UV, client.uv_index), (DATA_UV, client.uv_index),
@ -70,16 +69,11 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
) )
} }
# We disable the client's request retry abilities here to avoid a lengthy (and
# blocking) startup; then, if the initial update is successful, we re-enable client
# request retries:
client.disable_request_retries()
init_tasks = [ init_tasks = [
coordinator.async_config_entry_first_refresh() coordinator.async_config_entry_first_refresh()
for coordinator in coordinators.values() for coordinator in coordinators.values()
] ]
await asyncio.gather(*init_tasks) await asyncio.gather(*init_tasks)
client.enable_request_retries()
hass.data.setdefault(DOMAIN, {}) hass.data.setdefault(DOMAIN, {})
hass.data[DOMAIN][entry.entry_id] = coordinators hass.data[DOMAIN][entry.entry_id] = coordinators

View File

@ -103,7 +103,6 @@ class OpenUvFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
"""Verify the credentials and create/re-auth the entry.""" """Verify the credentials and create/re-auth the entry."""
websession = aiohttp_client.async_get_clientsession(self.hass) websession = aiohttp_client.async_get_clientsession(self.hass)
client = Client(data.api_key, 0, 0, session=websession) client = Client(data.api_key, 0, 0, session=websession)
client.disable_request_retries()
try: try:
await client.uv_index() await client.uv_index()

View File

@ -1,15 +1,14 @@
"""Define an update coordinator for OpenUV.""" """Define an update coordinator for OpenUV."""
from __future__ import annotations from __future__ import annotations
import asyncio
from collections.abc import Awaitable, Callable from collections.abc import Awaitable, Callable
from typing import Any, cast from typing import Any, cast
from pyopenuv.errors import InvalidApiKeyError, OpenUvError from pyopenuv.errors import InvalidApiKeyError, OpenUvError
from homeassistant.config_entries import SOURCE_REAUTH, ConfigEntry from homeassistant.config_entries import SOURCE_REAUTH, ConfigEntry
from homeassistant.core import HomeAssistant, callback from homeassistant.core import HomeAssistant
from homeassistant.data_entry_flow import FlowResult from homeassistant.exceptions import ConfigEntryAuthFailed
from homeassistant.helpers.debounce import Debouncer from homeassistant.helpers.debounce import Debouncer
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
@ -18,64 +17,6 @@ from .const import LOGGER
DEFAULT_DEBOUNCER_COOLDOWN_SECONDS = 15 * 60 DEFAULT_DEBOUNCER_COOLDOWN_SECONDS = 15 * 60
class InvalidApiKeyMonitor:
"""Define a monitor for failed API calls (due to bad keys) across coordinators."""
DEFAULT_FAILED_API_CALL_THRESHOLD = 5
def __init__(self, hass: HomeAssistant, entry: ConfigEntry) -> None:
"""Initialize."""
self._count = 1
self._lock = asyncio.Lock()
self._reauth_flow_manager = ReauthFlowManager(hass, entry)
self.entry = entry
async def async_increment(self) -> None:
"""Increment the counter."""
async with self._lock:
self._count += 1
if self._count > self.DEFAULT_FAILED_API_CALL_THRESHOLD:
LOGGER.info("Starting reauth after multiple failed API calls")
self._reauth_flow_manager.start_reauth()
async def async_reset(self) -> None:
"""Reset the counter."""
async with self._lock:
self._count = 0
self._reauth_flow_manager.cancel_reauth()
class ReauthFlowManager:
"""Define an OpenUV reauth flow manager."""
def __init__(self, hass: HomeAssistant, entry: ConfigEntry) -> None:
"""Initialize."""
self.entry = entry
self.hass = hass
@callback
def _get_active_reauth_flow(self) -> FlowResult | None:
"""Get an active reauth flow (if it exists)."""
return next(
iter(self.entry.async_get_active_flows(self.hass, {SOURCE_REAUTH})),
None,
)
@callback
def cancel_reauth(self) -> None:
"""Cancel a reauth flow (if appropriate)."""
if reauth_flow := self._get_active_reauth_flow():
LOGGER.debug("API seems to have recovered; canceling reauth flow")
self.hass.config_entries.flow.async_abort(reauth_flow["flow_id"])
@callback
def start_reauth(self) -> None:
"""Start a reauth flow (if appropriate)."""
if not self._get_active_reauth_flow():
LOGGER.debug("Multiple API failures in a row; starting reauth flow")
self.entry.async_start_reauth(self.hass)
class OpenUvCoordinator(DataUpdateCoordinator): class OpenUvCoordinator(DataUpdateCoordinator):
"""Define an OpenUV data coordinator.""" """Define an OpenUV data coordinator."""
@ -86,11 +27,11 @@ class OpenUvCoordinator(DataUpdateCoordinator):
self, self,
hass: HomeAssistant, hass: HomeAssistant,
*, *,
entry: ConfigEntry,
name: str, name: str,
latitude: str, latitude: str,
longitude: str, longitude: str,
update_method: Callable[[], Awaitable[dict[str, Any]]], update_method: Callable[[], Awaitable[dict[str, Any]]],
invalid_api_key_monitor: InvalidApiKeyMonitor,
) -> None: ) -> None:
"""Initialize.""" """Initialize."""
super().__init__( super().__init__(
@ -106,7 +47,7 @@ class OpenUvCoordinator(DataUpdateCoordinator):
), ),
) )
self._invalid_api_key_monitor = invalid_api_key_monitor self._entry = entry
self.latitude = latitude self.latitude = latitude
self.longitude = longitude self.longitude = longitude
@ -115,10 +56,18 @@ class OpenUvCoordinator(DataUpdateCoordinator):
try: try:
data = await self.update_method() data = await self.update_method()
except InvalidApiKeyError as err: except InvalidApiKeyError as err:
await self._invalid_api_key_monitor.async_increment() raise ConfigEntryAuthFailed("Invalid API key") from err
raise UpdateFailed(str(err)) from err
except OpenUvError as err: except OpenUvError as err:
raise UpdateFailed(str(err)) from err raise UpdateFailed(str(err)) from err
await self._invalid_api_key_monitor.async_reset() # OpenUV uses HTTP 403 to indicate both an invalid API key and an API key that
# has hit its daily/monthly limit; both cases will result in a reauth flow. If
# coordinator update succeeds after a reauth flow has been started, terminate
# it:
if reauth_flow := next(
iter(self._entry.async_get_active_flows(self.hass, {SOURCE_REAUTH})),
None,
):
self.hass.config_entries.flow.async_abort(reauth_flow["flow_id"])
return cast(dict[str, Any], data["result"]) return cast(dict[str, Any], data["result"])

View File

@ -3,7 +3,7 @@
"name": "OpenUV", "name": "OpenUV",
"config_flow": true, "config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/openuv", "documentation": "https://www.home-assistant.io/integrations/openuv",
"requirements": ["pyopenuv==2022.04.0"], "requirements": ["pyopenuv==2023.01.0"],
"codeowners": ["@bachya"], "codeowners": ["@bachya"],
"iot_class": "cloud_polling", "iot_class": "cloud_polling",
"loggers": ["pyopenuv"], "loggers": ["pyopenuv"],

View File

@ -2,7 +2,7 @@
"domain": "sense", "domain": "sense",
"name": "Sense", "name": "Sense",
"documentation": "https://www.home-assistant.io/integrations/sense", "documentation": "https://www.home-assistant.io/integrations/sense",
"requirements": ["sense_energy==0.11.0"], "requirements": ["sense_energy==0.11.1"],
"codeowners": ["@kbickar"], "codeowners": ["@kbickar"],
"config_flow": true, "config_flow": true,
"dhcp": [ "dhcp": [

View File

@ -509,7 +509,8 @@ class ShellyRpcCoordinator(DataUpdateCoordinator[None]):
This will be executed on connect or when the config entry This will be executed on connect or when the config entry
is updated. is updated.
""" """
await self._async_connect_ble_scanner() if not self.entry.data.get(CONF_SLEEP_PERIOD):
await self._async_connect_ble_scanner()
async def _async_connect_ble_scanner(self) -> None: async def _async_connect_ble_scanner(self) -> None:
"""Connect BLE scanner.""" """Connect BLE scanner."""

View File

@ -3,7 +3,7 @@
"name": "Shelly", "name": "Shelly",
"config_flow": true, "config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/shelly", "documentation": "https://www.home-assistant.io/integrations/shelly",
"requirements": ["aioshelly==5.2.0"], "requirements": ["aioshelly==5.2.1"],
"dependencies": ["bluetooth", "http"], "dependencies": ["bluetooth", "http"],
"zeroconf": [ "zeroconf": [
{ {

View File

@ -131,7 +131,6 @@ EV_SENSORS = [
key=sc.EV_TIME_TO_FULLY_CHARGED_UTC, key=sc.EV_TIME_TO_FULLY_CHARGED_UTC,
device_class=SensorDeviceClass.TIMESTAMP, device_class=SensorDeviceClass.TIMESTAMP,
name="EV time to full charge", name="EV time to full charge",
state_class=SensorStateClass.MEASUREMENT,
), ),
] ]

View File

@ -3,7 +3,7 @@
"name": "Tasmota", "name": "Tasmota",
"config_flow": true, "config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/tasmota", "documentation": "https://www.home-assistant.io/integrations/tasmota",
"requirements": ["hatasmota==0.6.2"], "requirements": ["hatasmota==0.6.3"],
"dependencies": ["mqtt"], "dependencies": ["mqtt"],
"mqtt": ["tasmota/discovery/#"], "mqtt": ["tasmota/discovery/#"],
"codeowners": ["@emontnemery"], "codeowners": ["@emontnemery"],

View File

@ -337,7 +337,7 @@ EVENT_SENSORS: tuple[ProtectBinaryEventEntityDescription, ...] = (
name="Doorbell", name="Doorbell",
device_class=BinarySensorDeviceClass.OCCUPANCY, device_class=BinarySensorDeviceClass.OCCUPANCY,
icon="mdi:doorbell-video", icon="mdi:doorbell-video",
ufp_required_field="feature_flags.has_chime", ufp_required_field="feature_flags.is_doorbell",
ufp_value="is_ringing", ufp_value="is_ringing",
ufp_event_obj="last_ring_event", ufp_event_obj="last_ring_event",
), ),

View File

@ -4,7 +4,7 @@
"integration_type": "hub", "integration_type": "hub",
"config_flow": true, "config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/unifiprotect", "documentation": "https://www.home-assistant.io/integrations/unifiprotect",
"requirements": ["pyunifiprotect==4.5.2", "unifi-discovery==1.1.7"], "requirements": ["pyunifiprotect==4.6.1", "unifi-discovery==1.1.7"],
"dependencies": ["http", "repairs"], "dependencies": ["http", "repairs"],
"codeowners": ["@briis", "@AngellusMortis", "@bdraco"], "codeowners": ["@briis", "@AngellusMortis", "@bdraco"],
"quality_scale": "platinum", "quality_scale": "platinum",

View File

@ -770,7 +770,7 @@ class ProtectMediaSource(MediaSource):
if camera is None: if camera is None:
raise BrowseError(f"Unknown Camera ID: {camera_id}") raise BrowseError(f"Unknown Camera ID: {camera_id}")
name = camera.name or camera.market_name or camera.type name = camera.name or camera.market_name or camera.type
is_doorbell = camera.feature_flags.has_chime is_doorbell = camera.feature_flags.is_doorbell
has_smart = camera.feature_flags.has_smart_detect has_smart = camera.feature_flags.has_smart_detect
thumbnail_url: str | None = None thumbnail_url: str | None = None

View File

@ -206,7 +206,7 @@ CAMERA_SENSORS: tuple[ProtectSensorEntityDescription, ...] = (
name="Last Doorbell Ring", name="Last Doorbell Ring",
device_class=SensorDeviceClass.TIMESTAMP, device_class=SensorDeviceClass.TIMESTAMP,
icon="mdi:doorbell-video", icon="mdi:doorbell-video",
ufp_required_field="feature_flags.has_chime", ufp_required_field="feature_flags.is_doorbell",
ufp_value="last_ring", ufp_value="last_ring",
entity_registry_enabled_default=False, entity_registry_enabled_default=False,
), ),

View File

@ -8,7 +8,7 @@ from .backports.enum import StrEnum
APPLICATION_NAME: Final = "HomeAssistant" APPLICATION_NAME: Final = "HomeAssistant"
MAJOR_VERSION: Final = 2023 MAJOR_VERSION: Final = 2023
MINOR_VERSION: Final = 1 MINOR_VERSION: Final = 1
PATCH_VERSION: Final = "2" PATCH_VERSION: Final = "3"
__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, 9, 0) REQUIRED_PYTHON_VER: Final[tuple[int, int, int]] = (3, 9, 0)

View File

@ -22,7 +22,7 @@ dbus-fast==1.82.0
fnvhash==0.1.0 fnvhash==0.1.0
hass-nabucasa==0.61.0 hass-nabucasa==0.61.0
home-assistant-bluetooth==1.9.2 home-assistant-bluetooth==1.9.2
home-assistant-frontend==20230104.0 home-assistant-frontend==20230110.0
httpx==0.23.2 httpx==0.23.2
ifaddr==0.1.7 ifaddr==0.1.7
janus==1.0.0 janus==1.0.0

View File

@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
[project] [project]
name = "homeassistant" name = "homeassistant"
version = "2023.1.2" version = "2023.1.3"
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"

View File

@ -267,7 +267,7 @@ aiosenseme==0.6.1
aiosenz==1.0.0 aiosenz==1.0.0
# homeassistant.components.shelly # homeassistant.components.shelly
aioshelly==5.2.0 aioshelly==5.2.1
# homeassistant.components.skybell # homeassistant.components.skybell
aioskybell==22.7.0 aioskybell==22.7.0
@ -744,7 +744,7 @@ gTTS==2.2.4
gassist-text==0.0.7 gassist-text==0.0.7
# homeassistant.components.google # homeassistant.components.google
gcal-sync==4.1.1 gcal-sync==4.1.2
# homeassistant.components.geniushub # homeassistant.components.geniushub
geniushub-client==0.6.30 geniushub-client==0.6.30
@ -858,7 +858,7 @@ hass-nabucasa==0.61.0
hass_splunk==0.1.1 hass_splunk==0.1.1
# homeassistant.components.tasmota # homeassistant.components.tasmota
hatasmota==0.6.2 hatasmota==0.6.3
# homeassistant.components.jewish_calendar # homeassistant.components.jewish_calendar
hdate==0.10.4 hdate==0.10.4
@ -888,7 +888,7 @@ hole==0.8.0
holidays==0.17.2 holidays==0.17.2
# homeassistant.components.frontend # homeassistant.components.frontend
home-assistant-frontend==20230104.0 home-assistant-frontend==20230110.0
# homeassistant.components.home_connect # homeassistant.components.home_connect
homeconnect==0.7.2 homeconnect==0.7.2
@ -1803,7 +1803,7 @@ pyoctoprintapi==0.1.9
pyombi==0.1.10 pyombi==0.1.10
# homeassistant.components.openuv # homeassistant.components.openuv
pyopenuv==2022.04.0 pyopenuv==2023.01.0
# homeassistant.components.opnsense # homeassistant.components.opnsense
pyopnsense==0.2.0 pyopnsense==0.2.0
@ -2109,7 +2109,7 @@ pytrafikverket==0.2.2
pyudev==0.23.2 pyudev==0.23.2
# homeassistant.components.unifiprotect # homeassistant.components.unifiprotect
pyunifiprotect==4.5.2 pyunifiprotect==4.6.1
# homeassistant.components.uptimerobot # homeassistant.components.uptimerobot
pyuptimerobot==22.2.0 pyuptimerobot==22.2.0
@ -2269,7 +2269,7 @@ sendgrid==6.8.2
# homeassistant.components.emulated_kasa # homeassistant.components.emulated_kasa
# homeassistant.components.sense # homeassistant.components.sense
sense_energy==0.11.0 sense_energy==0.11.1
# homeassistant.components.sensirion_ble # homeassistant.components.sensirion_ble
sensirion-ble==0.0.1 sensirion-ble==0.0.1

View File

@ -242,7 +242,7 @@ aiosenseme==0.6.1
aiosenz==1.0.0 aiosenz==1.0.0
# homeassistant.components.shelly # homeassistant.components.shelly
aioshelly==5.2.0 aioshelly==5.2.1
# homeassistant.components.skybell # homeassistant.components.skybell
aioskybell==22.7.0 aioskybell==22.7.0
@ -560,7 +560,7 @@ gTTS==2.2.4
gassist-text==0.0.7 gassist-text==0.0.7
# homeassistant.components.google # homeassistant.components.google
gcal-sync==4.1.1 gcal-sync==4.1.2
# homeassistant.components.geocaching # homeassistant.components.geocaching
geocachingapi==0.2.1 geocachingapi==0.2.1
@ -647,7 +647,7 @@ habitipy==0.2.0
hass-nabucasa==0.61.0 hass-nabucasa==0.61.0
# homeassistant.components.tasmota # homeassistant.components.tasmota
hatasmota==0.6.2 hatasmota==0.6.3
# homeassistant.components.jewish_calendar # homeassistant.components.jewish_calendar
hdate==0.10.4 hdate==0.10.4
@ -668,7 +668,7 @@ hole==0.8.0
holidays==0.17.2 holidays==0.17.2
# homeassistant.components.frontend # homeassistant.components.frontend
home-assistant-frontend==20230104.0 home-assistant-frontend==20230110.0
# homeassistant.components.home_connect # homeassistant.components.home_connect
homeconnect==0.7.2 homeconnect==0.7.2
@ -1283,7 +1283,7 @@ pynzbgetapi==0.2.0
pyoctoprintapi==0.1.9 pyoctoprintapi==0.1.9
# homeassistant.components.openuv # homeassistant.components.openuv
pyopenuv==2022.04.0 pyopenuv==2023.01.0
# homeassistant.components.opnsense # homeassistant.components.opnsense
pyopnsense==0.2.0 pyopnsense==0.2.0
@ -1475,7 +1475,7 @@ pytrafikverket==0.2.2
pyudev==0.23.2 pyudev==0.23.2
# homeassistant.components.unifiprotect # homeassistant.components.unifiprotect
pyunifiprotect==4.5.2 pyunifiprotect==4.6.1
# homeassistant.components.uptimerobot # homeassistant.components.uptimerobot
pyuptimerobot==22.2.0 pyuptimerobot==22.2.0
@ -1578,7 +1578,7 @@ securetar==2022.2.0
# homeassistant.components.emulated_kasa # homeassistant.components.emulated_kasa
# homeassistant.components.sense # homeassistant.components.sense
sense_energy==0.11.0 sense_energy==0.11.1
# homeassistant.components.sensirion_ble # homeassistant.components.sensirion_ble
sensirion-ble==0.0.1 sensirion-ble==0.0.1

View File

@ -213,7 +213,7 @@ async def test_entry_unload_not_connected(hass, mock_rpc_device, monkeypatch):
assert entry.state is ConfigEntryState.LOADED assert entry.state is ConfigEntryState.LOADED
async def test_entry_unload_not_connected_but_we_with_we_are( async def test_entry_unload_not_connected_but_we_think_we_are(
hass, mock_rpc_device, monkeypatch hass, mock_rpc_device, monkeypatch
): ):
"""Test entry unload when not connected but we think we are still connected.""" """Test entry unload when not connected but we think we are still connected."""
@ -238,3 +238,17 @@ async def test_entry_unload_not_connected_but_we_with_we_are(
assert not mock_stop_scanner.call_count assert not mock_stop_scanner.call_count
assert entry.state is ConfigEntryState.LOADED assert entry.state is ConfigEntryState.LOADED
async def test_no_attempt_to_stop_scanner_with_sleepy_devices(hass, mock_rpc_device):
"""Test we do not try to stop the scanner if its disabled with a sleepy device."""
with patch(
"homeassistant.components.shelly.coordinator.async_stop_scanner",
) as mock_stop_scanner:
entry = await init_integration(hass, 2, sleep_period=7200)
assert entry.state is ConfigEntryState.LOADED
assert not mock_stop_scanner.call_count
mock_rpc_device.mock_update()
await hass.async_block_till_done()
assert not mock_stop_scanner.call_count

View File

@ -214,6 +214,7 @@ def doorbell_fixture(camera: Camera, fixed_now: datetime):
doorbell.feature_flags.has_lcd_screen = True doorbell.feature_flags.has_lcd_screen = True
doorbell.feature_flags.has_speaker = True doorbell.feature_flags.has_speaker = True
doorbell.feature_flags.has_privacy_mask = True doorbell.feature_flags.has_privacy_mask = True
doorbell.feature_flags.is_doorbell = True
doorbell.feature_flags.has_chime = True doorbell.feature_flags.has_chime = True
doorbell.feature_flags.has_smart_detect = True doorbell.feature_flags.has_smart_detect = True
doorbell.feature_flags.has_package_camera = True doorbell.feature_flags.has_package_camera = True