mirror of
https://github.com/home-assistant/core.git
synced 2025-07-08 05:47:10 +00:00
2023.2.5 (#88190)
This commit is contained in:
commit
a7e42798da
@ -2,7 +2,7 @@
|
|||||||
"domain": "aladdin_connect",
|
"domain": "aladdin_connect",
|
||||||
"name": "Aladdin Connect",
|
"name": "Aladdin Connect",
|
||||||
"documentation": "https://www.home-assistant.io/integrations/aladdin_connect",
|
"documentation": "https://www.home-assistant.io/integrations/aladdin_connect",
|
||||||
"requirements": ["AIOAladdinConnect==0.1.55"],
|
"requirements": ["AIOAladdinConnect==0.1.56"],
|
||||||
"codeowners": ["@mkmer"],
|
"codeowners": ["@mkmer"],
|
||||||
"iot_class": "cloud_polling",
|
"iot_class": "cloud_polling",
|
||||||
"loggers": ["aladdin_connect"],
|
"loggers": ["aladdin_connect"],
|
||||||
|
@ -22,6 +22,7 @@ from .const import DOMAIN, PRODUCT
|
|||||||
SCAN_INTERVAL = timedelta(seconds=5)
|
SCAN_INTERVAL = timedelta(seconds=5)
|
||||||
|
|
||||||
BLEBOX_TO_HVACMODE = {
|
BLEBOX_TO_HVACMODE = {
|
||||||
|
None: None,
|
||||||
0: HVACMode.OFF,
|
0: HVACMode.OFF,
|
||||||
1: HVACMode.HEAT,
|
1: HVACMode.HEAT,
|
||||||
2: HVACMode.COOL,
|
2: HVACMode.COOL,
|
||||||
@ -58,13 +59,15 @@ class BleBoxClimateEntity(BleBoxEntity[blebox_uniapi.climate.Climate], ClimateEn
|
|||||||
@property
|
@property
|
||||||
def hvac_modes(self):
|
def hvac_modes(self):
|
||||||
"""Return list of supported HVAC modes."""
|
"""Return list of supported HVAC modes."""
|
||||||
return [HVACMode.OFF, self.hvac_mode]
|
return [HVACMode.OFF, BLEBOX_TO_HVACMODE[self._feature.mode]]
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def hvac_mode(self):
|
def hvac_mode(self):
|
||||||
"""Return the desired HVAC mode."""
|
"""Return the desired HVAC mode."""
|
||||||
if self._feature.is_on is None:
|
if self._feature.is_on is None:
|
||||||
return None
|
return None
|
||||||
|
if not self._feature.is_on:
|
||||||
|
return HVACMode.OFF
|
||||||
if self._feature.mode is not None:
|
if self._feature.mode is not None:
|
||||||
return BLEBOX_TO_HVACMODE[self._feature.mode]
|
return BLEBOX_TO_HVACMODE[self._feature.mode]
|
||||||
return HVACMode.HEAT if self._feature.is_on else HVACMode.OFF
|
return HVACMode.HEAT if self._feature.is_on else HVACMode.OFF
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
"name": "Matter (BETA)",
|
"name": "Matter (BETA)",
|
||||||
"config_flow": true,
|
"config_flow": true,
|
||||||
"documentation": "https://www.home-assistant.io/integrations/matter",
|
"documentation": "https://www.home-assistant.io/integrations/matter",
|
||||||
"requirements": ["python-matter-server==2.0.2"],
|
"requirements": ["python-matter-server==2.1.0"],
|
||||||
"dependencies": ["websocket_api"],
|
"dependencies": ["websocket_api"],
|
||||||
"codeowners": ["@home-assistant/matter"],
|
"codeowners": ["@home-assistant/matter"],
|
||||||
"iot_class": "local_push"
|
"iot_class": "local_push"
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
"name": "OctoPrint",
|
"name": "OctoPrint",
|
||||||
"config_flow": true,
|
"config_flow": true,
|
||||||
"documentation": "https://www.home-assistant.io/integrations/octoprint",
|
"documentation": "https://www.home-assistant.io/integrations/octoprint",
|
||||||
"requirements": ["pyoctoprintapi==0.1.9"],
|
"requirements": ["pyoctoprintapi==0.1.11"],
|
||||||
"codeowners": ["@rfleming71"],
|
"codeowners": ["@rfleming71"],
|
||||||
"zeroconf": ["_octoprint._tcp.local."],
|
"zeroconf": ["_octoprint._tcp.local."],
|
||||||
"ssdp": [
|
"ssdp": [
|
||||||
|
@ -15,7 +15,7 @@ An overview of the areas and the devices in this smart home:
|
|||||||
{{ area.name }}:
|
{{ area.name }}:
|
||||||
{%- set area_info.printed = true %}
|
{%- set area_info.printed = true %}
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
- {{ device_attr(device, "name") }}{% if device_attr(device, "model") and device_attr(device, "model") not in device_attr(device, "name") %} ({{ device_attr(device, "model") }}){% endif %}
|
- {{ device_attr(device, "name") }}{% if device_attr(device, "model") and (device_attr(device, "model") | string) not in (device_attr(device, "name") | string) %} ({{ device_attr(device, "model") }}){% endif %}
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
{%- endfor %}
|
{%- endfor %}
|
||||||
{%- endfor %}
|
{%- endfor %}
|
||||||
|
@ -6,7 +6,7 @@ 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 ConfigEntry
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.exceptions import ConfigEntryAuthFailed
|
from homeassistant.exceptions import ConfigEntryAuthFailed
|
||||||
from homeassistant.helpers.debounce import Debouncer
|
from homeassistant.helpers.debounce import Debouncer
|
||||||
@ -60,14 +60,4 @@ class OpenUvCoordinator(DataUpdateCoordinator):
|
|||||||
except OpenUvError as err:
|
except OpenUvError as err:
|
||||||
raise UpdateFailed(str(err)) from err
|
raise UpdateFailed(str(err)) from err
|
||||||
|
|
||||||
# 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"])
|
||||||
|
@ -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==2023.01.0"],
|
"requirements": ["pyopenuv==2023.02.0"],
|
||||||
"codeowners": ["@bachya"],
|
"codeowners": ["@bachya"],
|
||||||
"iot_class": "cloud_polling",
|
"iot_class": "cloud_polling",
|
||||||
"loggers": ["pyopenuv"],
|
"loggers": ["pyopenuv"],
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
"name": "Reolink IP NVR/camera",
|
"name": "Reolink IP NVR/camera",
|
||||||
"config_flow": true,
|
"config_flow": true,
|
||||||
"documentation": "https://www.home-assistant.io/integrations/reolink",
|
"documentation": "https://www.home-assistant.io/integrations/reolink",
|
||||||
"requirements": ["reolink-aio==0.4.0"],
|
"requirements": ["reolink-aio==0.4.2"],
|
||||||
"dependencies": ["webhook"],
|
"dependencies": ["webhook"],
|
||||||
"codeowners": ["@starkillerOG"],
|
"codeowners": ["@starkillerOG"],
|
||||||
"iot_class": "local_polling",
|
"iot_class": "local_polling",
|
||||||
|
@ -587,7 +587,7 @@ class SensorEntity(Entity):
|
|||||||
numerical_value: int | float | Decimal
|
numerical_value: int | float | Decimal
|
||||||
if not isinstance(value, (int, float, Decimal)):
|
if not isinstance(value, (int, float, Decimal)):
|
||||||
try:
|
try:
|
||||||
if isinstance(value, str) and "." not in value:
|
if isinstance(value, str) and "." not in value and "e" not in value:
|
||||||
numerical_value = int(value)
|
numerical_value = int(value)
|
||||||
else:
|
else:
|
||||||
numerical_value = float(value) # type:ignore[arg-type]
|
numerical_value = float(value) # type:ignore[arg-type]
|
||||||
|
@ -5,15 +5,17 @@ from collections import deque
|
|||||||
from collections.abc import Callable
|
from collections.abc import Callable
|
||||||
import contextlib
|
import contextlib
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
|
from enum import Enum
|
||||||
import logging
|
import logging
|
||||||
import statistics
|
import statistics
|
||||||
from typing import Any, Literal, cast
|
from typing import Any, Literal, TypeVar, cast
|
||||||
|
|
||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
|
|
||||||
from homeassistant.components.binary_sensor import DOMAIN as BINARY_SENSOR_DOMAIN
|
from homeassistant.components.binary_sensor import DOMAIN as BINARY_SENSOR_DOMAIN
|
||||||
from homeassistant.components.recorder import get_instance, history
|
from homeassistant.components.recorder import get_instance, history
|
||||||
from homeassistant.components.sensor import (
|
from homeassistant.components.sensor import ( # pylint: disable=hass-deprecated-import
|
||||||
|
DEVICE_CLASS_STATE_CLASSES,
|
||||||
PLATFORM_SCHEMA,
|
PLATFORM_SCHEMA,
|
||||||
SensorDeviceClass,
|
SensorDeviceClass,
|
||||||
SensorEntity,
|
SensorEntity,
|
||||||
@ -144,7 +146,7 @@ STATS_DATETIME = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
# Statistics which retain the unit of the source entity
|
# Statistics which retain the unit of the source entity
|
||||||
STAT_NUMERIC_RETAIN_UNIT = {
|
STATS_NUMERIC_RETAIN_UNIT = {
|
||||||
STAT_AVERAGE_LINEAR,
|
STAT_AVERAGE_LINEAR,
|
||||||
STAT_AVERAGE_STEP,
|
STAT_AVERAGE_STEP,
|
||||||
STAT_AVERAGE_TIMELESS,
|
STAT_AVERAGE_TIMELESS,
|
||||||
@ -166,7 +168,7 @@ STAT_NUMERIC_RETAIN_UNIT = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
# Statistics which produce percentage ratio from binary_sensor source entity
|
# Statistics which produce percentage ratio from binary_sensor source entity
|
||||||
STAT_BINARY_PERCENTAGE = {
|
STATS_BINARY_PERCENTAGE = {
|
||||||
STAT_AVERAGE_STEP,
|
STAT_AVERAGE_STEP,
|
||||||
STAT_AVERAGE_TIMELESS,
|
STAT_AVERAGE_TIMELESS,
|
||||||
STAT_MEAN,
|
STAT_MEAN,
|
||||||
@ -296,15 +298,9 @@ class StatisticsSensor(SensorEntity):
|
|||||||
self.ages: deque[datetime] = deque(maxlen=self._samples_max_buffer_size)
|
self.ages: deque[datetime] = deque(maxlen=self._samples_max_buffer_size)
|
||||||
self.attributes: dict[str, StateType] = {}
|
self.attributes: dict[str, StateType] = {}
|
||||||
|
|
||||||
self._state_characteristic_fn: Callable[[], StateType | datetime]
|
self._state_characteristic_fn: Callable[
|
||||||
if self.is_binary:
|
[], StateType | datetime
|
||||||
self._state_characteristic_fn = getattr(
|
] = self._callable_characteristic_fn(self._state_characteristic)
|
||||||
self, f"_stat_binary_{self._state_characteristic}"
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
self._state_characteristic_fn = getattr(
|
|
||||||
self, f"_stat_{self._state_characteristic}"
|
|
||||||
)
|
|
||||||
|
|
||||||
self._update_listener: CALLBACK_TYPE | None = None
|
self._update_listener: CALLBACK_TYPE | None = None
|
||||||
|
|
||||||
@ -368,11 +364,11 @@ class StatisticsSensor(SensorEntity):
|
|||||||
def _derive_unit_of_measurement(self, new_state: State) -> str | None:
|
def _derive_unit_of_measurement(self, new_state: State) -> str | None:
|
||||||
base_unit: str | None = new_state.attributes.get(ATTR_UNIT_OF_MEASUREMENT)
|
base_unit: str | None = new_state.attributes.get(ATTR_UNIT_OF_MEASUREMENT)
|
||||||
unit: str | None
|
unit: str | None
|
||||||
if self.is_binary and self._state_characteristic in STAT_BINARY_PERCENTAGE:
|
if self.is_binary and self._state_characteristic in STATS_BINARY_PERCENTAGE:
|
||||||
unit = PERCENTAGE
|
unit = PERCENTAGE
|
||||||
elif not base_unit:
|
elif not base_unit:
|
||||||
unit = None
|
unit = None
|
||||||
elif self._state_characteristic in STAT_NUMERIC_RETAIN_UNIT:
|
elif self._state_characteristic in STATS_NUMERIC_RETAIN_UNIT:
|
||||||
unit = base_unit
|
unit = base_unit
|
||||||
elif self._state_characteristic in STATS_NOT_A_NUMBER:
|
elif self._state_characteristic in STATS_NOT_A_NUMBER:
|
||||||
unit = None
|
unit = None
|
||||||
@ -393,11 +389,24 @@ class StatisticsSensor(SensorEntity):
|
|||||||
@property
|
@property
|
||||||
def device_class(self) -> SensorDeviceClass | None:
|
def device_class(self) -> SensorDeviceClass | None:
|
||||||
"""Return the class of this device."""
|
"""Return the class of this device."""
|
||||||
if self._state_characteristic in STAT_NUMERIC_RETAIN_UNIT:
|
|
||||||
_state = self.hass.states.get(self._source_entity_id)
|
|
||||||
return None if _state is None else _state.attributes.get(ATTR_DEVICE_CLASS)
|
|
||||||
if self._state_characteristic in STATS_DATETIME:
|
if self._state_characteristic in STATS_DATETIME:
|
||||||
return SensorDeviceClass.TIMESTAMP
|
return SensorDeviceClass.TIMESTAMP
|
||||||
|
if self._state_characteristic in STATS_NUMERIC_RETAIN_UNIT:
|
||||||
|
source_state = self.hass.states.get(self._source_entity_id)
|
||||||
|
if source_state is None:
|
||||||
|
return None
|
||||||
|
source_device_class = source_state.attributes.get(ATTR_DEVICE_CLASS)
|
||||||
|
if source_device_class is None:
|
||||||
|
return None
|
||||||
|
sensor_device_class = try_parse_enum(SensorDeviceClass, source_device_class)
|
||||||
|
if sensor_device_class is None:
|
||||||
|
return None
|
||||||
|
sensor_state_classes = DEVICE_CLASS_STATE_CLASSES.get(
|
||||||
|
sensor_device_class, set()
|
||||||
|
)
|
||||||
|
if SensorStateClass.MEASUREMENT not in sensor_state_classes:
|
||||||
|
return None
|
||||||
|
return sensor_device_class
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@ -472,8 +481,8 @@ class StatisticsSensor(SensorEntity):
|
|||||||
if timestamp := self._next_to_purge_timestamp():
|
if timestamp := self._next_to_purge_timestamp():
|
||||||
_LOGGER.debug("%s: scheduling update at %s", self.entity_id, timestamp)
|
_LOGGER.debug("%s: scheduling update at %s", self.entity_id, timestamp)
|
||||||
if self._update_listener:
|
if self._update_listener:
|
||||||
self._update_listener()
|
self._update_listener() # pragma: no cover
|
||||||
self._update_listener = None
|
self._update_listener = None # pragma: no cover
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
def _scheduled_update(now: datetime) -> None:
|
def _scheduled_update(now: datetime) -> None:
|
||||||
@ -563,6 +572,18 @@ class StatisticsSensor(SensorEntity):
|
|||||||
value = int(value)
|
value = int(value)
|
||||||
self._value = value
|
self._value = value
|
||||||
|
|
||||||
|
def _callable_characteristic_fn(
|
||||||
|
self, characteristic: str
|
||||||
|
) -> Callable[[], StateType | datetime]:
|
||||||
|
"""Return the function callable of one characteristic function."""
|
||||||
|
function: Callable[[], StateType | datetime] = getattr(
|
||||||
|
self,
|
||||||
|
f"_stat_binary_{characteristic}"
|
||||||
|
if self.is_binary
|
||||||
|
else f"_stat_{characteristic}",
|
||||||
|
)
|
||||||
|
return function
|
||||||
|
|
||||||
# Statistics for numeric sensor
|
# Statistics for numeric sensor
|
||||||
|
|
||||||
def _stat_average_linear(self) -> StateType:
|
def _stat_average_linear(self) -> StateType:
|
||||||
@ -748,3 +769,16 @@ class StatisticsSensor(SensorEntity):
|
|||||||
if len(self.states) > 0:
|
if len(self.states) > 0:
|
||||||
return 100.0 / len(self.states) * self.states.count(True)
|
return 100.0 / len(self.states) * self.states.count(True)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
_EnumT = TypeVar("_EnumT", bound=Enum)
|
||||||
|
|
||||||
|
|
||||||
|
def try_parse_enum(cls: type[_EnumT], value: Any) -> _EnumT | None:
|
||||||
|
"""Try to parse the value into an Enum.
|
||||||
|
|
||||||
|
Return None if parsing fails.
|
||||||
|
"""
|
||||||
|
with contextlib.suppress(ValueError):
|
||||||
|
return cls(value)
|
||||||
|
return None
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
"domain": "tibber",
|
"domain": "tibber",
|
||||||
"name": "Tibber",
|
"name": "Tibber",
|
||||||
"documentation": "https://www.home-assistant.io/integrations/tibber",
|
"documentation": "https://www.home-assistant.io/integrations/tibber",
|
||||||
"requirements": ["pyTibber==0.26.12"],
|
"requirements": ["pyTibber==0.26.13"],
|
||||||
"codeowners": ["@danielhiversen"],
|
"codeowners": ["@danielhiversen"],
|
||||||
"quality_scale": "silver",
|
"quality_scale": "silver",
|
||||||
"config_flow": true,
|
"config_flow": true,
|
||||||
|
@ -119,11 +119,12 @@ SENSORS: tuple[WhirlpoolSensorEntityDescription, ...] = (
|
|||||||
key="DispenseLevel",
|
key="DispenseLevel",
|
||||||
name="Detergent Level",
|
name="Detergent Level",
|
||||||
translation_key="whirlpool_tank",
|
translation_key="whirlpool_tank",
|
||||||
|
entity_registry_enabled_default=False,
|
||||||
device_class=SensorDeviceClass.ENUM,
|
device_class=SensorDeviceClass.ENUM,
|
||||||
options=list(TANK_FILL.values()),
|
options=list(TANK_FILL.values()),
|
||||||
value_fn=lambda WasherDryer: TANK_FILL[
|
value_fn=lambda WasherDryer: TANK_FILL.get(
|
||||||
WasherDryer.get_attribute("WashCavity_OpStatusBulkDispense1Level")
|
WasherDryer.get_attribute("WashCavity_OpStatusBulkDispense1Level")
|
||||||
],
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -265,6 +266,7 @@ class WasherDryerTimeClass(RestoreSensor):
|
|||||||
|
|
||||||
async def async_will_remove_from_hass(self) -> None:
|
async def async_will_remove_from_hass(self) -> None:
|
||||||
"""Close Whrilpool Appliance sockets before removing."""
|
"""Close Whrilpool Appliance sockets before removing."""
|
||||||
|
self._wd.unregister_attr_callback(self.update_from_latest_data)
|
||||||
await self._wd.disconnect()
|
await self._wd.disconnect()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
@ -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 = 2
|
MINOR_VERSION: Final = 2
|
||||||
PATCH_VERSION: Final = "4"
|
PATCH_VERSION: Final = "5"
|
||||||
__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, 10, 0)
|
REQUIRED_PYTHON_VER: Final[tuple[int, int, int]] = (3, 10, 0)
|
||||||
|
@ -30,7 +30,7 @@ ifaddr==0.1.7
|
|||||||
janus==1.0.0
|
janus==1.0.0
|
||||||
jinja2==3.1.2
|
jinja2==3.1.2
|
||||||
lru-dict==1.1.8
|
lru-dict==1.1.8
|
||||||
orjson==3.8.5
|
orjson==3.8.6
|
||||||
paho-mqtt==1.6.1
|
paho-mqtt==1.6.1
|
||||||
pillow==9.4.0
|
pillow==9.4.0
|
||||||
pip>=21.0,<22.4
|
pip>=21.0,<22.4
|
||||||
|
@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|||||||
|
|
||||||
[project]
|
[project]
|
||||||
name = "homeassistant"
|
name = "homeassistant"
|
||||||
version = "2023.2.4"
|
version = "2023.2.5"
|
||||||
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"
|
||||||
@ -44,7 +44,7 @@ dependencies = [
|
|||||||
"cryptography==39.0.1",
|
"cryptography==39.0.1",
|
||||||
# pyOpenSSL 23.0.0 is required to work with cryptography 39+
|
# pyOpenSSL 23.0.0 is required to work with cryptography 39+
|
||||||
"pyOpenSSL==23.0.0",
|
"pyOpenSSL==23.0.0",
|
||||||
"orjson==3.8.5",
|
"orjson==3.8.6",
|
||||||
"pip>=21.0,<22.4",
|
"pip>=21.0,<22.4",
|
||||||
"python-slugify==4.0.1",
|
"python-slugify==4.0.1",
|
||||||
"pyyaml==6.0",
|
"pyyaml==6.0",
|
||||||
|
@ -18,7 +18,7 @@ lru-dict==1.1.8
|
|||||||
PyJWT==2.5.0
|
PyJWT==2.5.0
|
||||||
cryptography==39.0.1
|
cryptography==39.0.1
|
||||||
pyOpenSSL==23.0.0
|
pyOpenSSL==23.0.0
|
||||||
orjson==3.8.5
|
orjson==3.8.6
|
||||||
pip>=21.0,<22.4
|
pip>=21.0,<22.4
|
||||||
python-slugify==4.0.1
|
python-slugify==4.0.1
|
||||||
pyyaml==6.0
|
pyyaml==6.0
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
AEMET-OpenData==0.2.1
|
AEMET-OpenData==0.2.1
|
||||||
|
|
||||||
# homeassistant.components.aladdin_connect
|
# homeassistant.components.aladdin_connect
|
||||||
AIOAladdinConnect==0.1.55
|
AIOAladdinConnect==0.1.56
|
||||||
|
|
||||||
# homeassistant.components.adax
|
# homeassistant.components.adax
|
||||||
Adax-local==0.1.5
|
Adax-local==0.1.5
|
||||||
@ -1470,7 +1470,7 @@ pyRFXtrx==0.30.0
|
|||||||
pySwitchmate==0.5.1
|
pySwitchmate==0.5.1
|
||||||
|
|
||||||
# homeassistant.components.tibber
|
# homeassistant.components.tibber
|
||||||
pyTibber==0.26.12
|
pyTibber==0.26.13
|
||||||
|
|
||||||
# homeassistant.components.dlink
|
# homeassistant.components.dlink
|
||||||
pyW215==0.7.0
|
pyW215==0.7.0
|
||||||
@ -1828,13 +1828,13 @@ pynzbgetapi==0.2.0
|
|||||||
pyobihai==1.3.2
|
pyobihai==1.3.2
|
||||||
|
|
||||||
# homeassistant.components.octoprint
|
# homeassistant.components.octoprint
|
||||||
pyoctoprintapi==0.1.9
|
pyoctoprintapi==0.1.11
|
||||||
|
|
||||||
# homeassistant.components.ombi
|
# homeassistant.components.ombi
|
||||||
pyombi==0.1.10
|
pyombi==0.1.10
|
||||||
|
|
||||||
# homeassistant.components.openuv
|
# homeassistant.components.openuv
|
||||||
pyopenuv==2023.01.0
|
pyopenuv==2023.02.0
|
||||||
|
|
||||||
# homeassistant.components.opnsense
|
# homeassistant.components.opnsense
|
||||||
pyopnsense==0.2.0
|
pyopnsense==0.2.0
|
||||||
@ -2072,7 +2072,7 @@ python-kasa==0.5.0
|
|||||||
# python-lirc==1.2.3
|
# python-lirc==1.2.3
|
||||||
|
|
||||||
# homeassistant.components.matter
|
# homeassistant.components.matter
|
||||||
python-matter-server==2.0.2
|
python-matter-server==2.1.0
|
||||||
|
|
||||||
# homeassistant.components.xiaomi_miio
|
# homeassistant.components.xiaomi_miio
|
||||||
python-miio==0.5.12
|
python-miio==0.5.12
|
||||||
@ -2227,7 +2227,7 @@ regenmaschine==2022.11.0
|
|||||||
renault-api==0.1.11
|
renault-api==0.1.11
|
||||||
|
|
||||||
# homeassistant.components.reolink
|
# homeassistant.components.reolink
|
||||||
reolink-aio==0.4.0
|
reolink-aio==0.4.2
|
||||||
|
|
||||||
# homeassistant.components.python_script
|
# homeassistant.components.python_script
|
||||||
restrictedpython==6.0
|
restrictedpython==6.0
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
AEMET-OpenData==0.2.1
|
AEMET-OpenData==0.2.1
|
||||||
|
|
||||||
# homeassistant.components.aladdin_connect
|
# homeassistant.components.aladdin_connect
|
||||||
AIOAladdinConnect==0.1.55
|
AIOAladdinConnect==0.1.56
|
||||||
|
|
||||||
# homeassistant.components.adax
|
# homeassistant.components.adax
|
||||||
Adax-local==0.1.5
|
Adax-local==0.1.5
|
||||||
@ -1073,7 +1073,7 @@ pyMetno==0.9.0
|
|||||||
pyRFXtrx==0.30.0
|
pyRFXtrx==0.30.0
|
||||||
|
|
||||||
# homeassistant.components.tibber
|
# homeassistant.components.tibber
|
||||||
pyTibber==0.26.12
|
pyTibber==0.26.13
|
||||||
|
|
||||||
# homeassistant.components.dlink
|
# homeassistant.components.dlink
|
||||||
pyW215==0.7.0
|
pyW215==0.7.0
|
||||||
@ -1317,10 +1317,10 @@ pynx584==0.5
|
|||||||
pynzbgetapi==0.2.0
|
pynzbgetapi==0.2.0
|
||||||
|
|
||||||
# homeassistant.components.octoprint
|
# homeassistant.components.octoprint
|
||||||
pyoctoprintapi==0.1.9
|
pyoctoprintapi==0.1.11
|
||||||
|
|
||||||
# homeassistant.components.openuv
|
# homeassistant.components.openuv
|
||||||
pyopenuv==2023.01.0
|
pyopenuv==2023.02.0
|
||||||
|
|
||||||
# homeassistant.components.opnsense
|
# homeassistant.components.opnsense
|
||||||
pyopnsense==0.2.0
|
pyopnsense==0.2.0
|
||||||
@ -1468,7 +1468,7 @@ python-juicenet==1.1.0
|
|||||||
python-kasa==0.5.0
|
python-kasa==0.5.0
|
||||||
|
|
||||||
# homeassistant.components.matter
|
# homeassistant.components.matter
|
||||||
python-matter-server==2.0.2
|
python-matter-server==2.1.0
|
||||||
|
|
||||||
# homeassistant.components.xiaomi_miio
|
# homeassistant.components.xiaomi_miio
|
||||||
python-miio==0.5.12
|
python-miio==0.5.12
|
||||||
@ -1572,7 +1572,7 @@ regenmaschine==2022.11.0
|
|||||||
renault-api==0.1.11
|
renault-api==0.1.11
|
||||||
|
|
||||||
# homeassistant.components.reolink
|
# homeassistant.components.reolink
|
||||||
reolink-aio==0.4.0
|
reolink-aio==0.4.2
|
||||||
|
|
||||||
# homeassistant.components.python_script
|
# homeassistant.components.python_script
|
||||||
restrictedpython==6.0
|
restrictedpython==6.0
|
||||||
|
@ -5,6 +5,7 @@ import asyncio
|
|||||||
from collections.abc import AsyncGenerator, Generator
|
from collections.abc import AsyncGenerator, Generator
|
||||||
from unittest.mock import AsyncMock, MagicMock, patch
|
from unittest.mock import AsyncMock, MagicMock, patch
|
||||||
|
|
||||||
|
from matter_server.common.const import SCHEMA_VERSION
|
||||||
from matter_server.common.models.server_information import ServerInfo
|
from matter_server.common.models.server_information import ServerInfo
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
@ -45,6 +46,7 @@ async def matter_client_fixture() -> AsyncGenerator[MagicMock, None]:
|
|||||||
sdk_version="2022.11.1",
|
sdk_version="2022.11.1",
|
||||||
wifi_credentials_set=True,
|
wifi_credentials_set=True,
|
||||||
thread_credentials_set=True,
|
thread_credentials_set=True,
|
||||||
|
min_supported_schema_version=SCHEMA_VERSION,
|
||||||
)
|
)
|
||||||
|
|
||||||
yield client
|
yield client
|
||||||
|
@ -5,7 +5,8 @@
|
|||||||
"schema_version": 1,
|
"schema_version": 1,
|
||||||
"sdk_version": "2022.12.0",
|
"sdk_version": "2022.12.0",
|
||||||
"wifi_credentials_set": true,
|
"wifi_credentials_set": true,
|
||||||
"thread_credentials_set": false
|
"thread_credentials_set": false,
|
||||||
|
"min_supported_schema_version": 1
|
||||||
},
|
},
|
||||||
"nodes": [
|
"nodes": [
|
||||||
{
|
{
|
||||||
|
@ -6,7 +6,8 @@
|
|||||||
"schema_version": 1,
|
"schema_version": 1,
|
||||||
"sdk_version": "2022.12.0",
|
"sdk_version": "2022.12.0",
|
||||||
"wifi_credentials_set": true,
|
"wifi_credentials_set": true,
|
||||||
"thread_credentials_set": false
|
"thread_credentials_set": false,
|
||||||
|
"min_supported_schema_version": 1
|
||||||
},
|
},
|
||||||
"nodes": [
|
"nodes": [
|
||||||
{
|
{
|
||||||
|
@ -67,14 +67,21 @@ async def test_default_prompt(hass, mock_init_component):
|
|||||||
device_reg.async_update_device(
|
device_reg.async_update_device(
|
||||||
device.id, disabled_by=device_registry.DeviceEntryDisabler.USER
|
device.id, disabled_by=device_registry.DeviceEntryDisabler.USER
|
||||||
)
|
)
|
||||||
device = device_reg.async_get_or_create(
|
device_reg.async_get_or_create(
|
||||||
config_entry_id="1234",
|
config_entry_id="1234",
|
||||||
connections={("test", "9876-no-name")},
|
connections={("test", "9876-no-name")},
|
||||||
manufacturer="Test Manufacturer NoName",
|
manufacturer="Test Manufacturer NoName",
|
||||||
model="Test Model NoName",
|
model="Test Model NoName",
|
||||||
suggested_area="Test Area 2",
|
suggested_area="Test Area 2",
|
||||||
)
|
)
|
||||||
|
device_reg.async_get_or_create(
|
||||||
|
config_entry_id="1234",
|
||||||
|
connections={("test", "9876-integer-values")},
|
||||||
|
name=1,
|
||||||
|
manufacturer=2,
|
||||||
|
model=3,
|
||||||
|
suggested_area="Test Area 2",
|
||||||
|
)
|
||||||
with patch("openai.Completion.create") as mock_create:
|
with patch("openai.Completion.create") as mock_create:
|
||||||
result = await conversation.async_converse(hass, "hello", None, Context())
|
result = await conversation.async_converse(hass, "hello", None, Context())
|
||||||
|
|
||||||
@ -93,6 +100,7 @@ Test Area 2:
|
|||||||
- Test Device 2
|
- Test Device 2
|
||||||
- Test Device 3 (Test Model 3A)
|
- Test Device 3 (Test Model 3A)
|
||||||
- Test Device 4
|
- Test Device 4
|
||||||
|
- 1 (3)
|
||||||
|
|
||||||
Answer the users questions about the world truthfully.
|
Answer the users questions about the world truthfully.
|
||||||
|
|
||||||
|
@ -1548,6 +1548,7 @@ async def test_non_numeric_validation_raise(
|
|||||||
[
|
[
|
||||||
(13, "13"),
|
(13, "13"),
|
||||||
(17.50, "17.5"),
|
(17.50, "17.5"),
|
||||||
|
("1e-05", "1e-05"),
|
||||||
(Decimal(18.50), "18.5"),
|
(Decimal(18.50), "18.5"),
|
||||||
("19.70", "19.70"),
|
("19.70", "19.70"),
|
||||||
(None, STATE_UNKNOWN),
|
(None, STATE_UNKNOWN),
|
||||||
|
@ -21,6 +21,7 @@ from homeassistant.const import (
|
|||||||
SERVICE_RELOAD,
|
SERVICE_RELOAD,
|
||||||
STATE_UNAVAILABLE,
|
STATE_UNAVAILABLE,
|
||||||
STATE_UNKNOWN,
|
STATE_UNKNOWN,
|
||||||
|
UnitOfEnergy,
|
||||||
UnitOfTemperature,
|
UnitOfTemperature,
|
||||||
)
|
)
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
@ -250,6 +251,63 @@ async def test_sensor_source_with_force_update(hass: HomeAssistant):
|
|||||||
assert state_force.attributes.get("buffer_usage_ratio") == round(9 / 20, 2)
|
assert state_force.attributes.get("buffer_usage_ratio") == round(9 / 20, 2)
|
||||||
|
|
||||||
|
|
||||||
|
async def test_sampling_boundaries_given(hass: HomeAssistant):
|
||||||
|
"""Test if either sampling_size or max_age are given."""
|
||||||
|
assert await async_setup_component(
|
||||||
|
hass,
|
||||||
|
"sensor",
|
||||||
|
{
|
||||||
|
"sensor": [
|
||||||
|
{
|
||||||
|
"platform": "statistics",
|
||||||
|
"name": "test_boundaries_none",
|
||||||
|
"entity_id": "sensor.test_monitored",
|
||||||
|
"state_characteristic": "mean",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"platform": "statistics",
|
||||||
|
"name": "test_boundaries_size",
|
||||||
|
"entity_id": "sensor.test_monitored",
|
||||||
|
"state_characteristic": "mean",
|
||||||
|
"sampling_size": 20,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"platform": "statistics",
|
||||||
|
"name": "test_boundaries_age",
|
||||||
|
"entity_id": "sensor.test_monitored",
|
||||||
|
"state_characteristic": "mean",
|
||||||
|
"max_age": {"minutes": 4},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"platform": "statistics",
|
||||||
|
"name": "test_boundaries_both",
|
||||||
|
"entity_id": "sensor.test_monitored",
|
||||||
|
"state_characteristic": "mean",
|
||||||
|
"sampling_size": 20,
|
||||||
|
"max_age": {"minutes": 4},
|
||||||
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
hass.states.async_set(
|
||||||
|
"sensor.test_monitored",
|
||||||
|
str(VALUES_NUMERIC[0]),
|
||||||
|
{ATTR_UNIT_OF_MEASUREMENT: UnitOfTemperature.CELSIUS},
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
state = hass.states.get("sensor.test_boundaries_none")
|
||||||
|
assert state is None
|
||||||
|
state = hass.states.get("sensor.test_boundaries_size")
|
||||||
|
assert state is not None
|
||||||
|
state = hass.states.get("sensor.test_boundaries_age")
|
||||||
|
assert state is not None
|
||||||
|
state = hass.states.get("sensor.test_boundaries_both")
|
||||||
|
assert state is not None
|
||||||
|
|
||||||
|
|
||||||
async def test_sampling_size_reduced(hass: HomeAssistant):
|
async def test_sampling_size_reduced(hass: HomeAssistant):
|
||||||
"""Test limited buffer size."""
|
"""Test limited buffer size."""
|
||||||
assert await async_setup_component(
|
assert await async_setup_component(
|
||||||
@ -514,9 +572,9 @@ async def test_device_class(hass: HomeAssistant):
|
|||||||
{
|
{
|
||||||
"sensor": [
|
"sensor": [
|
||||||
{
|
{
|
||||||
# Device class is carried over from source sensor for characteristics with same unit
|
# Device class is carried over from source sensor for characteristics which retain unit
|
||||||
"platform": "statistics",
|
"platform": "statistics",
|
||||||
"name": "test_source_class",
|
"name": "test_retain_unit",
|
||||||
"entity_id": "sensor.test_monitored",
|
"entity_id": "sensor.test_monitored",
|
||||||
"state_characteristic": "mean",
|
"state_characteristic": "mean",
|
||||||
"sampling_size": 20,
|
"sampling_size": 20,
|
||||||
@ -537,6 +595,14 @@ async def test_device_class(hass: HomeAssistant):
|
|||||||
"state_characteristic": "datetime_oldest",
|
"state_characteristic": "datetime_oldest",
|
||||||
"sampling_size": 20,
|
"sampling_size": 20,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
# Device class is set to None for any source sensor with TOTAL state class
|
||||||
|
"platform": "statistics",
|
||||||
|
"name": "test_source_class_total",
|
||||||
|
"entity_id": "sensor.test_monitored_total",
|
||||||
|
"state_characteristic": "mean",
|
||||||
|
"sampling_size": 20,
|
||||||
|
},
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
@ -549,11 +615,21 @@ async def test_device_class(hass: HomeAssistant):
|
|||||||
{
|
{
|
||||||
ATTR_UNIT_OF_MEASUREMENT: UnitOfTemperature.CELSIUS,
|
ATTR_UNIT_OF_MEASUREMENT: UnitOfTemperature.CELSIUS,
|
||||||
ATTR_DEVICE_CLASS: SensorDeviceClass.TEMPERATURE,
|
ATTR_DEVICE_CLASS: SensorDeviceClass.TEMPERATURE,
|
||||||
|
ATTR_STATE_CLASS: SensorStateClass.MEASUREMENT,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
hass.states.async_set(
|
||||||
|
"sensor.test_monitored_total",
|
||||||
|
str(value),
|
||||||
|
{
|
||||||
|
ATTR_UNIT_OF_MEASUREMENT: UnitOfEnergy.WATT_HOUR,
|
||||||
|
ATTR_DEVICE_CLASS: SensorDeviceClass.ENERGY,
|
||||||
|
ATTR_STATE_CLASS: SensorStateClass.TOTAL,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
state = hass.states.get("sensor.test_source_class")
|
state = hass.states.get("sensor.test_retain_unit")
|
||||||
assert state is not None
|
assert state is not None
|
||||||
assert state.attributes.get(ATTR_DEVICE_CLASS) == SensorDeviceClass.TEMPERATURE
|
assert state.attributes.get(ATTR_DEVICE_CLASS) == SensorDeviceClass.TEMPERATURE
|
||||||
state = hass.states.get("sensor.test_none")
|
state = hass.states.get("sensor.test_none")
|
||||||
@ -562,6 +638,9 @@ async def test_device_class(hass: HomeAssistant):
|
|||||||
state = hass.states.get("sensor.test_timestamp")
|
state = hass.states.get("sensor.test_timestamp")
|
||||||
assert state is not None
|
assert state is not None
|
||||||
assert state.attributes.get(ATTR_DEVICE_CLASS) == SensorDeviceClass.TIMESTAMP
|
assert state.attributes.get(ATTR_DEVICE_CLASS) == SensorDeviceClass.TIMESTAMP
|
||||||
|
state = hass.states.get("sensor.test_source_class_total")
|
||||||
|
assert state is not None
|
||||||
|
assert state.attributes.get(ATTR_DEVICE_CLASS) is None
|
||||||
|
|
||||||
|
|
||||||
async def test_state_class(hass: HomeAssistant):
|
async def test_state_class(hass: HomeAssistant):
|
||||||
@ -572,6 +651,15 @@ async def test_state_class(hass: HomeAssistant):
|
|||||||
{
|
{
|
||||||
"sensor": [
|
"sensor": [
|
||||||
{
|
{
|
||||||
|
# State class is None for datetime characteristics
|
||||||
|
"platform": "statistics",
|
||||||
|
"name": "test_nan",
|
||||||
|
"entity_id": "sensor.test_monitored",
|
||||||
|
"state_characteristic": "datetime_oldest",
|
||||||
|
"sampling_size": 20,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
# State class is MEASUREMENT for all other characteristics
|
||||||
"platform": "statistics",
|
"platform": "statistics",
|
||||||
"name": "test_normal",
|
"name": "test_normal",
|
||||||
"entity_id": "sensor.test_monitored",
|
"entity_id": "sensor.test_monitored",
|
||||||
@ -579,10 +667,12 @@ async def test_state_class(hass: HomeAssistant):
|
|||||||
"sampling_size": 20,
|
"sampling_size": 20,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
# State class is MEASUREMENT, even when the source sensor
|
||||||
|
# is of state class TOTAL
|
||||||
"platform": "statistics",
|
"platform": "statistics",
|
||||||
"name": "test_nan",
|
"name": "test_total",
|
||||||
"entity_id": "sensor.test_monitored",
|
"entity_id": "sensor.test_monitored_total",
|
||||||
"state_characteristic": "datetime_oldest",
|
"state_characteristic": "count",
|
||||||
"sampling_size": 20,
|
"sampling_size": 20,
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
@ -596,14 +686,28 @@ async def test_state_class(hass: HomeAssistant):
|
|||||||
str(value),
|
str(value),
|
||||||
{ATTR_UNIT_OF_MEASUREMENT: UnitOfTemperature.CELSIUS},
|
{ATTR_UNIT_OF_MEASUREMENT: UnitOfTemperature.CELSIUS},
|
||||||
)
|
)
|
||||||
|
hass.states.async_set(
|
||||||
|
"sensor.test_monitored_total",
|
||||||
|
str(value),
|
||||||
|
{
|
||||||
|
ATTR_UNIT_OF_MEASUREMENT: UnitOfTemperature.CELSIUS,
|
||||||
|
ATTR_STATE_CLASS: SensorStateClass.TOTAL,
|
||||||
|
},
|
||||||
|
)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
state = hass.states.get("sensor.test_normal")
|
|
||||||
assert state is not None
|
|
||||||
assert state.attributes.get(ATTR_STATE_CLASS) is SensorStateClass.MEASUREMENT
|
|
||||||
state = hass.states.get("sensor.test_nan")
|
state = hass.states.get("sensor.test_nan")
|
||||||
assert state is not None
|
assert state is not None
|
||||||
assert state.attributes.get(ATTR_STATE_CLASS) is None
|
assert state.attributes.get(ATTR_STATE_CLASS) is None
|
||||||
|
state = hass.states.get("sensor.test_normal")
|
||||||
|
assert state is not None
|
||||||
|
assert state.attributes.get(ATTR_STATE_CLASS) is SensorStateClass.MEASUREMENT
|
||||||
|
state = hass.states.get("sensor.test_monitored_total")
|
||||||
|
assert state is not None
|
||||||
|
assert state.attributes.get(ATTR_STATE_CLASS) is SensorStateClass.TOTAL
|
||||||
|
state = hass.states.get("sensor.test_total")
|
||||||
|
assert state is not None
|
||||||
|
assert state.attributes.get(ATTR_STATE_CLASS) is SensorStateClass.MEASUREMENT
|
||||||
|
|
||||||
|
|
||||||
async def test_unitless_source_sensor(hass: HomeAssistant):
|
async def test_unitless_source_sensor(hass: HomeAssistant):
|
||||||
|
@ -49,6 +49,21 @@ def fixture_mock_appliances_manager_api():
|
|||||||
yield mock_appliances_manager
|
yield mock_appliances_manager
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(name="mock_appliances_manager_laundry_api")
|
||||||
|
def fixture_mock_appliances_manager_laundry_api():
|
||||||
|
"""Set up AppliancesManager fixture."""
|
||||||
|
with mock.patch(
|
||||||
|
"homeassistant.components.whirlpool.AppliancesManager"
|
||||||
|
) as mock_appliances_manager:
|
||||||
|
mock_appliances_manager.return_value.fetch_appliances = AsyncMock()
|
||||||
|
mock_appliances_manager.return_value.aircons = None
|
||||||
|
mock_appliances_manager.return_value.washer_dryers = [
|
||||||
|
{"SAID": MOCK_SAID3, "NAME": "washer"},
|
||||||
|
{"SAID": MOCK_SAID4, "NAME": "dryer"},
|
||||||
|
]
|
||||||
|
yield mock_appliances_manager
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(name="mock_backend_selector_api")
|
@pytest.fixture(name="mock_backend_selector_api")
|
||||||
def fixture_mock_backend_selector_api():
|
def fixture_mock_backend_selector_api():
|
||||||
"""Set up BackendSelector fixture."""
|
"""Set up BackendSelector fixture."""
|
||||||
@ -115,8 +130,6 @@ def side_effect_function(*args, **kwargs):
|
|||||||
return "0"
|
return "0"
|
||||||
if args[0] == "WashCavity_OpStatusBulkDispense1Level":
|
if args[0] == "WashCavity_OpStatusBulkDispense1Level":
|
||||||
return "3"
|
return "3"
|
||||||
if args[0] == "Cavity_TimeStatusEstTimeRemaining":
|
|
||||||
return "4000"
|
|
||||||
|
|
||||||
|
|
||||||
def get_sensor_mock(said):
|
def get_sensor_mock(said):
|
||||||
@ -141,13 +154,13 @@ def get_sensor_mock(said):
|
|||||||
|
|
||||||
|
|
||||||
@pytest.fixture(name="mock_sensor1_api", autouse=False)
|
@pytest.fixture(name="mock_sensor1_api", autouse=False)
|
||||||
def fixture_mock_sensor1_api(mock_auth_api, mock_appliances_manager_api):
|
def fixture_mock_sensor1_api(mock_auth_api, mock_appliances_manager_laundry_api):
|
||||||
"""Set up sensor API fixture."""
|
"""Set up sensor API fixture."""
|
||||||
yield get_sensor_mock(MOCK_SAID3)
|
yield get_sensor_mock(MOCK_SAID3)
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(name="mock_sensor2_api", autouse=False)
|
@pytest.fixture(name="mock_sensor2_api", autouse=False)
|
||||||
def fixture_mock_sensor2_api(mock_auth_api, mock_appliances_manager_api):
|
def fixture_mock_sensor2_api(mock_auth_api, mock_appliances_manager_laundry_api):
|
||||||
"""Set up sensor API fixture."""
|
"""Set up sensor API fixture."""
|
||||||
yield get_sensor_mock(MOCK_SAID4)
|
yield get_sensor_mock(MOCK_SAID4)
|
||||||
|
|
||||||
@ -161,5 +174,7 @@ def fixture_mock_sensor_api_instances(mock_sensor1_api, mock_sensor2_api):
|
|||||||
mock_sensor_api.side_effect = [
|
mock_sensor_api.side_effect = [
|
||||||
mock_sensor1_api,
|
mock_sensor1_api,
|
||||||
mock_sensor2_api,
|
mock_sensor2_api,
|
||||||
|
mock_sensor1_api,
|
||||||
|
mock_sensor2_api,
|
||||||
]
|
]
|
||||||
yield mock_sensor_api
|
yield mock_sensor_api
|
||||||
|
@ -17,7 +17,7 @@ async def update_sensor_state(
|
|||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
entity_id: str,
|
entity_id: str,
|
||||||
mock_sensor_api_instance: MagicMock,
|
mock_sensor_api_instance: MagicMock,
|
||||||
):
|
) -> None:
|
||||||
"""Simulate an update trigger from the API."""
|
"""Simulate an update trigger from the API."""
|
||||||
|
|
||||||
for call in mock_sensor_api_instance.register_attr_callback.call_args_list:
|
for call in mock_sensor_api_instance.register_attr_callback.call_args_list:
|
||||||
@ -44,7 +44,7 @@ async def test_dryer_sensor_values(
|
|||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
mock_sensor_api_instances: MagicMock,
|
mock_sensor_api_instances: MagicMock,
|
||||||
mock_sensor2_api: MagicMock,
|
mock_sensor2_api: MagicMock,
|
||||||
):
|
) -> None:
|
||||||
"""Test the sensor value callbacks."""
|
"""Test the sensor value callbacks."""
|
||||||
hass.state = CoreState.not_running
|
hass.state = CoreState.not_running
|
||||||
thetimestamp: datetime = datetime(2022, 11, 29, 00, 00, 00, 00, timezone.utc)
|
thetimestamp: datetime = datetime(2022, 11, 29, 00, 00, 00, 00, timezone.utc)
|
||||||
@ -108,7 +108,7 @@ async def test_washer_sensor_values(
|
|||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
mock_sensor_api_instances: MagicMock,
|
mock_sensor_api_instances: MagicMock,
|
||||||
mock_sensor1_api: MagicMock,
|
mock_sensor1_api: MagicMock,
|
||||||
):
|
) -> None:
|
||||||
"""Test the sensor value callbacks."""
|
"""Test the sensor value callbacks."""
|
||||||
hass.state = CoreState.not_running
|
hass.state = CoreState.not_running
|
||||||
thetimestamp: datetime = datetime(2022, 11, 29, 00, 00, 00, 00, timezone.utc)
|
thetimestamp: datetime = datetime(2022, 11, 29, 00, 00, 00, 00, timezone.utc)
|
||||||
@ -147,6 +147,21 @@ async def test_washer_sensor_values(
|
|||||||
assert state.state == thetimestamp.isoformat()
|
assert state.state == thetimestamp.isoformat()
|
||||||
|
|
||||||
state_id = f"{entity_id.split('_')[0]}_detergent_level"
|
state_id = f"{entity_id.split('_')[0]}_detergent_level"
|
||||||
|
registry = entity_registry.async_get(hass)
|
||||||
|
entry = registry.async_get(state_id)
|
||||||
|
assert entry
|
||||||
|
assert entry.disabled
|
||||||
|
assert entry.disabled_by is entity_registry.RegistryEntryDisabler.INTEGRATION
|
||||||
|
|
||||||
|
update_entry = registry.async_update_entity(entry.entity_id, disabled_by=None)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
assert update_entry != entry
|
||||||
|
assert update_entry.disabled is False
|
||||||
|
state = hass.states.get(state_id)
|
||||||
|
assert state is None
|
||||||
|
|
||||||
|
await hass.config_entries.async_reload(entry.config_entry_id)
|
||||||
state = hass.states.get(state_id)
|
state = hass.states.get(state_id)
|
||||||
assert state is not None
|
assert state is not None
|
||||||
assert state.state == "50"
|
assert state.state == "50"
|
||||||
@ -253,7 +268,7 @@ async def test_washer_sensor_values(
|
|||||||
async def test_restore_state(
|
async def test_restore_state(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
mock_sensor_api_instances: MagicMock,
|
mock_sensor_api_instances: MagicMock,
|
||||||
):
|
) -> None:
|
||||||
"""Test sensor restore state."""
|
"""Test sensor restore state."""
|
||||||
# Home assistant is not running yet
|
# Home assistant is not running yet
|
||||||
hass.state = CoreState.not_running
|
hass.state = CoreState.not_running
|
||||||
@ -288,7 +303,7 @@ async def test_callback(
|
|||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
mock_sensor_api_instances: MagicMock,
|
mock_sensor_api_instances: MagicMock,
|
||||||
mock_sensor1_api: MagicMock,
|
mock_sensor1_api: MagicMock,
|
||||||
):
|
) -> None:
|
||||||
"""Test callback timestamp callback function."""
|
"""Test callback timestamp callback function."""
|
||||||
hass.state = CoreState.not_running
|
hass.state = CoreState.not_running
|
||||||
thetimestamp: datetime = datetime(2022, 11, 29, 00, 00, 00, 00, timezone.utc)
|
thetimestamp: datetime = datetime(2022, 11, 29, 00, 00, 00, 00, timezone.utc)
|
||||||
@ -314,9 +329,9 @@ async def test_callback(
|
|||||||
# restore from cache
|
# restore from cache
|
||||||
state = hass.states.get("sensor.washer_end_time")
|
state = hass.states.get("sensor.washer_end_time")
|
||||||
assert state.state == thetimestamp.isoformat()
|
assert state.state == thetimestamp.isoformat()
|
||||||
callback = mock_sensor1_api.register_attr_callback.call_args_list[2][0][0]
|
callback = mock_sensor1_api.register_attr_callback.call_args_list[1][0][0]
|
||||||
callback()
|
callback()
|
||||||
# await hass.async_block_till_done()
|
|
||||||
state = hass.states.get("sensor.washer_end_time")
|
state = hass.states.get("sensor.washer_end_time")
|
||||||
assert state.state == thetimestamp.isoformat()
|
assert state.state == thetimestamp.isoformat()
|
||||||
mock_sensor1_api.get_machine_state.return_value = MachineState.RunningMainCycle
|
mock_sensor1_api.get_machine_state.return_value = MachineState.RunningMainCycle
|
||||||
|
Loading…
x
Reference in New Issue
Block a user