forked from home-assistant/core
Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b2fd8836c9 | |||
| 31e9de3b95 | |||
| ed1eb8ac9c | |||
| d09a274548 | |||
| 02b142fbde | |||
| 33b4f40b2a |
@@ -36,7 +36,7 @@ env:
|
||||
CACHE_VERSION: 9
|
||||
UV_CACHE_VERSION: 1
|
||||
MYPY_CACHE_VERSION: 8
|
||||
HA_SHORT_VERSION: "2024.7"
|
||||
HA_SHORT_VERSION: "2024.8"
|
||||
DEFAULT_PYTHON: "3.12"
|
||||
ALL_PYTHON_VERSIONS: "['3.12']"
|
||||
# 10.3 is the oldest supported version
|
||||
|
||||
@@ -7,5 +7,5 @@
|
||||
"integration_type": "service",
|
||||
"iot_class": "local_polling",
|
||||
"loggers": ["adguardhome"],
|
||||
"requirements": ["adguardhome==0.7.0"]
|
||||
"requirements": ["adguardhome==0.6.3"]
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ from homeassistant.components.media_player import (
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import CONF_MODEL
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.exceptions import HomeAssistantError, ServiceValidationError
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
from homeassistant.helpers.device_registry import DeviceInfo
|
||||
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
@@ -316,7 +316,7 @@ class BangOlufsenMediaPlayer(BangOlufsenEntity, MediaPlayerEntity):
|
||||
@callback
|
||||
def _async_update_playback_error(self, data: PlaybackError) -> None:
|
||||
"""Show playback error."""
|
||||
raise HomeAssistantError(data.error)
|
||||
_LOGGER.error(data.error)
|
||||
|
||||
@callback
|
||||
def _async_update_playback_progress(self, data: PlaybackProgress) -> None:
|
||||
@@ -516,9 +516,7 @@ class BangOlufsenMediaPlayer(BangOlufsenEntity, MediaPlayerEntity):
|
||||
|
||||
self.async_write_ha_state()
|
||||
else:
|
||||
raise HomeAssistantError(
|
||||
translation_domain=DOMAIN, translation_key="non_deezer_seeking"
|
||||
)
|
||||
_LOGGER.error("Seeking is currently only supported when using Deezer")
|
||||
|
||||
async def async_media_previous_track(self) -> None:
|
||||
"""Send the previous track command."""
|
||||
@@ -531,14 +529,12 @@ class BangOlufsenMediaPlayer(BangOlufsenEntity, MediaPlayerEntity):
|
||||
async def async_select_source(self, source: str) -> None:
|
||||
"""Select an input source."""
|
||||
if source not in self._sources.values():
|
||||
raise ServiceValidationError(
|
||||
translation_domain=DOMAIN,
|
||||
translation_key="invalid_source",
|
||||
translation_placeholders={
|
||||
"invalid_source": source,
|
||||
"valid_sources": ",".join(list(self._sources.values())),
|
||||
},
|
||||
_LOGGER.error(
|
||||
"Invalid source: %s. Valid sources are: %s",
|
||||
source,
|
||||
list(self._sources.values()),
|
||||
)
|
||||
return
|
||||
|
||||
key = [x for x in self._sources if self._sources[x] == source][0]
|
||||
|
||||
@@ -563,14 +559,12 @@ class BangOlufsenMediaPlayer(BangOlufsenEntity, MediaPlayerEntity):
|
||||
media_type = MediaType.MUSIC
|
||||
|
||||
if media_type not in VALID_MEDIA_TYPES:
|
||||
raise ServiceValidationError(
|
||||
translation_domain=DOMAIN,
|
||||
translation_key="invalid_media_type",
|
||||
translation_placeholders={
|
||||
"invalid_media_type": media_type,
|
||||
"valid_media_types": ",".join(VALID_MEDIA_TYPES),
|
||||
},
|
||||
_LOGGER.error(
|
||||
"%s is an invalid type. Valid values are: %s",
|
||||
media_type,
|
||||
VALID_MEDIA_TYPES,
|
||||
)
|
||||
return
|
||||
|
||||
if media_source.is_media_source_id(media_id):
|
||||
sourced_media = await media_source.async_resolve_media(
|
||||
@@ -687,14 +681,7 @@ class BangOlufsenMediaPlayer(BangOlufsenEntity, MediaPlayerEntity):
|
||||
)
|
||||
|
||||
except ApiException as error:
|
||||
raise HomeAssistantError(
|
||||
translation_domain=DOMAIN,
|
||||
translation_key="play_media_error",
|
||||
translation_placeholders={
|
||||
"media_type": media_type,
|
||||
"error_message": json.loads(error.body)["message"],
|
||||
},
|
||||
) from error
|
||||
_LOGGER.error(json.loads(error.body)["message"])
|
||||
|
||||
async def async_browse_media(
|
||||
self,
|
||||
|
||||
@@ -28,18 +28,6 @@
|
||||
"exceptions": {
|
||||
"m3u_invalid_format": {
|
||||
"message": "Media sources with the .m3u extension are not supported."
|
||||
},
|
||||
"non_deezer_seeking": {
|
||||
"message": "Seeking is currently only supported when using Deezer"
|
||||
},
|
||||
"invalid_source": {
|
||||
"message": "Invalid source: {invalid_source}. Valid sources are: {valid_sources}"
|
||||
},
|
||||
"invalid_media_type": {
|
||||
"message": "{invalid_media_type} is an invalid type. Valid values are: {valid_media_types}."
|
||||
},
|
||||
"play_media_error": {
|
||||
"message": "An error occurred while attempting to play {media_type}: {error_message}."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,9 +81,6 @@
|
||||
}
|
||||
},
|
||||
"exceptions": {
|
||||
"manual_switching_disabled": {
|
||||
"message": "Can't toggle switch while manual switching is disabled for the device."
|
||||
},
|
||||
"change_preset_while_active_mode": {
|
||||
"message": "Can't change preset while holiday or summer mode is active on the device."
|
||||
},
|
||||
|
||||
@@ -6,11 +6,9 @@ from typing import Any
|
||||
|
||||
from homeassistant.components.switch import SwitchEntity
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
|
||||
from . import FritzBoxDeviceEntity
|
||||
from .const import DOMAIN
|
||||
from .coordinator import FritzboxConfigEntry
|
||||
|
||||
|
||||
@@ -50,20 +48,10 @@ class FritzboxSwitch(FritzBoxDeviceEntity, SwitchEntity):
|
||||
|
||||
async def async_turn_on(self, **kwargs: Any) -> None:
|
||||
"""Turn the switch on."""
|
||||
self.check_lock_state()
|
||||
await self.hass.async_add_executor_job(self.data.set_switch_state_on)
|
||||
await self.coordinator.async_refresh()
|
||||
|
||||
async def async_turn_off(self, **kwargs: Any) -> None:
|
||||
"""Turn the switch off."""
|
||||
self.check_lock_state()
|
||||
await self.hass.async_add_executor_job(self.data.set_switch_state_off)
|
||||
await self.coordinator.async_refresh()
|
||||
|
||||
def check_lock_state(self) -> None:
|
||||
"""Raise an Error if manual switching via FRITZ!Box user interface is disabled."""
|
||||
if self.data.lock:
|
||||
raise HomeAssistantError(
|
||||
translation_domain=DOMAIN,
|
||||
translation_key="manual_switching_disabled",
|
||||
)
|
||||
|
||||
@@ -20,5 +20,5 @@
|
||||
"documentation": "https://www.home-assistant.io/integrations/frontend",
|
||||
"integration_type": "system",
|
||||
"quality_scale": "internal",
|
||||
"requirements": ["home-assistant-frontend==20240626.2"]
|
||||
"requirements": ["home-assistant-frontend==20240626.0"]
|
||||
}
|
||||
|
||||
@@ -483,7 +483,7 @@ class HomeAssistantHTTP:
|
||||
frame.report(
|
||||
"calls hass.http.register_static_path which is deprecated because "
|
||||
"it does blocking I/O in the event loop, instead "
|
||||
"call `await hass.http.async_register_static_paths("
|
||||
"call `await hass.http.async_register_static_path("
|
||||
f'[StaticPathConfig("{url_path}", "{path}", {cache_headers})])`; '
|
||||
"This function will be removed in 2025.7",
|
||||
exclude_integrations={"http"},
|
||||
|
||||
@@ -446,6 +446,7 @@ class IntegrationSensor(RestoreSensor):
|
||||
event_filter=callback(
|
||||
lambda event_data: event_data["entity_id"] == self._sensor_source_id
|
||||
),
|
||||
run_immediately=True,
|
||||
)
|
||||
)
|
||||
self.async_on_remove(
|
||||
@@ -455,6 +456,7 @@ class IntegrationSensor(RestoreSensor):
|
||||
event_filter=callback(
|
||||
lambda event_data: event_data["entity_id"] == self._sensor_source_id
|
||||
),
|
||||
run_immediately=True,
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
@@ -28,6 +28,8 @@ SCAN_INTERVAL = timedelta(seconds=30)
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
type RoborockConfigEntry = ConfigEntry[RoborockCoordinators]
|
||||
|
||||
|
||||
@dataclass
|
||||
class RoborockCoordinators:
|
||||
@@ -43,7 +45,7 @@ class RoborockCoordinators:
|
||||
return self.v1 + self.a01
|
||||
|
||||
|
||||
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||
async def async_setup_entry(hass: HomeAssistant, entry: RoborockConfigEntry) -> bool:
|
||||
"""Set up roborock from a config entry."""
|
||||
|
||||
_LOGGER.debug("Integration async setup entry: %s", entry.as_dict())
|
||||
@@ -99,7 +101,16 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||
translation_key="no_coordinators",
|
||||
)
|
||||
valid_coordinators = RoborockCoordinators(v1_coords, a01_coords)
|
||||
hass.data.setdefault(DOMAIN, {})[entry.entry_id] = valid_coordinators
|
||||
|
||||
async def on_unload() -> None:
|
||||
release_tasks = set()
|
||||
for coordinator in valid_coordinators.values():
|
||||
release_tasks.add(coordinator.release())
|
||||
await asyncio.gather(*release_tasks)
|
||||
|
||||
entry.async_on_unload(on_unload)
|
||||
entry.runtime_data = valid_coordinators
|
||||
|
||||
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
|
||||
|
||||
return True
|
||||
@@ -231,18 +242,12 @@ async def setup_device_a01(
|
||||
return coord
|
||||
|
||||
|
||||
async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||
async def async_unload_entry(hass: HomeAssistant, entry: RoborockConfigEntry) -> bool:
|
||||
"""Handle removal of an entry."""
|
||||
if unload_ok := await hass.config_entries.async_unload_platforms(entry, PLATFORMS):
|
||||
release_tasks = set()
|
||||
for coordinator in hass.data[DOMAIN][entry.entry_id].values():
|
||||
release_tasks.add(coordinator.release())
|
||||
hass.data[DOMAIN].pop(entry.entry_id)
|
||||
await asyncio.gather(*release_tasks)
|
||||
return unload_ok
|
||||
return await hass.config_entries.async_unload_platforms(entry, PLATFORMS)
|
||||
|
||||
|
||||
async def update_listener(hass: HomeAssistant, entry: ConfigEntry) -> None:
|
||||
async def update_listener(hass: HomeAssistant, entry: RoborockConfigEntry) -> None:
|
||||
"""Handle options update."""
|
||||
# Reload entry to update data
|
||||
await hass.config_entries.async_reload(entry.entry_id)
|
||||
|
||||
@@ -12,14 +12,12 @@ from homeassistant.components.binary_sensor import (
|
||||
BinarySensorEntity,
|
||||
BinarySensorEntityDescription,
|
||||
)
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import EntityCategory
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.util import slugify
|
||||
|
||||
from . import RoborockCoordinators
|
||||
from .const import DOMAIN
|
||||
from . import RoborockConfigEntry
|
||||
from .coordinator import RoborockDataUpdateCoordinator
|
||||
from .device import RoborockCoordinatedEntityV1
|
||||
|
||||
@@ -72,17 +70,16 @@ BINARY_SENSOR_DESCRIPTIONS = [
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
config_entry: ConfigEntry,
|
||||
config_entry: RoborockConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up the Roborock vacuum binary sensors."""
|
||||
coordinators: RoborockCoordinators = hass.data[DOMAIN][config_entry.entry_id]
|
||||
async_add_entities(
|
||||
RoborockBinarySensorEntity(
|
||||
coordinator,
|
||||
description,
|
||||
)
|
||||
for coordinator in coordinators.v1
|
||||
for coordinator in config_entry.runtime_data.v1
|
||||
for description in BINARY_SENSOR_DESCRIPTIONS
|
||||
if description.value_fn(coordinator.roborock_device_info.props) is not None
|
||||
)
|
||||
|
||||
@@ -7,14 +7,12 @@ from dataclasses import dataclass
|
||||
from roborock.roborock_typing import RoborockCommand
|
||||
|
||||
from homeassistant.components.button import ButtonEntity, ButtonEntityDescription
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import EntityCategory
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.util import slugify
|
||||
|
||||
from . import RoborockCoordinators
|
||||
from .const import DOMAIN
|
||||
from . import RoborockConfigEntry
|
||||
from .coordinator import RoborockDataUpdateCoordinator
|
||||
from .device import RoborockEntityV1
|
||||
|
||||
@@ -65,17 +63,16 @@ CONSUMABLE_BUTTON_DESCRIPTIONS = [
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
config_entry: ConfigEntry,
|
||||
config_entry: RoborockConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up Roborock button platform."""
|
||||
coordinators: RoborockCoordinators = hass.data[DOMAIN][config_entry.entry_id]
|
||||
async_add_entities(
|
||||
RoborockButtonEntity(
|
||||
coordinator,
|
||||
description,
|
||||
)
|
||||
for coordinator in coordinators.v1
|
||||
for coordinator in config_entry.runtime_data.v1
|
||||
for description in CONSUMABLE_BUTTON_DESCRIPTIONS
|
||||
if isinstance(coordinator, RoborockDataUpdateCoordinator)
|
||||
)
|
||||
|
||||
@@ -5,12 +5,10 @@ from __future__ import annotations
|
||||
from typing import Any
|
||||
|
||||
from homeassistant.components.diagnostics.util import async_redact_data
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import CONF_UNIQUE_ID
|
||||
from homeassistant.core import HomeAssistant
|
||||
|
||||
from . import RoborockCoordinators
|
||||
from .const import DOMAIN
|
||||
from . import RoborockConfigEntry
|
||||
|
||||
TO_REDACT_CONFIG = ["token", "sn", "rruid", CONF_UNIQUE_ID, "username", "uid"]
|
||||
|
||||
@@ -18,10 +16,10 @@ TO_REDACT_COORD = ["duid", "localKey", "mac", "bssid"]
|
||||
|
||||
|
||||
async def async_get_config_entry_diagnostics(
|
||||
hass: HomeAssistant, config_entry: ConfigEntry
|
||||
hass: HomeAssistant, config_entry: RoborockConfigEntry
|
||||
) -> dict[str, Any]:
|
||||
"""Return diagnostics for a config entry."""
|
||||
coordinators: RoborockCoordinators = hass.data[DOMAIN][config_entry.entry_id]
|
||||
coordinators = config_entry.runtime_data
|
||||
|
||||
return {
|
||||
"config_entry": async_redact_data(config_entry.data, TO_REDACT_CONFIG),
|
||||
|
||||
@@ -13,7 +13,6 @@ from vacuum_map_parser_base.config.size import Sizes
|
||||
from vacuum_map_parser_roborock.map_data_parser import RoborockMapDataParser
|
||||
|
||||
from homeassistant.components.image import ImageEntity
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import EntityCategory
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
@@ -21,7 +20,7 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.util import slugify
|
||||
import homeassistant.util.dt as dt_util
|
||||
|
||||
from . import RoborockCoordinators
|
||||
from . import RoborockConfigEntry
|
||||
from .const import DEFAULT_DRAWABLES, DOMAIN, DRAWABLES, IMAGE_CACHE_INTERVAL, MAP_SLEEP
|
||||
from .coordinator import RoborockDataUpdateCoordinator
|
||||
from .device import RoborockCoordinatedEntityV1
|
||||
@@ -29,12 +28,11 @@ from .device import RoborockCoordinatedEntityV1
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
config_entry: ConfigEntry,
|
||||
config_entry: RoborockConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up Roborock image platform."""
|
||||
|
||||
coordinators: RoborockCoordinators = hass.data[DOMAIN][config_entry.entry_id]
|
||||
drawables = [
|
||||
drawable
|
||||
for drawable, default_value in DEFAULT_DRAWABLES.items()
|
||||
@@ -45,7 +43,7 @@ async def async_setup_entry(
|
||||
await asyncio.gather(
|
||||
*(
|
||||
create_coordinator_maps(coord, drawables)
|
||||
for coord in coordinators.v1
|
||||
for coord in config_entry.runtime_data.v1
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
@@ -11,14 +11,12 @@ from roborock.exceptions import RoborockException
|
||||
from roborock.version_1_apis.roborock_client_v1 import AttributeCache
|
||||
|
||||
from homeassistant.components.number import NumberEntity, NumberEntityDescription
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import PERCENTAGE, EntityCategory
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.util import slugify
|
||||
|
||||
from . import RoborockCoordinators
|
||||
from .const import DOMAIN
|
||||
from . import RoborockConfigEntry
|
||||
from .coordinator import RoborockDataUpdateCoordinator
|
||||
from .device import RoborockEntityV1
|
||||
|
||||
@@ -51,16 +49,15 @@ NUMBER_DESCRIPTIONS: list[RoborockNumberDescription] = [
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
config_entry: ConfigEntry,
|
||||
config_entry: RoborockConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up Roborock number platform."""
|
||||
coordinators: RoborockCoordinators = hass.data[DOMAIN][config_entry.entry_id]
|
||||
possible_entities: list[
|
||||
tuple[RoborockDataUpdateCoordinator, RoborockNumberDescription]
|
||||
] = [
|
||||
(coordinator, description)
|
||||
for coordinator in coordinators.v1
|
||||
for coordinator in config_entry.runtime_data.v1
|
||||
for description in NUMBER_DESCRIPTIONS
|
||||
]
|
||||
# We need to check if this function is supported by the device.
|
||||
|
||||
@@ -8,14 +8,12 @@ from roborock.roborock_message import RoborockDataProtocol
|
||||
from roborock.roborock_typing import RoborockCommand
|
||||
|
||||
from homeassistant.components.select import SelectEntity, SelectEntityDescription
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import EntityCategory
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.util import slugify
|
||||
|
||||
from . import RoborockCoordinators
|
||||
from .const import DOMAIN
|
||||
from . import RoborockConfigEntry
|
||||
from .coordinator import RoborockDataUpdateCoordinator
|
||||
from .device import RoborockCoordinatedEntityV1
|
||||
|
||||
@@ -65,15 +63,14 @@ SELECT_DESCRIPTIONS: list[RoborockSelectDescription] = [
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
config_entry: ConfigEntry,
|
||||
config_entry: RoborockConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up Roborock select platform."""
|
||||
|
||||
coordinators: RoborockCoordinators = hass.data[DOMAIN][config_entry.entry_id]
|
||||
async_add_entities(
|
||||
RoborockSelectEntity(coordinator, description, options)
|
||||
for coordinator in coordinators.v1
|
||||
for coordinator in config_entry.runtime_data.v1
|
||||
for description in SELECT_DESCRIPTIONS
|
||||
if (
|
||||
options := description.options_lambda(
|
||||
|
||||
@@ -21,7 +21,6 @@ from homeassistant.components.sensor import (
|
||||
SensorEntity,
|
||||
SensorEntityDescription,
|
||||
)
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import (
|
||||
AREA_SQUARE_METERS,
|
||||
PERCENTAGE,
|
||||
@@ -33,8 +32,7 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.typing import StateType
|
||||
from homeassistant.util import slugify
|
||||
|
||||
from . import RoborockCoordinators
|
||||
from .const import DOMAIN
|
||||
from . import RoborockConfigEntry
|
||||
from .coordinator import RoborockDataUpdateCoordinator, RoborockDataUpdateCoordinatorA01
|
||||
from .device import RoborockCoordinatedEntityA01, RoborockCoordinatedEntityV1
|
||||
|
||||
@@ -255,11 +253,11 @@ A01_SENSOR_DESCRIPTIONS: list[RoborockSensorDescriptionA01] = [
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
config_entry: ConfigEntry,
|
||||
config_entry: RoborockConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up the Roborock vacuum sensors."""
|
||||
coordinators: RoborockCoordinators = hass.data[DOMAIN][config_entry.entry_id]
|
||||
coordinators = config_entry.runtime_data
|
||||
async_add_entities(
|
||||
RoborockSensorEntity(
|
||||
coordinator,
|
||||
|
||||
@@ -12,14 +12,12 @@ from roborock.command_cache import CacheableAttribute
|
||||
from roborock.version_1_apis.roborock_client_v1 import AttributeCache
|
||||
|
||||
from homeassistant.components.switch import SwitchEntity, SwitchEntityDescription
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import EntityCategory
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.util import slugify
|
||||
|
||||
from . import RoborockCoordinators
|
||||
from .const import DOMAIN
|
||||
from . import RoborockConfigEntry
|
||||
from .coordinator import RoborockDataUpdateCoordinator
|
||||
from .device import RoborockEntityV1
|
||||
|
||||
@@ -99,16 +97,15 @@ SWITCH_DESCRIPTIONS: list[RoborockSwitchDescription] = [
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
config_entry: ConfigEntry,
|
||||
config_entry: RoborockConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up Roborock switch platform."""
|
||||
coordinators: RoborockCoordinators = hass.data[DOMAIN][config_entry.entry_id]
|
||||
possible_entities: list[
|
||||
tuple[RoborockDataUpdateCoordinator, RoborockSwitchDescription]
|
||||
] = [
|
||||
(coordinator, description)
|
||||
for coordinator in coordinators.v1
|
||||
for coordinator in config_entry.runtime_data.v1
|
||||
for description in SWITCH_DESCRIPTIONS
|
||||
]
|
||||
# We need to check if this function is supported by the device.
|
||||
|
||||
@@ -13,14 +13,12 @@ from roborock.exceptions import RoborockException
|
||||
from roborock.version_1_apis.roborock_client_v1 import AttributeCache
|
||||
|
||||
from homeassistant.components.time import TimeEntity, TimeEntityDescription
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import EntityCategory
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.util import slugify
|
||||
|
||||
from . import RoborockCoordinators
|
||||
from .const import DOMAIN
|
||||
from . import RoborockConfigEntry
|
||||
from .coordinator import RoborockDataUpdateCoordinator
|
||||
from .device import RoborockEntityV1
|
||||
|
||||
@@ -115,16 +113,15 @@ TIME_DESCRIPTIONS: list[RoborockTimeDescription] = [
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
config_entry: ConfigEntry,
|
||||
config_entry: RoborockConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up Roborock time platform."""
|
||||
coordinators: RoborockCoordinators = hass.data[DOMAIN][config_entry.entry_id]
|
||||
possible_entities: list[
|
||||
tuple[RoborockDataUpdateCoordinator, RoborockTimeDescription]
|
||||
] = [
|
||||
(coordinator, description)
|
||||
for coordinator in coordinators.v1
|
||||
for coordinator in config_entry.runtime_data.v1
|
||||
for description in TIME_DESCRIPTIONS
|
||||
]
|
||||
# We need to check if this function is supported by the device.
|
||||
|
||||
@@ -17,13 +17,12 @@ from homeassistant.components.vacuum import (
|
||||
StateVacuumEntity,
|
||||
VacuumEntityFeature,
|
||||
)
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.core import HomeAssistant, ServiceResponse, SupportsResponse
|
||||
from homeassistant.helpers import entity_platform
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.util import slugify
|
||||
|
||||
from . import RoborockCoordinators
|
||||
from . import RoborockConfigEntry
|
||||
from .const import DOMAIN, GET_MAPS_SERVICE_NAME
|
||||
from .coordinator import RoborockDataUpdateCoordinator
|
||||
from .device import RoborockCoordinatedEntityV1
|
||||
@@ -57,14 +56,13 @@ STATE_CODE_TO_STATE = {
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
config_entry: ConfigEntry,
|
||||
config_entry: RoborockConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up the Roborock sensor."""
|
||||
coordinators: RoborockCoordinators = hass.data[DOMAIN][config_entry.entry_id]
|
||||
async_add_entities(
|
||||
RoborockVacuum(coordinator)
|
||||
for coordinator in coordinators.v1
|
||||
for coordinator in config_entry.runtime_data.v1
|
||||
if isinstance(coordinator, RoborockDataUpdateCoordinator)
|
||||
)
|
||||
|
||||
|
||||
@@ -83,9 +83,11 @@ REST_SENSORS_UPDATE_INTERVAL: Final = 60
|
||||
# Refresh interval for RPC polling sensors
|
||||
RPC_SENSORS_POLLING_INTERVAL: Final = 60
|
||||
|
||||
# Multiplier used to calculate the "update_interval" for sleeping devices.
|
||||
SLEEP_PERIOD_MULTIPLIER: Final = 1.2
|
||||
CONF_SLEEP_PERIOD: Final = "sleep_period"
|
||||
|
||||
# Multiplier used to calculate the "update_interval" for shelly devices.
|
||||
# Multiplier used to calculate the "update_interval" for non-sleeping devices.
|
||||
UPDATE_PERIOD_MULTIPLIER: Final = 2.2
|
||||
|
||||
# Reconnect interval for GEN2 devices
|
||||
|
||||
@@ -54,6 +54,7 @@ from .const import (
|
||||
RPC_RECONNECT_INTERVAL,
|
||||
RPC_SENSORS_POLLING_INTERVAL,
|
||||
SHBTN_MODELS,
|
||||
SLEEP_PERIOD_MULTIPLIER,
|
||||
UPDATE_PERIOD_MULTIPLIER,
|
||||
BLEScannerMode,
|
||||
)
|
||||
@@ -228,7 +229,7 @@ class ShellyBlockCoordinator(ShellyCoordinatorBase[BlockDevice]):
|
||||
"""Initialize the Shelly block device coordinator."""
|
||||
self.entry = entry
|
||||
if self.sleep_period:
|
||||
update_interval = UPDATE_PERIOD_MULTIPLIER * self.sleep_period
|
||||
update_interval = SLEEP_PERIOD_MULTIPLIER * self.sleep_period
|
||||
else:
|
||||
update_interval = (
|
||||
UPDATE_PERIOD_MULTIPLIER * device.settings["coiot"]["update_period"]
|
||||
@@ -428,7 +429,7 @@ class ShellyRestCoordinator(ShellyCoordinatorBase[BlockDevice]):
|
||||
in BATTERY_DEVICES_WITH_PERMANENT_CONNECTION
|
||||
):
|
||||
update_interval = (
|
||||
UPDATE_PERIOD_MULTIPLIER * device.settings["coiot"]["update_period"]
|
||||
SLEEP_PERIOD_MULTIPLIER * device.settings["coiot"]["update_period"]
|
||||
)
|
||||
super().__init__(hass, entry, device, update_interval)
|
||||
|
||||
@@ -458,7 +459,7 @@ class ShellyRpcCoordinator(ShellyCoordinatorBase[RpcDevice]):
|
||||
"""Initialize the Shelly RPC device coordinator."""
|
||||
self.entry = entry
|
||||
if self.sleep_period:
|
||||
update_interval = UPDATE_PERIOD_MULTIPLIER * self.sleep_period
|
||||
update_interval = SLEEP_PERIOD_MULTIPLIER * self.sleep_period
|
||||
else:
|
||||
update_interval = RPC_RECONNECT_INTERVAL
|
||||
super().__init__(hass, entry, device, update_interval)
|
||||
@@ -485,7 +486,7 @@ class ShellyRpcCoordinator(ShellyCoordinatorBase[RpcDevice]):
|
||||
data[CONF_SLEEP_PERIOD] = wakeup_period
|
||||
self.hass.config_entries.async_update_entry(self.entry, data=data)
|
||||
|
||||
update_interval = UPDATE_PERIOD_MULTIPLIER * wakeup_period
|
||||
update_interval = SLEEP_PERIOD_MULTIPLIER * wakeup_period
|
||||
self.update_interval = timedelta(seconds=update_interval)
|
||||
|
||||
return True
|
||||
|
||||
@@ -24,8 +24,6 @@ async def async_get_config_entry_diagnostics(
|
||||
device_settings: str | dict = "not initialized"
|
||||
device_status: str | dict = "not initialized"
|
||||
bluetooth: str | dict = "not initialized"
|
||||
last_error: str = "not initialized"
|
||||
|
||||
if shelly_entry_data.block:
|
||||
block_coordinator = shelly_entry_data.block
|
||||
assert block_coordinator
|
||||
@@ -57,10 +55,6 @@ async def async_get_config_entry_diagnostics(
|
||||
"uptime",
|
||||
]
|
||||
}
|
||||
|
||||
if block_coordinator.device.last_error:
|
||||
last_error = repr(block_coordinator.device.last_error)
|
||||
|
||||
else:
|
||||
rpc_coordinator = shelly_entry_data.rpc
|
||||
assert rpc_coordinator
|
||||
@@ -85,9 +79,6 @@ async def async_get_config_entry_diagnostics(
|
||||
"scanner": await scanner.async_diagnostics(),
|
||||
}
|
||||
|
||||
if rpc_coordinator.device.last_error:
|
||||
last_error = repr(rpc_coordinator.device.last_error)
|
||||
|
||||
if isinstance(device_status, dict):
|
||||
device_status = async_redact_data(device_status, ["ssid"])
|
||||
|
||||
@@ -96,6 +87,5 @@ async def async_get_config_entry_diagnostics(
|
||||
"device_info": device_info,
|
||||
"device_settings": device_settings,
|
||||
"device_status": device_status,
|
||||
"last_error": last_error,
|
||||
"bluetooth": bluetooth,
|
||||
}
|
||||
|
||||
@@ -702,7 +702,7 @@ class TelegramNotificationService:
|
||||
}
|
||||
if message_tag is not None:
|
||||
event_data[ATTR_MESSAGE_TAG] = message_tag
|
||||
if kwargs_msg.get(ATTR_MESSAGE_THREAD_ID) is not None:
|
||||
if kwargs_msg[ATTR_MESSAGE_THREAD_ID] is not None:
|
||||
event_data[ATTR_MESSAGE_THREAD_ID] = kwargs_msg[
|
||||
ATTR_MESSAGE_THREAD_ID
|
||||
]
|
||||
|
||||
@@ -23,8 +23,8 @@ if TYPE_CHECKING:
|
||||
|
||||
APPLICATION_NAME: Final = "HomeAssistant"
|
||||
MAJOR_VERSION: Final = 2024
|
||||
MINOR_VERSION: Final = 7
|
||||
PATCH_VERSION: Final = "0b2"
|
||||
MINOR_VERSION: Final = 8
|
||||
PATCH_VERSION: Final = "0.dev0"
|
||||
__short_version__: Final = f"{MAJOR_VERSION}.{MINOR_VERSION}"
|
||||
__version__: Final = f"{__short_version__}.{PATCH_VERSION}"
|
||||
REQUIRED_PYTHON_VER: Final[tuple[int, int, int]] = (3, 12, 0)
|
||||
|
||||
@@ -926,6 +926,12 @@ class DeviceRegistry(BaseRegistry[dict[str, list[dict[str, Any]]]]):
|
||||
|
||||
if add_config_entry.entry_id not in old.config_entries:
|
||||
config_entries = old.config_entries | {add_config_entry.entry_id}
|
||||
if (
|
||||
old.disabled_by
|
||||
and not add_config_entry.disabled_by
|
||||
and disabled_by is UNDEFINED
|
||||
):
|
||||
disabled_by = None
|
||||
|
||||
if (
|
||||
remove_config_entry_id is not UNDEFINED
|
||||
|
||||
@@ -32,7 +32,7 @@ habluetooth==3.1.3
|
||||
hass-nabucasa==0.81.1
|
||||
hassil==1.7.1
|
||||
home-assistant-bluetooth==1.12.2
|
||||
home-assistant-frontend==20240626.2
|
||||
home-assistant-frontend==20240626.0
|
||||
home-assistant-intents==2024.6.26
|
||||
httpx==0.27.0
|
||||
ifaddr==0.2.0
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
||||
|
||||
[project]
|
||||
name = "homeassistant"
|
||||
version = "2024.7.0b2"
|
||||
version = "2024.8.0.dev0"
|
||||
license = {text = "Apache-2.0"}
|
||||
description = "Open-source home automation platform running on Python 3."
|
||||
readme = "README.rst"
|
||||
|
||||
@@ -149,7 +149,7 @@ adb-shell[async]==0.4.4
|
||||
adext==0.4.3
|
||||
|
||||
# homeassistant.components.adguard
|
||||
adguardhome==0.7.0
|
||||
adguardhome==0.6.3
|
||||
|
||||
# homeassistant.components.advantage_air
|
||||
advantage-air==0.4.4
|
||||
@@ -1090,7 +1090,7 @@ hole==0.8.0
|
||||
holidays==0.51
|
||||
|
||||
# homeassistant.components.frontend
|
||||
home-assistant-frontend==20240626.2
|
||||
home-assistant-frontend==20240626.0
|
||||
|
||||
# homeassistant.components.conversation
|
||||
home-assistant-intents==2024.6.26
|
||||
|
||||
@@ -128,7 +128,7 @@ adb-shell[async]==0.4.4
|
||||
adext==0.4.3
|
||||
|
||||
# homeassistant.components.adguard
|
||||
adguardhome==0.7.0
|
||||
adguardhome==0.6.3
|
||||
|
||||
# homeassistant.components.advantage_air
|
||||
advantage-air==0.4.4
|
||||
@@ -895,7 +895,7 @@ hole==0.8.0
|
||||
holidays==0.51
|
||||
|
||||
# homeassistant.components.frontend
|
||||
home-assistant-frontend==20240626.2
|
||||
home-assistant-frontend==20240626.0
|
||||
|
||||
# homeassistant.components.conversation
|
||||
home-assistant-intents==2024.6.26
|
||||
|
||||
@@ -92,7 +92,7 @@ async def test_api_error(hass: HomeAssistant) -> None:
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN,
|
||||
context={"source": config_entries.SOURCE_USER},
|
||||
data=deepcopy(FIXTURE_USER_INPUT),
|
||||
data=FIXTURE_USER_INPUT,
|
||||
)
|
||||
|
||||
assert result["type"] is FlowResultType.FORM
|
||||
@@ -116,7 +116,7 @@ async def test_full_user_flow_implementation(hass: HomeAssistant) -> None:
|
||||
result2 = await hass.config_entries.flow.async_init(
|
||||
DOMAIN,
|
||||
context={"source": config_entries.SOURCE_USER},
|
||||
data=deepcopy(FIXTURE_USER_INPUT),
|
||||
data=FIXTURE_USER_INPUT,
|
||||
)
|
||||
assert result2["type"] is FlowResultType.CREATE_ENTRY
|
||||
assert result2["title"] == FIXTURE_COMPLETE_ENTRY[CONF_USERNAME]
|
||||
@@ -137,8 +137,7 @@ async def test_options_flow_implementation(hass: HomeAssistant) -> None:
|
||||
return_value=True,
|
||||
) as mock_setup_entry,
|
||||
):
|
||||
config_entry_args = deepcopy(FIXTURE_CONFIG_ENTRY)
|
||||
config_entry = MockConfigEntry(**config_entry_args)
|
||||
config_entry = MockConfigEntry(**FIXTURE_CONFIG_ENTRY)
|
||||
config_entry.add_to_hass(hass)
|
||||
|
||||
await hass.config_entries.async_setup(config_entry.entry_id)
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
"""Test Axis component setup process."""
|
||||
|
||||
from copy import deepcopy
|
||||
from unittest.mock import patch
|
||||
|
||||
import pytest
|
||||
@@ -38,7 +37,7 @@ async def test_migrate_options(
|
||||
) -> None:
|
||||
"""Test successful migration of options."""
|
||||
|
||||
config_entry = deepcopy(FIXTURE_CONFIG_ENTRY)
|
||||
config_entry = FIXTURE_CONFIG_ENTRY.copy()
|
||||
config_entry["options"] = options
|
||||
|
||||
mock_config_entry = MockConfigEntry(**config_entry)
|
||||
@@ -56,7 +55,7 @@ async def test_migrate_options(
|
||||
async def test_migrate_options_from_data(hass: HomeAssistant) -> None:
|
||||
"""Test successful migration of options."""
|
||||
|
||||
config_entry = deepcopy(FIXTURE_CONFIG_ENTRY)
|
||||
config_entry = FIXTURE_CONFIG_ENTRY.copy()
|
||||
config_entry["options"] = {}
|
||||
config_entry["data"].update({CONF_READ_ONLY: False})
|
||||
|
||||
@@ -108,8 +107,7 @@ async def test_migrate_unique_ids(
|
||||
entity_registry: er.EntityRegistry,
|
||||
) -> None:
|
||||
"""Test successful migration of entity unique_ids."""
|
||||
confg_entry = deepcopy(FIXTURE_CONFIG_ENTRY)
|
||||
mock_config_entry = MockConfigEntry(**confg_entry)
|
||||
mock_config_entry = MockConfigEntry(**FIXTURE_CONFIG_ENTRY)
|
||||
mock_config_entry.add_to_hass(hass)
|
||||
|
||||
entity: er.RegistryEntry = entity_registry.async_get_or_create(
|
||||
@@ -155,8 +153,7 @@ async def test_dont_migrate_unique_ids(
|
||||
entity_registry: er.EntityRegistry,
|
||||
) -> None:
|
||||
"""Test successful migration of entity unique_ids."""
|
||||
confg_entry = deepcopy(FIXTURE_CONFIG_ENTRY)
|
||||
mock_config_entry = MockConfigEntry(**confg_entry)
|
||||
mock_config_entry = MockConfigEntry(**FIXTURE_CONFIG_ENTRY)
|
||||
mock_config_entry.add_to_hass(hass)
|
||||
|
||||
# create existing entry with new_unique_id
|
||||
@@ -199,8 +196,7 @@ async def test_remove_stale_devices(
|
||||
device_registry: dr.DeviceRegistry,
|
||||
) -> None:
|
||||
"""Test remove stale device registry entries."""
|
||||
config_entry = deepcopy(FIXTURE_CONFIG_ENTRY)
|
||||
mock_config_entry = MockConfigEntry(**config_entry)
|
||||
mock_config_entry = MockConfigEntry(**FIXTURE_CONFIG_ENTRY)
|
||||
mock_config_entry.add_to_hass(hass)
|
||||
|
||||
device_registry.async_get_or_create(
|
||||
|
||||
@@ -151,7 +151,7 @@ class FritzDeviceSwitchMock(FritzEntityBaseMock):
|
||||
has_thermostat = False
|
||||
has_blind = False
|
||||
switch_state = "fake_state"
|
||||
lock = False
|
||||
lock = "fake_locked"
|
||||
power = 5678
|
||||
present = True
|
||||
temperature = 1.23
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
from datetime import timedelta
|
||||
from unittest.mock import Mock
|
||||
|
||||
import pytest
|
||||
from requests.exceptions import HTTPError
|
||||
|
||||
from homeassistant.components.fritzbox.const import DOMAIN as FB_DOMAIN
|
||||
@@ -30,7 +29,6 @@ from homeassistant.const import (
|
||||
UnitOfTemperature,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
from homeassistant.helpers import entity_registry as er
|
||||
import homeassistant.util.dt as dt_util
|
||||
|
||||
@@ -132,7 +130,6 @@ async def test_turn_on(hass: HomeAssistant, fritz: Mock) -> None:
|
||||
async def test_turn_off(hass: HomeAssistant, fritz: Mock) -> None:
|
||||
"""Test turn device off."""
|
||||
device = FritzDeviceSwitchMock()
|
||||
|
||||
assert await setup_config_entry(
|
||||
hass, MOCK_CONFIG[FB_DOMAIN][CONF_DEVICES][0], ENTITY_ID, device, fritz
|
||||
)
|
||||
@@ -140,36 +137,9 @@ async def test_turn_off(hass: HomeAssistant, fritz: Mock) -> None:
|
||||
await hass.services.async_call(
|
||||
DOMAIN, SERVICE_TURN_OFF, {ATTR_ENTITY_ID: ENTITY_ID}, True
|
||||
)
|
||||
|
||||
assert device.set_switch_state_off.call_count == 1
|
||||
|
||||
|
||||
async def test_toggle_while_locked(hass: HomeAssistant, fritz: Mock) -> None:
|
||||
"""Test toggling while device is locked."""
|
||||
device = FritzDeviceSwitchMock()
|
||||
device.lock = True
|
||||
|
||||
assert await setup_config_entry(
|
||||
hass, MOCK_CONFIG[FB_DOMAIN][CONF_DEVICES][0], ENTITY_ID, device, fritz
|
||||
)
|
||||
|
||||
with pytest.raises(
|
||||
HomeAssistantError,
|
||||
match="Can't toggle switch while manual switching is disabled for the device",
|
||||
):
|
||||
await hass.services.async_call(
|
||||
DOMAIN, SERVICE_TURN_OFF, {ATTR_ENTITY_ID: ENTITY_ID}, True
|
||||
)
|
||||
|
||||
with pytest.raises(
|
||||
HomeAssistantError,
|
||||
match="Can't toggle switch while manual switching is disabled for the device",
|
||||
):
|
||||
await hass.services.async_call(
|
||||
DOMAIN, SERVICE_TURN_ON, {ATTR_ENTITY_ID: ENTITY_ID}, True
|
||||
)
|
||||
|
||||
|
||||
async def test_update(hass: HomeAssistant, fritz: Mock) -> None:
|
||||
"""Test update without error."""
|
||||
device = FritzDeviceSwitchMock()
|
||||
|
||||
@@ -543,5 +543,5 @@ async def test_register_static_paths(
|
||||
"Detected code that calls hass.http.register_static_path "
|
||||
"which is deprecated because it does blocking I/O in the "
|
||||
"event loop, instead call "
|
||||
"`await hass.http.async_register_static_paths"
|
||||
"`await hass.http.async_register_static_path"
|
||||
) in caplog.text
|
||||
|
||||
@@ -1561,7 +1561,7 @@ async def test_setup_with_advanced_settings(
|
||||
}
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("mock_ssl_context", "mock_process_uploaded_file")
|
||||
@pytest.mark.usesfixtures("mock_ssl_context", "mock_process_uploaded_file")
|
||||
async def test_change_websockets_transport_to_tcp(
|
||||
hass: HomeAssistant, mock_try_connection: MagicMock
|
||||
) -> None:
|
||||
|
||||
@@ -499,7 +499,7 @@ async def test_image_from_url_fails(
|
||||
),
|
||||
],
|
||||
)
|
||||
@pytest.mark.usefixtures("hass", "hass_client_no_auth")
|
||||
@pytest.mark.usesfixtures("hass", "hass_client_no_auth")
|
||||
async def test_image_config_fails(
|
||||
mqtt_mock_entry: MqttMockHAClientGenerator,
|
||||
caplog: pytest.LogCaptureFixture,
|
||||
|
||||
@@ -29,7 +29,6 @@ async def test_unload_entry(
|
||||
await hass.async_block_till_done()
|
||||
assert mock_disconnect.call_count == 2
|
||||
assert setup_entry.state is ConfigEntryState.NOT_LOADED
|
||||
assert not hass.data.get(DOMAIN)
|
||||
|
||||
|
||||
async def test_config_entry_not_ready(
|
||||
|
||||
@@ -7,7 +7,7 @@ from freezegun.api import FrozenDateTimeFactory
|
||||
import pytest
|
||||
|
||||
from homeassistant.components.binary_sensor import DOMAIN as BINARY_SENSOR_DOMAIN
|
||||
from homeassistant.components.shelly.const import UPDATE_PERIOD_MULTIPLIER
|
||||
from homeassistant.components.shelly.const import SLEEP_PERIOD_MULTIPLIER
|
||||
from homeassistant.const import STATE_OFF, STATE_ON, STATE_UNKNOWN
|
||||
from homeassistant.core import HomeAssistant, State
|
||||
from homeassistant.helpers.device_registry import DeviceRegistry
|
||||
@@ -122,7 +122,7 @@ async def test_block_rest_binary_sensor_connected_battery_devices(
|
||||
assert hass.states.get(entity_id).state == STATE_OFF
|
||||
|
||||
# Verify update on slow intervals
|
||||
await mock_rest_update(hass, freezer, seconds=UPDATE_PERIOD_MULTIPLIER * 3600)
|
||||
await mock_rest_update(hass, freezer, seconds=SLEEP_PERIOD_MULTIPLIER * 3600)
|
||||
assert hass.states.get(entity_id).state == STATE_ON
|
||||
|
||||
entry = entity_registry.async_get(entity_id)
|
||||
|
||||
@@ -20,6 +20,7 @@ from homeassistant.components.shelly.const import (
|
||||
ENTRY_RELOAD_COOLDOWN,
|
||||
MAX_PUSH_UPDATE_FAILURES,
|
||||
RPC_RECONNECT_INTERVAL,
|
||||
SLEEP_PERIOD_MULTIPLIER,
|
||||
UPDATE_PERIOD_MULTIPLIER,
|
||||
BLEScannerMode,
|
||||
)
|
||||
@@ -563,7 +564,7 @@ async def test_rpc_update_entry_sleep_period(
|
||||
|
||||
# Move time to generate sleep period update
|
||||
monkeypatch.setitem(mock_rpc_device.status["sys"], "wakeup_period", 3600)
|
||||
freezer.tick(timedelta(seconds=600 * UPDATE_PERIOD_MULTIPLIER))
|
||||
freezer.tick(timedelta(seconds=600 * SLEEP_PERIOD_MULTIPLIER))
|
||||
async_fire_time_changed(hass)
|
||||
await hass.async_block_till_done(wait_background_tasks=True)
|
||||
|
||||
@@ -595,7 +596,7 @@ async def test_rpc_sleeping_device_no_periodic_updates(
|
||||
assert get_entity_state(hass, entity_id) == "22.9"
|
||||
|
||||
# Move time to generate polling
|
||||
freezer.tick(timedelta(seconds=UPDATE_PERIOD_MULTIPLIER * 1000))
|
||||
freezer.tick(timedelta(seconds=SLEEP_PERIOD_MULTIPLIER * 1000))
|
||||
async_fire_time_changed(hass)
|
||||
await hass.async_block_till_done(wait_background_tasks=True)
|
||||
|
||||
@@ -888,7 +889,7 @@ async def test_block_sleeping_device_connection_error(
|
||||
assert get_entity_state(hass, entity_id) == STATE_ON
|
||||
|
||||
# Move time to generate sleep period update
|
||||
freezer.tick(timedelta(seconds=sleep_period * UPDATE_PERIOD_MULTIPLIER))
|
||||
freezer.tick(timedelta(seconds=sleep_period * SLEEP_PERIOD_MULTIPLIER))
|
||||
async_fire_time_changed(hass)
|
||||
await hass.async_block_till_done(wait_background_tasks=True)
|
||||
|
||||
@@ -933,7 +934,7 @@ async def test_rpc_sleeping_device_connection_error(
|
||||
assert get_entity_state(hass, entity_id) == STATE_ON
|
||||
|
||||
# Move time to generate sleep period update
|
||||
freezer.tick(timedelta(seconds=sleep_period * UPDATE_PERIOD_MULTIPLIER))
|
||||
freezer.tick(timedelta(seconds=sleep_period * SLEEP_PERIOD_MULTIPLIER))
|
||||
async_fire_time_changed(hass)
|
||||
await hass.async_block_till_done(wait_background_tasks=True)
|
||||
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
"""Tests for Shelly diagnostics platform."""
|
||||
|
||||
from unittest.mock import ANY, Mock, PropertyMock
|
||||
from unittest.mock import ANY, Mock
|
||||
|
||||
from aioshelly.ble.const import BLE_SCAN_RESULT_EVENT
|
||||
from aioshelly.const import MODEL_25
|
||||
from aioshelly.exceptions import DeviceConnectionError
|
||||
import pytest
|
||||
|
||||
from homeassistant.components.diagnostics import REDACTED
|
||||
@@ -37,10 +36,6 @@ async def test_block_config_entry_diagnostics(
|
||||
{key: REDACTED for key in TO_REDACT if key in entry_dict["data"]}
|
||||
)
|
||||
|
||||
type(mock_block_device).last_error = PropertyMock(
|
||||
return_value=DeviceConnectionError()
|
||||
)
|
||||
|
||||
result = await get_diagnostics_for_config_entry(hass, hass_client, entry)
|
||||
|
||||
assert result == {
|
||||
@@ -53,7 +48,6 @@ async def test_block_config_entry_diagnostics(
|
||||
},
|
||||
"device_settings": {"coiot": {"update_period": 15}},
|
||||
"device_status": MOCK_STATUS_COAP,
|
||||
"last_error": "DeviceConnectionError()",
|
||||
}
|
||||
|
||||
|
||||
@@ -97,10 +91,6 @@ async def test_rpc_config_entry_diagnostics(
|
||||
{key: REDACTED for key in TO_REDACT if key in entry_dict["data"]}
|
||||
)
|
||||
|
||||
type(mock_rpc_device).last_error = PropertyMock(
|
||||
return_value=DeviceConnectionError()
|
||||
)
|
||||
|
||||
result = await get_diagnostics_for_config_entry(hass, hass_client, entry)
|
||||
|
||||
assert result == {
|
||||
@@ -162,5 +152,4 @@ async def test_rpc_config_entry_diagnostics(
|
||||
},
|
||||
"wifi": {"rssi": -63},
|
||||
},
|
||||
"last_error": "DeviceConnectionError()",
|
||||
}
|
||||
|
||||
@@ -3052,3 +3052,39 @@ async def test_primary_config_entry(
|
||||
model="model",
|
||||
)
|
||||
assert device.primary_config_entry == mock_config_entry_1.entry_id
|
||||
|
||||
|
||||
@pytest.mark.parametrize("disabled_by", list(dr.DeviceEntryDisabler))
|
||||
async def test_add_config_entry_to_disabled_device(
|
||||
hass: HomeAssistant,
|
||||
device_registry: dr.DeviceRegistry,
|
||||
disabled_by: dr.DeviceEntryDisabler,
|
||||
) -> None:
|
||||
"""Test adding config entry to a disabled device."""
|
||||
mock_config_entry_1 = MockConfigEntry(title=None)
|
||||
mock_config_entry_1.add_to_hass(hass)
|
||||
mock_config_entry_2 = MockConfigEntry(
|
||||
disabled_by=config_entries.ConfigEntryDisabler.USER, title=None
|
||||
)
|
||||
mock_config_entry_2.add_to_hass(hass)
|
||||
mock_config_entry_3 = MockConfigEntry(title=None)
|
||||
mock_config_entry_3.add_to_hass(hass)
|
||||
|
||||
device = device_registry.async_get_or_create(
|
||||
config_entry_id=mock_config_entry_1.entry_id,
|
||||
connections={(dr.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:EF")},
|
||||
disabled_by=disabled_by,
|
||||
)
|
||||
assert device.disabled_by == disabled_by
|
||||
|
||||
device = device_registry.async_update_device(
|
||||
device.id, add_config_entry_id=mock_config_entry_2.entry_id
|
||||
)
|
||||
assert device
|
||||
assert device.disabled_by == disabled_by
|
||||
|
||||
device = device_registry.async_update_device(
|
||||
device.id, add_config_entry_id=mock_config_entry_3.entry_id
|
||||
)
|
||||
assert device
|
||||
assert device.disabled_by is None
|
||||
|
||||
Reference in New Issue
Block a user