mirror of
https://github.com/home-assistant/core.git
synced 2026-01-11 09:38:26 +00:00
Compare commits
17 Commits
claude/ip-
...
dev
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
98e918cd8a | ||
|
|
1efc87bfef | ||
|
|
b4360ccbd9 | ||
|
|
ce234d69a7 | ||
|
|
b2a198e230 | ||
|
|
538009d2df | ||
|
|
99329851a2 | ||
|
|
f8ec395e96 | ||
|
|
98fe189edf | ||
|
|
7b413e3fd3 | ||
|
|
00ca5473d4 | ||
|
|
33c808713e | ||
|
|
c97437fbf3 | ||
|
|
ad8f14fec1 | ||
|
|
7df586eff1 | ||
|
|
f6fa95d2f7 | ||
|
|
23a8300012 |
@@ -43,6 +43,13 @@ BUTTON_TYPES: tuple[AirobotButtonEntityDescription, ...] = (
|
||||
entity_category=EntityCategory.CONFIG,
|
||||
press_fn=lambda coordinator: coordinator.client.reboot_thermostat(),
|
||||
),
|
||||
AirobotButtonEntityDescription(
|
||||
key="recalibrate_co2",
|
||||
translation_key="recalibrate_co2",
|
||||
entity_category=EntityCategory.CONFIG,
|
||||
entity_registry_enabled_default=False,
|
||||
press_fn=lambda coordinator: coordinator.client.recalibrate_co2_sensor(),
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
{
|
||||
"entity": {
|
||||
"button": {
|
||||
"recalibrate_co2": {
|
||||
"default": "mdi:molecule-co2"
|
||||
}
|
||||
},
|
||||
"number": {
|
||||
"hysteresis_band": {
|
||||
"default": "mdi:delta"
|
||||
|
||||
@@ -59,6 +59,11 @@
|
||||
}
|
||||
},
|
||||
"entity": {
|
||||
"button": {
|
||||
"recalibrate_co2": {
|
||||
"name": "Recalibrate CO2 sensor"
|
||||
}
|
||||
},
|
||||
"number": {
|
||||
"hysteresis_band": {
|
||||
"name": "Hysteresis band"
|
||||
|
||||
@@ -12,5 +12,5 @@
|
||||
"integration_type": "hub",
|
||||
"iot_class": "local_polling",
|
||||
"loggers": ["aioairzone"],
|
||||
"requirements": ["aioairzone==1.0.4"]
|
||||
"requirements": ["aioairzone==1.0.5"]
|
||||
}
|
||||
|
||||
@@ -8,5 +8,5 @@
|
||||
"integration_type": "system",
|
||||
"iot_class": "local_push",
|
||||
"quality_scale": "internal",
|
||||
"requirements": ["pysilero-vad==3.1.0", "pyspeex-noise==1.0.2"]
|
||||
"requirements": ["pysilero-vad==3.2.0", "pyspeex-noise==1.0.2"]
|
||||
}
|
||||
|
||||
@@ -20,5 +20,5 @@
|
||||
"dependencies": ["bluetooth_adapters"],
|
||||
"documentation": "https://www.home-assistant.io/integrations/bthome",
|
||||
"iot_class": "local_push",
|
||||
"requirements": ["bthome-ble==3.17.0"]
|
||||
"requirements": ["bthome-ble==3.16.0"]
|
||||
}
|
||||
|
||||
@@ -6,6 +6,6 @@
|
||||
"documentation": "https://www.home-assistant.io/integrations/easyenergy",
|
||||
"integration_type": "service",
|
||||
"iot_class": "cloud_polling",
|
||||
"requirements": ["easyenergy==2.1.2"],
|
||||
"requirements": ["easyenergy==2.2.0"],
|
||||
"single_config_entry": true
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ class EheimDigitalEntity[_DeviceT: EheimDigitalDevice](
|
||||
name=device.name,
|
||||
connections={(CONNECTION_NETWORK_MAC, device.mac_address)},
|
||||
manufacturer="EHEIM",
|
||||
model=device.device_type.model_name,
|
||||
model=device.model_name,
|
||||
identifiers={(DOMAIN, device.mac_address)},
|
||||
suggested_area=device.aquarium_name,
|
||||
sw_version=device.sw_version,
|
||||
@@ -59,9 +59,9 @@ class EheimDigitalEntity[_DeviceT: EheimDigitalDevice](
|
||||
def exception_handler[_EntityT: EheimDigitalEntity[EheimDigitalDevice], **_P](
|
||||
func: Callable[Concatenate[_EntityT, _P], Coroutine[Any, Any, Any]],
|
||||
) -> Callable[Concatenate[_EntityT, _P], Coroutine[Any, Any, None]]:
|
||||
"""Decorate AirGradient calls to handle exceptions.
|
||||
"""Decorate eheimdigital calls to handle exceptions.
|
||||
|
||||
A decorator that wraps the passed in function, catches AirGradient errors.
|
||||
A decorator that wraps the passed in function, catches eheimdigital errors.
|
||||
"""
|
||||
|
||||
async def handler(self: _EntityT, *args: _P.args, **kwargs: _P.kwargs) -> None:
|
||||
|
||||
@@ -6,6 +6,7 @@ from typing import Any, override
|
||||
|
||||
from eheimdigital.classic_vario import EheimDigitalClassicVario
|
||||
from eheimdigital.device import EheimDigitalDevice
|
||||
from eheimdigital.filter import EheimDigitalFilter
|
||||
from eheimdigital.heater import EheimDigitalHeater
|
||||
from eheimdigital.types import HeaterUnit
|
||||
|
||||
@@ -21,6 +22,7 @@ from homeassistant.const import (
|
||||
PRECISION_WHOLE,
|
||||
EntityCategory,
|
||||
UnitOfTemperature,
|
||||
UnitOfTime,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
@@ -42,6 +44,34 @@ class EheimDigitalNumberDescription[_DeviceT: EheimDigitalDevice](
|
||||
uom_fn: Callable[[_DeviceT], str] | None = None
|
||||
|
||||
|
||||
FILTER_DESCRIPTIONS: tuple[EheimDigitalNumberDescription[EheimDigitalFilter], ...] = (
|
||||
EheimDigitalNumberDescription[EheimDigitalFilter](
|
||||
key="high_pulse_time",
|
||||
translation_key="high_pulse_time",
|
||||
entity_category=EntityCategory.CONFIG,
|
||||
native_step=PRECISION_WHOLE,
|
||||
native_unit_of_measurement=UnitOfTime.SECONDS,
|
||||
device_class=NumberDeviceClass.DURATION,
|
||||
native_min_value=5,
|
||||
native_max_value=200000,
|
||||
value_fn=lambda device: device.high_pulse_time,
|
||||
set_value_fn=lambda device, value: device.set_high_pulse_time(int(value)),
|
||||
),
|
||||
EheimDigitalNumberDescription[EheimDigitalFilter](
|
||||
key="low_pulse_time",
|
||||
translation_key="low_pulse_time",
|
||||
entity_category=EntityCategory.CONFIG,
|
||||
native_step=PRECISION_WHOLE,
|
||||
native_unit_of_measurement=UnitOfTime.SECONDS,
|
||||
device_class=NumberDeviceClass.DURATION,
|
||||
native_min_value=5,
|
||||
native_max_value=200000,
|
||||
value_fn=lambda device: device.low_pulse_time,
|
||||
set_value_fn=lambda device, value: device.set_low_pulse_time(int(value)),
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
CLASSICVARIO_DESCRIPTIONS: tuple[
|
||||
EheimDigitalNumberDescription[EheimDigitalClassicVario], ...
|
||||
] = (
|
||||
@@ -145,6 +175,13 @@ async def async_setup_entry(
|
||||
)
|
||||
for description in CLASSICVARIO_DESCRIPTIONS
|
||||
)
|
||||
if isinstance(device, EheimDigitalFilter):
|
||||
entities.extend(
|
||||
EheimDigitalNumber[EheimDigitalFilter](
|
||||
coordinator, device, description
|
||||
)
|
||||
for description in FILTER_DESCRIPTIONS
|
||||
)
|
||||
if isinstance(device, EheimDigitalHeater):
|
||||
entities.extend(
|
||||
EheimDigitalNumber[EheimDigitalHeater](
|
||||
|
||||
@@ -2,13 +2,19 @@
|
||||
|
||||
from collections.abc import Awaitable, Callable
|
||||
from dataclasses import dataclass
|
||||
from typing import Any, override
|
||||
from typing import Any, Literal, override
|
||||
|
||||
from eheimdigital.classic_vario import EheimDigitalClassicVario
|
||||
from eheimdigital.device import EheimDigitalDevice
|
||||
from eheimdigital.types import FilterMode
|
||||
from eheimdigital.filter import EheimDigitalFilter
|
||||
from eheimdigital.types import (
|
||||
FilterMode,
|
||||
FilterModeProf,
|
||||
UnitOfMeasurement as EheimDigitalUnitOfMeasurement,
|
||||
)
|
||||
|
||||
from homeassistant.components.select import SelectEntity, SelectEntityDescription
|
||||
from homeassistant.const import EntityCategory, UnitOfFrequency, UnitOfVolumeFlowRate
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
|
||||
@@ -24,8 +30,109 @@ class EheimDigitalSelectDescription[_DeviceT: EheimDigitalDevice](
|
||||
):
|
||||
"""Class describing EHEIM Digital select entities."""
|
||||
|
||||
options_fn: Callable[[_DeviceT], list[str]] | None = None
|
||||
use_api_unit: Literal[True] | None = None
|
||||
value_fn: Callable[[_DeviceT], str | None]
|
||||
set_value_fn: Callable[[_DeviceT, str], Awaitable[None]]
|
||||
set_value_fn: Callable[[_DeviceT, str], Awaitable[None] | None]
|
||||
|
||||
|
||||
FILTER_DESCRIPTIONS: tuple[EheimDigitalSelectDescription[EheimDigitalFilter], ...] = (
|
||||
EheimDigitalSelectDescription[EheimDigitalFilter](
|
||||
key="filter_mode",
|
||||
translation_key="filter_mode",
|
||||
entity_category=EntityCategory.CONFIG,
|
||||
options=[item.lower() for item in FilterModeProf._member_names_],
|
||||
value_fn=lambda device: device.filter_mode.name.lower(),
|
||||
set_value_fn=lambda device, value: device.set_filter_mode(
|
||||
FilterModeProf[value.upper()]
|
||||
),
|
||||
),
|
||||
EheimDigitalSelectDescription[EheimDigitalFilter](
|
||||
key="manual_speed",
|
||||
translation_key="manual_speed",
|
||||
entity_category=EntityCategory.CONFIG,
|
||||
unit_of_measurement=UnitOfFrequency.HERTZ,
|
||||
options_fn=lambda device: [str(i) for i in device.filter_manual_values],
|
||||
value_fn=lambda device: str(device.manual_speed),
|
||||
set_value_fn=lambda device, value: device.set_manual_speed(float(value)),
|
||||
),
|
||||
EheimDigitalSelectDescription[EheimDigitalFilter](
|
||||
key="const_flow_speed",
|
||||
translation_key="const_flow_speed",
|
||||
entity_category=EntityCategory.CONFIG,
|
||||
use_api_unit=True,
|
||||
unit_of_measurement=UnitOfVolumeFlowRate.LITERS_PER_HOUR,
|
||||
options_fn=lambda device: [str(i) for i in device.filter_const_flow_values],
|
||||
value_fn=lambda device: str(device.filter_const_flow_values[device.const_flow]),
|
||||
set_value_fn=(
|
||||
lambda device, value: device.set_const_flow(
|
||||
device.filter_const_flow_values.index(int(value))
|
||||
)
|
||||
),
|
||||
),
|
||||
EheimDigitalSelectDescription[EheimDigitalFilter](
|
||||
key="day_speed",
|
||||
translation_key="day_speed",
|
||||
entity_category=EntityCategory.CONFIG,
|
||||
use_api_unit=True,
|
||||
unit_of_measurement=UnitOfVolumeFlowRate.LITERS_PER_HOUR,
|
||||
options_fn=lambda device: [str(i) for i in device.filter_const_flow_values],
|
||||
value_fn=lambda device: str(device.filter_const_flow_values[device.day_speed]),
|
||||
set_value_fn=(
|
||||
lambda device, value: device.set_day_speed(
|
||||
device.filter_const_flow_values.index(int(value))
|
||||
)
|
||||
),
|
||||
),
|
||||
EheimDigitalSelectDescription[EheimDigitalFilter](
|
||||
key="night_speed",
|
||||
translation_key="night_speed",
|
||||
entity_category=EntityCategory.CONFIG,
|
||||
use_api_unit=True,
|
||||
unit_of_measurement=UnitOfVolumeFlowRate.LITERS_PER_HOUR,
|
||||
options_fn=lambda device: [str(i) for i in device.filter_const_flow_values],
|
||||
value_fn=lambda device: str(
|
||||
device.filter_const_flow_values[device.night_speed]
|
||||
),
|
||||
set_value_fn=(
|
||||
lambda device, value: device.set_night_speed(
|
||||
device.filter_const_flow_values.index(int(value))
|
||||
)
|
||||
),
|
||||
),
|
||||
EheimDigitalSelectDescription[EheimDigitalFilter](
|
||||
key="high_pulse_speed",
|
||||
translation_key="high_pulse_speed",
|
||||
entity_category=EntityCategory.CONFIG,
|
||||
use_api_unit=True,
|
||||
unit_of_measurement=UnitOfVolumeFlowRate.LITERS_PER_HOUR,
|
||||
options_fn=lambda device: [str(i) for i in device.filter_const_flow_values],
|
||||
value_fn=lambda device: str(
|
||||
device.filter_const_flow_values[device.high_pulse_speed]
|
||||
),
|
||||
set_value_fn=(
|
||||
lambda device, value: device.set_high_pulse_speed(
|
||||
device.filter_const_flow_values.index(int(value))
|
||||
)
|
||||
),
|
||||
),
|
||||
EheimDigitalSelectDescription[EheimDigitalFilter](
|
||||
key="low_pulse_speed",
|
||||
translation_key="low_pulse_speed",
|
||||
entity_category=EntityCategory.CONFIG,
|
||||
use_api_unit=True,
|
||||
unit_of_measurement=UnitOfVolumeFlowRate.LITERS_PER_HOUR,
|
||||
options_fn=lambda device: [str(i) for i in device.filter_const_flow_values],
|
||||
value_fn=lambda device: str(
|
||||
device.filter_const_flow_values[device.low_pulse_speed]
|
||||
),
|
||||
set_value_fn=(
|
||||
lambda device, value: device.set_low_pulse_speed(
|
||||
device.filter_const_flow_values.index(int(value))
|
||||
)
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
CLASSICVARIO_DESCRIPTIONS: tuple[
|
||||
@@ -34,11 +141,7 @@ CLASSICVARIO_DESCRIPTIONS: tuple[
|
||||
EheimDigitalSelectDescription[EheimDigitalClassicVario](
|
||||
key="filter_mode",
|
||||
translation_key="filter_mode",
|
||||
value_fn=(
|
||||
lambda device: device.filter_mode.name.lower()
|
||||
if device.filter_mode is not None
|
||||
else None
|
||||
),
|
||||
value_fn=lambda device: device.filter_mode.name.lower(),
|
||||
set_value_fn=(
|
||||
lambda device, value: device.set_filter_mode(FilterMode[value.upper()])
|
||||
),
|
||||
@@ -68,6 +171,11 @@ async def async_setup_entry(
|
||||
)
|
||||
for description in CLASSICVARIO_DESCRIPTIONS
|
||||
)
|
||||
if isinstance(device, EheimDigitalFilter):
|
||||
entities.extend(
|
||||
EheimDigitalFilterSelect(coordinator, device, description)
|
||||
for description in FILTER_DESCRIPTIONS
|
||||
)
|
||||
|
||||
async_add_entities(entities)
|
||||
|
||||
@@ -82,6 +190,8 @@ class EheimDigitalSelect[_DeviceT: EheimDigitalDevice](
|
||||
|
||||
entity_description: EheimDigitalSelectDescription[_DeviceT]
|
||||
|
||||
_attr_options: list[str]
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
coordinator: EheimDigitalUpdateCoordinator,
|
||||
@@ -91,13 +201,49 @@ class EheimDigitalSelect[_DeviceT: EheimDigitalDevice](
|
||||
"""Initialize an EHEIM Digital select entity."""
|
||||
super().__init__(coordinator, device)
|
||||
self.entity_description = description
|
||||
if description.options_fn is not None:
|
||||
self._attr_options = description.options_fn(device)
|
||||
elif description.options is not None:
|
||||
self._attr_options = description.options
|
||||
self._attr_unique_id = f"{self._device_address}_{description.key}"
|
||||
|
||||
@override
|
||||
@exception_handler
|
||||
async def async_select_option(self, option: str) -> None:
|
||||
return await self.entity_description.set_value_fn(self._device, option)
|
||||
if await_return := self.entity_description.set_value_fn(self._device, option):
|
||||
return await await_return
|
||||
return None
|
||||
|
||||
@override
|
||||
def _async_update_attrs(self) -> None:
|
||||
self._attr_current_option = self.entity_description.value_fn(self._device)
|
||||
|
||||
|
||||
class EheimDigitalFilterSelect(EheimDigitalSelect[EheimDigitalFilter]):
|
||||
"""Represent an EHEIM Digital Filter select entity."""
|
||||
|
||||
entity_description: EheimDigitalSelectDescription[EheimDigitalFilter]
|
||||
_attr_native_unit_of_measurement: str | None
|
||||
|
||||
@override
|
||||
def _async_update_attrs(self) -> None:
|
||||
if (
|
||||
self.entity_description.options is None
|
||||
and self.entity_description.options_fn is not None
|
||||
):
|
||||
self._attr_options = self.entity_description.options_fn(self._device)
|
||||
if self.entity_description.use_api_unit:
|
||||
if (
|
||||
self.entity_description.unit_of_measurement
|
||||
== UnitOfVolumeFlowRate.LITERS_PER_HOUR
|
||||
and self._device.usrdta["unit"]
|
||||
== int(EheimDigitalUnitOfMeasurement.US_CUSTOMARY)
|
||||
):
|
||||
self._attr_native_unit_of_measurement = (
|
||||
UnitOfVolumeFlowRate.GALLONS_PER_HOUR
|
||||
)
|
||||
else:
|
||||
self._attr_native_unit_of_measurement = (
|
||||
self.entity_description.unit_of_measurement
|
||||
)
|
||||
super()._async_update_attrs()
|
||||
|
||||
@@ -6,6 +6,7 @@ from typing import Any, override
|
||||
|
||||
from eheimdigital.classic_vario import EheimDigitalClassicVario
|
||||
from eheimdigital.device import EheimDigitalDevice
|
||||
from eheimdigital.filter import EheimDigitalFilter
|
||||
from eheimdigital.types import FilterErrorCode
|
||||
|
||||
from homeassistant.components.sensor import (
|
||||
@@ -13,7 +14,7 @@ from homeassistant.components.sensor import (
|
||||
SensorEntity,
|
||||
SensorEntityDescription,
|
||||
)
|
||||
from homeassistant.const import PERCENTAGE, EntityCategory, UnitOfTime
|
||||
from homeassistant.const import PERCENTAGE, EntityCategory, UnitOfFrequency, UnitOfTime
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
|
||||
@@ -33,6 +34,27 @@ class EheimDigitalSensorDescription[_DeviceT: EheimDigitalDevice](
|
||||
value_fn: Callable[[_DeviceT], float | str | None]
|
||||
|
||||
|
||||
FILTER_DESCRIPTIONS: tuple[EheimDigitalSensorDescription[EheimDigitalFilter], ...] = (
|
||||
EheimDigitalSensorDescription[EheimDigitalFilter](
|
||||
key="current_speed",
|
||||
translation_key="current_speed",
|
||||
value_fn=lambda device: device.current_speed,
|
||||
device_class=SensorDeviceClass.FREQUENCY,
|
||||
suggested_display_precision=1,
|
||||
native_unit_of_measurement=UnitOfFrequency.HERTZ,
|
||||
),
|
||||
EheimDigitalSensorDescription[EheimDigitalFilter](
|
||||
key="service_hours",
|
||||
translation_key="service_hours",
|
||||
value_fn=lambda device: device.service_hours,
|
||||
device_class=SensorDeviceClass.DURATION,
|
||||
native_unit_of_measurement=UnitOfTime.HOURS,
|
||||
suggested_unit_of_measurement=UnitOfTime.DAYS,
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
CLASSICVARIO_DESCRIPTIONS: tuple[
|
||||
EheimDigitalSensorDescription[EheimDigitalClassicVario], ...
|
||||
] = (
|
||||
@@ -54,11 +76,7 @@ CLASSICVARIO_DESCRIPTIONS: tuple[
|
||||
EheimDigitalSensorDescription[EheimDigitalClassicVario](
|
||||
key="error_code",
|
||||
translation_key="error_code",
|
||||
value_fn=(
|
||||
lambda device: device.error_code.name.lower()
|
||||
if device.error_code is not None
|
||||
else None
|
||||
),
|
||||
value_fn=lambda device: device.error_code.name.lower(),
|
||||
device_class=SensorDeviceClass.ENUM,
|
||||
options=[name.lower() for name in FilterErrorCode._member_names_],
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
@@ -80,6 +98,13 @@ async def async_setup_entry(
|
||||
"""Set up the light entities for one or multiple devices."""
|
||||
entities: list[EheimDigitalSensor[Any]] = []
|
||||
for device in device_address.values():
|
||||
if isinstance(device, EheimDigitalFilter):
|
||||
entities += [
|
||||
EheimDigitalSensor[EheimDigitalFilter](
|
||||
coordinator, device, description
|
||||
)
|
||||
for description in FILTER_DESCRIPTIONS
|
||||
]
|
||||
if isinstance(device, EheimDigitalClassicVario):
|
||||
entities += [
|
||||
EheimDigitalSensor[EheimDigitalClassicVario](
|
||||
|
||||
@@ -61,6 +61,12 @@
|
||||
"day_speed": {
|
||||
"name": "Day speed"
|
||||
},
|
||||
"high_pulse_time": {
|
||||
"name": "High pulse duration"
|
||||
},
|
||||
"low_pulse_time": {
|
||||
"name": "Low pulse duration"
|
||||
},
|
||||
"manual_speed": {
|
||||
"name": "Manual speed"
|
||||
},
|
||||
@@ -78,13 +84,32 @@
|
||||
}
|
||||
},
|
||||
"select": {
|
||||
"const_flow_speed": {
|
||||
"name": "Constant flow speed"
|
||||
},
|
||||
"day_speed": {
|
||||
"name": "Day speed"
|
||||
},
|
||||
"filter_mode": {
|
||||
"name": "Filter mode",
|
||||
"state": {
|
||||
"bio": "Bio",
|
||||
"constant_flow": "Constant flow",
|
||||
"manual": "Manual",
|
||||
"pulse": "Pulse"
|
||||
}
|
||||
},
|
||||
"high_pulse_speed": {
|
||||
"name": "High pulse speed"
|
||||
},
|
||||
"low_pulse_speed": {
|
||||
"name": "Low pulse speed"
|
||||
},
|
||||
"manual_speed": {
|
||||
"name": "Manual speed"
|
||||
},
|
||||
"night_speed": {
|
||||
"name": "Night speed"
|
||||
}
|
||||
},
|
||||
"sensor": {
|
||||
@@ -99,8 +124,17 @@
|
||||
"rotor_stuck": "Rotor stuck"
|
||||
}
|
||||
},
|
||||
"operating_time": {
|
||||
"name": "Operating time"
|
||||
},
|
||||
"service_hours": {
|
||||
"name": "Remaining hours until service"
|
||||
},
|
||||
"turn_feeding_time": {
|
||||
"name": "Remaining off time after feeding"
|
||||
},
|
||||
"turn_off_time": {
|
||||
"name": "Remaining off time"
|
||||
}
|
||||
},
|
||||
"time": {
|
||||
|
||||
@@ -4,6 +4,7 @@ from typing import Any, override
|
||||
|
||||
from eheimdigital.classic_vario import EheimDigitalClassicVario
|
||||
from eheimdigital.device import EheimDigitalDevice
|
||||
from eheimdigital.filter import EheimDigitalFilter
|
||||
|
||||
from homeassistant.components.switch import SwitchEntity
|
||||
from homeassistant.core import HomeAssistant
|
||||
@@ -30,8 +31,8 @@ async def async_setup_entry(
|
||||
"""Set up the switch entities for one or multiple devices."""
|
||||
entities: list[SwitchEntity] = []
|
||||
for device in device_address.values():
|
||||
if isinstance(device, EheimDigitalClassicVario):
|
||||
entities.append(EheimDigitalClassicVarioSwitch(coordinator, device)) # noqa: PERF401
|
||||
if isinstance(device, (EheimDigitalClassicVario, EheimDigitalFilter)):
|
||||
entities.append(EheimDigitalFilterSwitch(coordinator, device)) # noqa: PERF401
|
||||
|
||||
async_add_entities(entities)
|
||||
|
||||
@@ -39,10 +40,10 @@ async def async_setup_entry(
|
||||
async_setup_device_entities(coordinator.hub.devices)
|
||||
|
||||
|
||||
class EheimDigitalClassicVarioSwitch(
|
||||
EheimDigitalEntity[EheimDigitalClassicVario], SwitchEntity
|
||||
class EheimDigitalFilterSwitch(
|
||||
EheimDigitalEntity[EheimDigitalClassicVario | EheimDigitalFilter], SwitchEntity
|
||||
):
|
||||
"""Represent an EHEIM Digital classicVARIO switch entity."""
|
||||
"""Represent an EHEIM Digital classicVARIO or filter switch entity."""
|
||||
|
||||
_attr_translation_key = "filter_active"
|
||||
_attr_name = None
|
||||
@@ -50,9 +51,9 @@ class EheimDigitalClassicVarioSwitch(
|
||||
def __init__(
|
||||
self,
|
||||
coordinator: EheimDigitalUpdateCoordinator,
|
||||
device: EheimDigitalClassicVario,
|
||||
device: EheimDigitalClassicVario | EheimDigitalFilter,
|
||||
) -> None:
|
||||
"""Initialize an EHEIM Digital classicVARIO switch entity."""
|
||||
"""Initialize an EHEIM Digital classicVARIO or filter switch entity."""
|
||||
super().__init__(coordinator, device)
|
||||
self._attr_unique_id = device.mac_address
|
||||
self._async_update_attrs()
|
||||
|
||||
@@ -7,6 +7,7 @@ from typing import Any, final, override
|
||||
|
||||
from eheimdigital.classic_vario import EheimDigitalClassicVario
|
||||
from eheimdigital.device import EheimDigitalDevice
|
||||
from eheimdigital.filter import EheimDigitalFilter
|
||||
from eheimdigital.heater import EheimDigitalHeater
|
||||
|
||||
from homeassistant.components.time import TimeEntity, TimeEntityDescription
|
||||
@@ -28,6 +29,23 @@ class EheimDigitalTimeDescription[_DeviceT: EheimDigitalDevice](TimeEntityDescri
|
||||
set_value_fn: Callable[[_DeviceT, time], Awaitable[None]]
|
||||
|
||||
|
||||
FILTER_DESCRIPTIONS: tuple[EheimDigitalTimeDescription[EheimDigitalFilter], ...] = (
|
||||
EheimDigitalTimeDescription[EheimDigitalFilter](
|
||||
key="day_start_time",
|
||||
translation_key="day_start_time",
|
||||
entity_category=EntityCategory.CONFIG,
|
||||
value_fn=lambda device: device.day_start_time,
|
||||
set_value_fn=lambda device, value: device.set_day_start_time(value),
|
||||
),
|
||||
EheimDigitalTimeDescription[EheimDigitalFilter](
|
||||
key="night_start_time",
|
||||
translation_key="night_start_time",
|
||||
entity_category=EntityCategory.CONFIG,
|
||||
value_fn=lambda device: device.night_start_time,
|
||||
set_value_fn=lambda device, value: device.set_night_start_time(value),
|
||||
),
|
||||
)
|
||||
|
||||
CLASSICVARIO_DESCRIPTIONS: tuple[
|
||||
EheimDigitalTimeDescription[EheimDigitalClassicVario], ...
|
||||
] = (
|
||||
@@ -79,6 +97,13 @@ async def async_setup_entry(
|
||||
"""Set up the time entities for one or multiple devices."""
|
||||
entities: list[EheimDigitalTime[Any]] = []
|
||||
for device in device_address.values():
|
||||
if isinstance(device, EheimDigitalFilter):
|
||||
entities.extend(
|
||||
EheimDigitalTime[EheimDigitalFilter](
|
||||
coordinator, device, description
|
||||
)
|
||||
for description in FILTER_DESCRIPTIONS
|
||||
)
|
||||
if isinstance(device, EheimDigitalClassicVario):
|
||||
entities.extend(
|
||||
EheimDigitalTime[EheimDigitalClassicVario](
|
||||
|
||||
@@ -7,5 +7,5 @@
|
||||
"documentation": "https://www.home-assistant.io/integrations/gree",
|
||||
"iot_class": "local_polling",
|
||||
"loggers": ["greeclimate"],
|
||||
"requirements": ["greeclimate==2.1.0"]
|
||||
"requirements": ["greeclimate==2.1.1"]
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ from aiohasupervisor.models import GreenOptions, YellowOptions # noqa: F401
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.auth.const import GROUP_ID_ADMIN
|
||||
from homeassistant.components import network, panel_custom
|
||||
from homeassistant.components import panel_custom
|
||||
from homeassistant.components.homeassistant import async_set_stop_handler
|
||||
from homeassistant.components.http import StaticPathConfig
|
||||
from homeassistant.config_entries import SOURCE_SYSTEM, ConfigEntry
|
||||
@@ -41,7 +41,6 @@ from homeassistant.helpers import (
|
||||
issue_registry as ir,
|
||||
)
|
||||
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
||||
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
||||
from homeassistant.helpers.event import async_call_later
|
||||
from homeassistant.helpers.issue_registry import IssueSeverity
|
||||
from homeassistant.helpers.typing import ConfigType
|
||||
@@ -79,7 +78,6 @@ from .const import (
|
||||
ATTR_LOCATION,
|
||||
ATTR_PASSWORD,
|
||||
ATTR_SLUG,
|
||||
ATTR_WS_EVENT,
|
||||
DATA_COMPONENT,
|
||||
DATA_CONFIG_STORE,
|
||||
DATA_CORE_INFO,
|
||||
@@ -91,8 +89,6 @@ from .const import (
|
||||
DATA_STORE,
|
||||
DATA_SUPERVISOR_INFO,
|
||||
DOMAIN,
|
||||
EVENT_NETWORK_CHANGED,
|
||||
EVENT_SUPERVISOR_EVENT,
|
||||
HASSIO_UPDATE_INTERVAL,
|
||||
)
|
||||
from .coordinator import (
|
||||
@@ -384,16 +380,6 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: # noqa:
|
||||
hass.data[DATA_KEY_SUPERVISOR_ISSUES] = issues = SupervisorIssues(hass, hassio)
|
||||
issues_task = hass.async_create_task(issues.setup(), eager_start=True)
|
||||
|
||||
@callback
|
||||
def _async_handle_supervisor_events(event: dict[str, Any]) -> None:
|
||||
"""Handle supervisor events for network changes."""
|
||||
if event.get(ATTR_WS_EVENT) == EVENT_NETWORK_CHANGED:
|
||||
hass.async_create_task(network.async_notify_network_change(hass))
|
||||
|
||||
async_dispatcher_connect(
|
||||
hass, EVENT_SUPERVISOR_EVENT, _async_handle_supervisor_events
|
||||
)
|
||||
|
||||
async def async_service_handler(service: ServiceCall) -> None:
|
||||
"""Handle service calls for Hass.io."""
|
||||
api_endpoint = MAP_SERVICE_API[service.service]
|
||||
|
||||
@@ -70,7 +70,6 @@ EVENT_HEALTH_CHANGED = "health_changed"
|
||||
EVENT_SUPPORTED_CHANGED = "supported_changed"
|
||||
EVENT_ISSUE_CHANGED = "issue_changed"
|
||||
EVENT_ISSUE_REMOVED = "issue_removed"
|
||||
EVENT_NETWORK_CHANGED = "network_changed"
|
||||
EVENT_JOB = "job"
|
||||
|
||||
UPDATE_KEY_SUPERVISOR = "supervisor"
|
||||
|
||||
@@ -8,5 +8,5 @@
|
||||
"iot_class": "local_push",
|
||||
"loggers": ["pyhik"],
|
||||
"quality_scale": "legacy",
|
||||
"requirements": ["pyHik==0.3.4"]
|
||||
"requirements": ["pyHik==0.4.0"]
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"domain": "namecheapdns",
|
||||
"name": "Namecheap FreeDNS",
|
||||
"name": "Namecheap DynamicDNS",
|
||||
"codeowners": [],
|
||||
"documentation": "https://www.home-assistant.io/integrations/namecheapdns",
|
||||
"iot_class": "cloud_push",
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from collections.abc import Callable
|
||||
from ipaddress import IPv4Address, IPv6Address, ip_interface
|
||||
import logging
|
||||
from pathlib import Path
|
||||
@@ -23,12 +22,7 @@ from .const import (
|
||||
PUBLIC_TARGET_IP,
|
||||
)
|
||||
from .models import Adapter
|
||||
from .network import (
|
||||
Network,
|
||||
NetworkChangeCallback,
|
||||
async_get_loaded_network,
|
||||
async_get_network,
|
||||
)
|
||||
from .network import Network, async_get_loaded_network, async_get_network
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
@@ -178,32 +172,6 @@ async def async_get_announce_addresses(hass: HomeAssistant) -> list[str]:
|
||||
return list(addresses)
|
||||
|
||||
|
||||
@callback
|
||||
def async_register_network_change_callback(
|
||||
hass: HomeAssistant, callback_fn: NetworkChangeCallback
|
||||
) -> Callable[[], None]:
|
||||
"""Register a callback to be called when network adapters change.
|
||||
|
||||
Returns a function to unregister the callback.
|
||||
|
||||
The callback will be called with the new list of adapters when
|
||||
a network change is detected.
|
||||
"""
|
||||
network: Network = async_get_loaded_network(hass)
|
||||
return network.async_register_change_callback(callback_fn)
|
||||
|
||||
|
||||
async def async_notify_network_change(hass: HomeAssistant) -> None:
|
||||
"""Notify the network integration of a network change.
|
||||
|
||||
This will reload network adapters and notify all registered callbacks.
|
||||
This should be called when external systems (like the supervisor) detect
|
||||
a network change.
|
||||
"""
|
||||
network: Network = await async_get_network(hass)
|
||||
await network.async_notify_network_change()
|
||||
|
||||
|
||||
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
|
||||
"""Set up network for Home Assistant."""
|
||||
# Avoid circular issue: http->network->websocket_api->http
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from collections.abc import Callable
|
||||
import logging
|
||||
from typing import Any
|
||||
|
||||
@@ -24,8 +23,6 @@ from .util import async_load_adapters, enable_adapters, enable_auto_detected_ada
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
type NetworkChangeCallback = Callable[[list[Adapter]], None]
|
||||
|
||||
DATA_NETWORK: HassKey[Network] = HassKey(DOMAIN)
|
||||
|
||||
|
||||
@@ -51,13 +48,11 @@ class Network:
|
||||
|
||||
def __init__(self, hass: HomeAssistant) -> None:
|
||||
"""Initialize the Network class."""
|
||||
self._hass = hass
|
||||
self._store = Store[dict[str, list[str]]](
|
||||
hass, STORAGE_VERSION, STORAGE_KEY, atomic_writes=True
|
||||
)
|
||||
self._data: dict[str, list[str]] = {}
|
||||
self.adapters: list[Adapter] = []
|
||||
self._change_callbacks: list[NetworkChangeCallback] = []
|
||||
|
||||
@property
|
||||
def configured_adapters(self) -> list[str]:
|
||||
@@ -90,34 +85,3 @@ class Network:
|
||||
async def _async_save(self) -> None:
|
||||
"""Save preferences."""
|
||||
await self._store.async_save(self._data)
|
||||
|
||||
@callback
|
||||
def async_register_change_callback(
|
||||
self, callback_fn: NetworkChangeCallback
|
||||
) -> Callable[[], None]:
|
||||
"""Register a callback to be called when network adapters change.
|
||||
|
||||
Returns a function to unregister the callback.
|
||||
"""
|
||||
self._change_callbacks.append(callback_fn)
|
||||
|
||||
@callback
|
||||
def unregister() -> None:
|
||||
"""Unregister the callback."""
|
||||
self._change_callbacks.remove(callback_fn)
|
||||
|
||||
return unregister
|
||||
|
||||
async def async_notify_network_change(self) -> None:
|
||||
"""Notify listeners of a network change.
|
||||
|
||||
This reloads network adapters and calls all registered callbacks.
|
||||
"""
|
||||
old_adapters = self.adapters
|
||||
self.adapters = await async_load_adapters()
|
||||
self.async_configure()
|
||||
|
||||
if old_adapters != self.adapters:
|
||||
_LOGGER.info("Network adapters changed: %s", self.adapters)
|
||||
for callback_fn in self._change_callbacks:
|
||||
callback_fn(self.adapters)
|
||||
|
||||
@@ -50,7 +50,6 @@ rules:
|
||||
Use load_json_object_fixture in tests
|
||||
Patch the library instead of the HTTP requests
|
||||
Create a shared fixture for the mock config entry
|
||||
Use snapshots for binary sensor tests
|
||||
Use init_integration in tests
|
||||
Evaluate the need of test_config_entry_not_ready
|
||||
|
||||
|
||||
@@ -8,5 +8,5 @@
|
||||
"iot_class": "cloud_polling",
|
||||
"loggers": ["pynintendoauth", "pynintendoparental"],
|
||||
"quality_scale": "bronze",
|
||||
"requirements": ["pynintendoauth==1.0.2", "pynintendoparental==2.3.0"]
|
||||
"requirements": ["pynintendoauth==1.0.2", "pynintendoparental==2.3.2"]
|
||||
}
|
||||
|
||||
@@ -128,15 +128,15 @@ class AtlanticElectricalHeaterWithAdjustableTemperatureSetpoint(
|
||||
|
||||
states = self.device.states
|
||||
|
||||
if (
|
||||
operating_mode := states[OverkizState.CORE_OPERATING_MODE]
|
||||
) and operating_mode.value_as_str == OverkizCommandParam.EXTERNAL:
|
||||
return PRESET_EXTERNAL
|
||||
|
||||
if (
|
||||
state := states[OverkizState.IO_TARGET_HEATING_LEVEL]
|
||||
) and state.value_as_str:
|
||||
return OVERKIZ_TO_PRESET_MODE[state.value_as_str]
|
||||
|
||||
if (
|
||||
operating_mode := states[OverkizState.CORE_OPERATING_MODE]
|
||||
) and operating_mode.value_as_str == OverkizCommandParam.EXTERNAL:
|
||||
return PRESET_EXTERNAL
|
||||
return None
|
||||
|
||||
async def async_set_preset_mode(self, preset_mode: str) -> None:
|
||||
|
||||
@@ -151,6 +151,12 @@ SENSOR_DESCRIPTIONS = {
|
||||
translation_key="nox_index",
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
"iaqs": SensorEntityDescription(
|
||||
key="iaqs",
|
||||
translation_key="iaqs",
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
entity_registry_enabled_default=False,
|
||||
),
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -33,6 +33,9 @@
|
||||
"acceleration_z": {
|
||||
"name": "Acceleration Z"
|
||||
},
|
||||
"iaqs": {
|
||||
"name": "Indoor air quality score"
|
||||
},
|
||||
"movement_counter": {
|
||||
"name": "Movement counter"
|
||||
},
|
||||
|
||||
@@ -13,5 +13,5 @@
|
||||
"integration_type": "hub",
|
||||
"iot_class": "cloud_polling",
|
||||
"loggers": ["switchbot_api"],
|
||||
"requirements": ["switchbot-api==2.9.0"]
|
||||
"requirements": ["switchbot-api==2.10.0"]
|
||||
}
|
||||
|
||||
@@ -24,13 +24,13 @@ async def async_setup_platform(
|
||||
return pollbot
|
||||
|
||||
|
||||
async def process_error(update: object, context: CallbackContext) -> None:
|
||||
async def process_error(bot: Bot, update: object, context: CallbackContext) -> None:
|
||||
"""Telegram bot error handler."""
|
||||
if context.error:
|
||||
error_callback(context.error, update)
|
||||
error_callback(bot, context.error, update)
|
||||
|
||||
|
||||
def error_callback(error: Exception, update: object | None = None) -> None:
|
||||
def error_callback(bot: Bot, error: Exception, update: object | None = None) -> None:
|
||||
"""Log the error."""
|
||||
try:
|
||||
raise error
|
||||
@@ -39,9 +39,17 @@ def error_callback(error: Exception, update: object | None = None) -> None:
|
||||
pass
|
||||
except TelegramError:
|
||||
if update is not None:
|
||||
_LOGGER.error('Update "%s" caused error: "%s"', update, error)
|
||||
_LOGGER.error(
|
||||
'[%s %s] Update "%s" caused error: "%s"',
|
||||
bot.username,
|
||||
bot.id,
|
||||
update,
|
||||
error,
|
||||
)
|
||||
else:
|
||||
_LOGGER.error("%s: %s", error.__class__.__name__, error)
|
||||
_LOGGER.error(
|
||||
"[%s %s] %s: %s", bot.username, bot.id, error.__class__.__name__, error
|
||||
)
|
||||
|
||||
|
||||
class PollBot(BaseTelegramBot):
|
||||
@@ -58,7 +66,9 @@ class PollBot(BaseTelegramBot):
|
||||
self.bot = bot
|
||||
self.application = ApplicationBuilder().bot(self.bot).build()
|
||||
self.application.add_handler(TypeHandler(Update, self.handle_update))
|
||||
self.application.add_error_handler(process_error)
|
||||
self.application.add_error_handler(
|
||||
lambda update, context: process_error(self.bot, update, context)
|
||||
)
|
||||
|
||||
async def shutdown(self) -> None:
|
||||
"""Shutdown the app."""
|
||||
@@ -66,16 +76,18 @@ class PollBot(BaseTelegramBot):
|
||||
|
||||
async def start_polling(self) -> None:
|
||||
"""Start the polling task."""
|
||||
_LOGGER.debug("Starting polling")
|
||||
await self.application.initialize()
|
||||
if self.application.updater:
|
||||
await self.application.updater.start_polling(error_callback=error_callback)
|
||||
await self.application.updater.start_polling(
|
||||
error_callback=lambda error: error_callback(self.bot, error, None)
|
||||
)
|
||||
await self.application.start()
|
||||
_LOGGER.info("[%s %s] Started polling", self.bot.username, self.bot.id)
|
||||
|
||||
async def stop_polling(self) -> None:
|
||||
"""Stop the polling task."""
|
||||
_LOGGER.debug("Stopping polling")
|
||||
if self.application.updater:
|
||||
await self.application.updater.stop()
|
||||
await self.application.stop()
|
||||
await self.application.shutdown()
|
||||
_LOGGER.info("[%s %s] Stopped polling", self.bot.username, self.bot.id)
|
||||
|
||||
@@ -8,7 +8,7 @@ start:
|
||||
duration:
|
||||
example: "00:01:00 or 60"
|
||||
selector:
|
||||
text:
|
||||
duration:
|
||||
|
||||
pause:
|
||||
target:
|
||||
|
||||
@@ -654,6 +654,7 @@ DISCOVERY_SCHEMAS: list[NewZWaveDiscoverySchema] = [
|
||||
key=NOTIFICATION_SMOKE_ALARM,
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
not_states={
|
||||
0,
|
||||
SmokeAlarmNotificationEvent.SENSOR_STATUS_SMOKE_DETECTED_LOCATION_PROVIDED,
|
||||
SmokeAlarmNotificationEvent.SENSOR_STATUS_SMOKE_DETECTED,
|
||||
SmokeAlarmNotificationEvent.MAINTENANCE_STATUS_REPLACEMENT_REQUIRED,
|
||||
|
||||
@@ -4342,7 +4342,7 @@
|
||||
"iot_class": "local_polling"
|
||||
},
|
||||
"namecheapdns": {
|
||||
"name": "Namecheap FreeDNS",
|
||||
"name": "Namecheap DynamicDNS",
|
||||
"integration_type": "hub",
|
||||
"config_flow": false,
|
||||
"iot_class": "cloud_push"
|
||||
|
||||
@@ -56,7 +56,7 @@ PyJWT==2.10.1
|
||||
PyNaCl==1.6.0
|
||||
pyOpenSSL==25.3.0
|
||||
pyserial==3.5
|
||||
pysilero-vad==3.1.0
|
||||
pysilero-vad==3.2.0
|
||||
pyspeex-noise==1.0.2
|
||||
python-slugify==8.0.4
|
||||
PyTurboJPEG==1.8.0
|
||||
|
||||
2
requirements.txt
generated
2
requirements.txt
generated
@@ -40,7 +40,7 @@ propcache==0.4.1
|
||||
psutil-home-assistant==0.0.1
|
||||
PyJWT==2.10.1
|
||||
pyOpenSSL==25.3.0
|
||||
pysilero-vad==3.1.0
|
||||
pysilero-vad==3.2.0
|
||||
pyspeex-noise==1.0.2
|
||||
python-slugify==8.0.4
|
||||
PyTurboJPEG==1.8.0
|
||||
|
||||
16
requirements_all.txt
generated
16
requirements_all.txt
generated
@@ -187,7 +187,7 @@ aioairq==0.4.7
|
||||
aioairzone-cloud==0.7.2
|
||||
|
||||
# homeassistant.components.airzone
|
||||
aioairzone==1.0.4
|
||||
aioairzone==1.0.5
|
||||
|
||||
# homeassistant.components.alexa_devices
|
||||
aioamazondevices==11.0.2
|
||||
@@ -703,7 +703,7 @@ brottsplatskartan==1.0.5
|
||||
brunt==1.2.0
|
||||
|
||||
# homeassistant.components.bthome
|
||||
bthome-ble==3.17.0
|
||||
bthome-ble==3.16.0
|
||||
|
||||
# homeassistant.components.bt_home_hub_5
|
||||
bthomehub5-devicelist==0.1.1
|
||||
@@ -842,7 +842,7 @@ dynalite-panel==0.0.4
|
||||
eagle100==0.1.1
|
||||
|
||||
# homeassistant.components.easyenergy
|
||||
easyenergy==2.1.2
|
||||
easyenergy==2.2.0
|
||||
|
||||
# homeassistant.components.ebusd
|
||||
ebusdpy==0.0.17
|
||||
@@ -1127,7 +1127,7 @@ gpiozero==1.6.2
|
||||
gps3==0.33.3
|
||||
|
||||
# homeassistant.components.gree
|
||||
greeclimate==2.1.0
|
||||
greeclimate==2.1.1
|
||||
|
||||
# homeassistant.components.greeneye_monitor
|
||||
greeneye_monitor==3.0.3
|
||||
@@ -1855,7 +1855,7 @@ pyElectra==1.2.4
|
||||
pyEmby==1.10
|
||||
|
||||
# homeassistant.components.hikvision
|
||||
pyHik==0.3.4
|
||||
pyHik==0.4.0
|
||||
|
||||
# homeassistant.components.homee
|
||||
pyHomee==1.3.8
|
||||
@@ -2238,7 +2238,7 @@ pynina==0.3.6
|
||||
pynintendoauth==1.0.2
|
||||
|
||||
# homeassistant.components.nintendo_parental_controls
|
||||
pynintendoparental==2.3.0
|
||||
pynintendoparental==2.3.2
|
||||
|
||||
# homeassistant.components.nobo_hub
|
||||
pynobo==1.8.1
|
||||
@@ -2409,7 +2409,7 @@ pysiaalarm==3.1.1
|
||||
pysignalclirestapi==0.3.24
|
||||
|
||||
# homeassistant.components.assist_pipeline
|
||||
pysilero-vad==3.1.0
|
||||
pysilero-vad==3.2.0
|
||||
|
||||
# homeassistant.components.sky_hub
|
||||
pyskyqhub==0.1.4
|
||||
@@ -2956,7 +2956,7 @@ surepy==0.9.0
|
||||
swisshydrodata==0.1.0
|
||||
|
||||
# homeassistant.components.switchbot_cloud
|
||||
switchbot-api==2.9.0
|
||||
switchbot-api==2.10.0
|
||||
|
||||
# homeassistant.components.synology_srm
|
||||
synology-srm==0.2.0
|
||||
|
||||
16
requirements_test_all.txt
generated
16
requirements_test_all.txt
generated
@@ -178,7 +178,7 @@ aioairq==0.4.7
|
||||
aioairzone-cloud==0.7.2
|
||||
|
||||
# homeassistant.components.airzone
|
||||
aioairzone==1.0.4
|
||||
aioairzone==1.0.5
|
||||
|
||||
# homeassistant.components.alexa_devices
|
||||
aioamazondevices==11.0.2
|
||||
@@ -633,7 +633,7 @@ brottsplatskartan==1.0.5
|
||||
brunt==1.2.0
|
||||
|
||||
# homeassistant.components.bthome
|
||||
bthome-ble==3.17.0
|
||||
bthome-ble==3.16.0
|
||||
|
||||
# homeassistant.components.buienradar
|
||||
buienradar==1.0.6
|
||||
@@ -748,7 +748,7 @@ dynalite-panel==0.0.4
|
||||
eagle100==0.1.1
|
||||
|
||||
# homeassistant.components.easyenergy
|
||||
easyenergy==2.1.2
|
||||
easyenergy==2.2.0
|
||||
|
||||
# homeassistant.components.egauge
|
||||
egauge-async==0.4.0
|
||||
@@ -1000,7 +1000,7 @@ govee-local-api==2.3.0
|
||||
gps3==0.33.3
|
||||
|
||||
# homeassistant.components.gree
|
||||
greeclimate==2.1.0
|
||||
greeclimate==2.1.1
|
||||
|
||||
# homeassistant.components.greeneye_monitor
|
||||
greeneye_monitor==3.0.3
|
||||
@@ -1589,7 +1589,7 @@ pyDuotecno==2024.10.1
|
||||
pyElectra==1.2.4
|
||||
|
||||
# homeassistant.components.hikvision
|
||||
pyHik==0.3.4
|
||||
pyHik==0.4.0
|
||||
|
||||
# homeassistant.components.homee
|
||||
pyHomee==1.3.8
|
||||
@@ -1891,7 +1891,7 @@ pynina==0.3.6
|
||||
pynintendoauth==1.0.2
|
||||
|
||||
# homeassistant.components.nintendo_parental_controls
|
||||
pynintendoparental==2.3.0
|
||||
pynintendoparental==2.3.2
|
||||
|
||||
# homeassistant.components.nobo_hub
|
||||
pynobo==1.8.1
|
||||
@@ -2035,7 +2035,7 @@ pysiaalarm==3.1.1
|
||||
pysignalclirestapi==0.3.24
|
||||
|
||||
# homeassistant.components.assist_pipeline
|
||||
pysilero-vad==3.1.0
|
||||
pysilero-vad==3.2.0
|
||||
|
||||
# homeassistant.components.sma
|
||||
pysma==1.1.0
|
||||
@@ -2477,7 +2477,7 @@ subarulink==0.7.15
|
||||
surepy==0.9.0
|
||||
|
||||
# homeassistant.components.switchbot_cloud
|
||||
switchbot-api==2.9.0
|
||||
switchbot-api==2.10.0
|
||||
|
||||
# homeassistant.components.system_bridge
|
||||
systembridgeconnector==5.3.1
|
||||
|
||||
@@ -1,4 +1,52 @@
|
||||
# serializer version: 1
|
||||
# name: test_buttons[button.test_thermostat_recalibrate_co2_sensor-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
'area_id': None,
|
||||
'capabilities': None,
|
||||
'config_entry_id': <ANY>,
|
||||
'config_subentry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'button',
|
||||
'entity_category': <EntityCategory.CONFIG: 'config'>,
|
||||
'entity_id': 'button.test_thermostat_recalibrate_co2_sensor',
|
||||
'has_entity_name': True,
|
||||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
'original_device_class': None,
|
||||
'original_icon': None,
|
||||
'original_name': 'Recalibrate CO2 sensor',
|
||||
'platform': 'airobot',
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'recalibrate_co2',
|
||||
'unique_id': 'T01A1B2C3_recalibrate_co2',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
# name: test_buttons[button.test_thermostat_recalibrate_co2_sensor-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'friendly_name': 'Test Thermostat Recalibrate CO2 sensor',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'button.test_thermostat_recalibrate_co2_sensor',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'unknown',
|
||||
})
|
||||
# ---
|
||||
# name: test_buttons[button.test_thermostat_restart-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
|
||||
@@ -25,7 +25,7 @@ def platforms() -> list[Platform]:
|
||||
return [Platform.BUTTON]
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("init_integration")
|
||||
@pytest.mark.usefixtures("entity_registry_enabled_by_default", "init_integration")
|
||||
async def test_buttons(
|
||||
hass: HomeAssistant,
|
||||
snapshot: SnapshotAssertion,
|
||||
@@ -93,3 +93,38 @@ async def test_restart_button_connection_errors(
|
||||
)
|
||||
|
||||
mock_airobot_client.reboot_thermostat.assert_called_once()
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("entity_registry_enabled_by_default", "init_integration")
|
||||
async def test_recalibrate_co2_button(
|
||||
hass: HomeAssistant,
|
||||
mock_airobot_client: AsyncMock,
|
||||
) -> None:
|
||||
"""Test recalibrate CO2 sensor button."""
|
||||
await hass.services.async_call(
|
||||
BUTTON_DOMAIN,
|
||||
SERVICE_PRESS,
|
||||
{ATTR_ENTITY_ID: "button.test_thermostat_recalibrate_co2_sensor"},
|
||||
blocking=True,
|
||||
)
|
||||
|
||||
mock_airobot_client.recalibrate_co2_sensor.assert_called_once()
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("entity_registry_enabled_by_default", "init_integration")
|
||||
async def test_recalibrate_co2_button_error(
|
||||
hass: HomeAssistant,
|
||||
mock_airobot_client: AsyncMock,
|
||||
) -> None:
|
||||
"""Test recalibrate CO2 sensor button error handling."""
|
||||
mock_airobot_client.recalibrate_co2_sensor.side_effect = AirobotError("Test error")
|
||||
|
||||
with pytest.raises(HomeAssistantError):
|
||||
await hass.services.async_call(
|
||||
BUTTON_DOMAIN,
|
||||
SERVICE_PRESS,
|
||||
{ATTR_ENTITY_ID: "button.test_thermostat_recalibrate_co2_sensor"},
|
||||
blocking=True,
|
||||
)
|
||||
|
||||
mock_airobot_client.recalibrate_co2_sensor.assert_called_once()
|
||||
|
||||
@@ -5,6 +5,7 @@ from unittest.mock import AsyncMock, MagicMock, patch
|
||||
|
||||
from eheimdigital.classic_led_ctrl import EheimDigitalClassicLEDControl
|
||||
from eheimdigital.classic_vario import EheimDigitalClassicVario
|
||||
from eheimdigital.filter import EheimDigitalFilter
|
||||
from eheimdigital.heater import EheimDigitalHeater
|
||||
from eheimdigital.hub import EheimDigitalHub
|
||||
from eheimdigital.types import (
|
||||
@@ -13,6 +14,7 @@ from eheimdigital.types import (
|
||||
ClassicVarioDataPacket,
|
||||
ClockPacket,
|
||||
CloudPacket,
|
||||
FilterDataPacket,
|
||||
MoonPacket,
|
||||
UsrDtaPacket,
|
||||
)
|
||||
@@ -82,11 +84,25 @@ def classic_vario_mock():
|
||||
return classic_vario
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def filter_mock():
|
||||
"""Mock a filter device."""
|
||||
eheim_filter = EheimDigitalFilter(
|
||||
MagicMock(spec=EheimDigitalHub),
|
||||
UsrDtaPacket(load_json_object_fixture("filter/usrdta.json", DOMAIN)),
|
||||
)
|
||||
eheim_filter.filter_data = FilterDataPacket(
|
||||
load_json_object_fixture("filter/filter_data.json", DOMAIN)
|
||||
)
|
||||
return eheim_filter
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def eheimdigital_hub_mock(
|
||||
classic_led_ctrl_mock: MagicMock,
|
||||
heater_mock: MagicMock,
|
||||
classic_vario_mock: MagicMock,
|
||||
filter_mock: MagicMock,
|
||||
) -> Generator[AsyncMock]:
|
||||
"""Mock eheimdigital hub."""
|
||||
with (
|
||||
@@ -103,6 +119,7 @@ def eheimdigital_hub_mock(
|
||||
"00:00:00:00:00:01": classic_led_ctrl_mock,
|
||||
"00:00:00:00:00:02": heater_mock,
|
||||
"00:00:00:00:00:03": classic_vario_mock,
|
||||
"00:00:00:00:00:04": filter_mock,
|
||||
}
|
||||
eheimdigital_hub_mock.return_value.main = classic_led_ctrl_mock
|
||||
yield eheimdigital_hub_mock
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
{
|
||||
"title": "FILTER_DATA",
|
||||
"from": "00:00:00:00:00:04",
|
||||
"minFreq": 3500,
|
||||
"maxFreq": 6700,
|
||||
"maxFreqRglOff": 7200,
|
||||
"freq": 7200,
|
||||
"freqSoll": 7200,
|
||||
"dfs": 0,
|
||||
"dfsFaktor": 0,
|
||||
"sollStep": 14,
|
||||
"rotSpeed": 43,
|
||||
"pumpMode": 16,
|
||||
"sync": "",
|
||||
"partnerName": "",
|
||||
"filterActive": 1,
|
||||
"runTime": 106435,
|
||||
"actualTime": 106435,
|
||||
"serviceHour": 36774,
|
||||
"pm_dfs_soll_high": 10,
|
||||
"pm_dfs_soll_low": 1,
|
||||
"pm_time_high": 10,
|
||||
"pm_time_low": 10,
|
||||
"nm_dfs_soll_day": 10,
|
||||
"nm_dfs_soll_night": 4,
|
||||
"end_time_night_mode": 420,
|
||||
"start_time_night_mode": 1140,
|
||||
"version": 74,
|
||||
"isEheim": 1,
|
||||
"turnOffTime": 0,
|
||||
"turnTimeFeeding": 0
|
||||
}
|
||||
34
tests/components/eheimdigital/fixtures/filter/usrdta.json
Normal file
34
tests/components/eheimdigital/fixtures/filter/usrdta.json
Normal file
@@ -0,0 +1,34 @@
|
||||
{
|
||||
"title": "USRDTA",
|
||||
"from": "00:00:00:00:00:04",
|
||||
"name": "Mock filter",
|
||||
"aqName": "Mock Aquarium",
|
||||
"version": 4,
|
||||
"language": "DE",
|
||||
"timezone": 60,
|
||||
"tID": 30,
|
||||
"dst": 1,
|
||||
"tankconfig": "WITHOUT_THERMO",
|
||||
"power": "",
|
||||
"netmode": "ST",
|
||||
"host": "eheimdigital",
|
||||
"groupID": 0,
|
||||
"meshing": 1,
|
||||
"firstStart": 0,
|
||||
"remote": 0,
|
||||
"revision": [1026, 1030],
|
||||
"build": ["1752053563000", "1752045985672"],
|
||||
"latestAvailableRevision": [1026, 1030, 2038, 2038],
|
||||
"firmwareAvailable": 0,
|
||||
"emailAddr": "",
|
||||
"stMail": 0,
|
||||
"stMailMode": 0,
|
||||
"fstTime": 720,
|
||||
"sstTime": 0,
|
||||
"liveTime": 103680,
|
||||
"usrName": "",
|
||||
"unit": 0,
|
||||
"demoUse": 0,
|
||||
"sysLED": 45,
|
||||
"to": "USER"
|
||||
}
|
||||
@@ -236,6 +236,85 @@
|
||||
'version': 18,
|
||||
}),
|
||||
}),
|
||||
'00:00:00:00:00:04': dict({
|
||||
'filter_data': dict({
|
||||
'actualTime': 106435,
|
||||
'dfs': 0,
|
||||
'dfsFaktor': 0,
|
||||
'end_time_night_mode': 420,
|
||||
'filterActive': 1,
|
||||
'freq': 7200,
|
||||
'freqSoll': 7200,
|
||||
'from': '00:00:00:00:00:04',
|
||||
'isEheim': 1,
|
||||
'maxFreq': 6700,
|
||||
'maxFreqRglOff': 7200,
|
||||
'minFreq': 3500,
|
||||
'nm_dfs_soll_day': 10,
|
||||
'nm_dfs_soll_night': 4,
|
||||
'partnerName': '',
|
||||
'pm_dfs_soll_high': 10,
|
||||
'pm_dfs_soll_low': 1,
|
||||
'pm_time_high': 10,
|
||||
'pm_time_low': 10,
|
||||
'pumpMode': 16,
|
||||
'rotSpeed': 43,
|
||||
'runTime': 106435,
|
||||
'serviceHour': 36774,
|
||||
'sollStep': 14,
|
||||
'start_time_night_mode': 1140,
|
||||
'sync': '',
|
||||
'title': 'FILTER_DATA',
|
||||
'turnOffTime': 0,
|
||||
'turnTimeFeeding': 0,
|
||||
'version': 74,
|
||||
}),
|
||||
'usrdta': dict({
|
||||
'aqName': 'Mock Aquarium',
|
||||
'build': list([
|
||||
'1752053563000',
|
||||
'1752045985672',
|
||||
]),
|
||||
'demoUse': 0,
|
||||
'dst': 1,
|
||||
'emailAddr': '',
|
||||
'firmwareAvailable': 0,
|
||||
'firstStart': 0,
|
||||
'from': '00:00:00:00:00:04',
|
||||
'fstTime': 720,
|
||||
'groupID': 0,
|
||||
'host': 'eheimdigital',
|
||||
'language': 'DE',
|
||||
'latestAvailableRevision': list([
|
||||
1026,
|
||||
1030,
|
||||
2038,
|
||||
2038,
|
||||
]),
|
||||
'liveTime': 103680,
|
||||
'meshing': 1,
|
||||
'name': 'Mock filter',
|
||||
'netmode': 'ST',
|
||||
'power': '',
|
||||
'remote': 0,
|
||||
'revision': list([
|
||||
1026,
|
||||
1030,
|
||||
]),
|
||||
'sstTime': 0,
|
||||
'stMail': 0,
|
||||
'stMailMode': 0,
|
||||
'sysLED': 45,
|
||||
'tID': 30,
|
||||
'tankconfig': 'WITHOUT_THERMO',
|
||||
'timezone': 60,
|
||||
'title': 'USRDTA',
|
||||
'to': 'USER',
|
||||
'unit': 0,
|
||||
'usrName': '',
|
||||
'version': 4,
|
||||
}),
|
||||
}),
|
||||
}),
|
||||
'entry': dict({
|
||||
'data': dict({
|
||||
|
||||
@@ -289,6 +289,182 @@
|
||||
'state': 'unknown',
|
||||
})
|
||||
# ---
|
||||
# name: test_setup[number.mock_filter_high_pulse_duration-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
'area_id': None,
|
||||
'capabilities': dict({
|
||||
'max': 200000,
|
||||
'min': 5,
|
||||
'mode': <NumberMode.AUTO: 'auto'>,
|
||||
'step': 1,
|
||||
}),
|
||||
'config_entry_id': <ANY>,
|
||||
'config_subentry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'number',
|
||||
'entity_category': <EntityCategory.CONFIG: 'config'>,
|
||||
'entity_id': 'number.mock_filter_high_pulse_duration',
|
||||
'has_entity_name': True,
|
||||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
'original_device_class': <NumberDeviceClass.DURATION: 'duration'>,
|
||||
'original_icon': None,
|
||||
'original_name': 'High pulse duration',
|
||||
'platform': 'eheimdigital',
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'high_pulse_time',
|
||||
'unique_id': '00:00:00:00:00:04_high_pulse_time',
|
||||
'unit_of_measurement': <UnitOfTime.SECONDS: 's'>,
|
||||
})
|
||||
# ---
|
||||
# name: test_setup[number.mock_filter_high_pulse_duration-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'device_class': 'duration',
|
||||
'friendly_name': 'Mock filter High pulse duration',
|
||||
'max': 200000,
|
||||
'min': 5,
|
||||
'mode': <NumberMode.AUTO: 'auto'>,
|
||||
'step': 1,
|
||||
'unit_of_measurement': <UnitOfTime.SECONDS: 's'>,
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'number.mock_filter_high_pulse_duration',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'unknown',
|
||||
})
|
||||
# ---
|
||||
# name: test_setup[number.mock_filter_low_pulse_duration-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
'area_id': None,
|
||||
'capabilities': dict({
|
||||
'max': 200000,
|
||||
'min': 5,
|
||||
'mode': <NumberMode.AUTO: 'auto'>,
|
||||
'step': 1,
|
||||
}),
|
||||
'config_entry_id': <ANY>,
|
||||
'config_subentry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'number',
|
||||
'entity_category': <EntityCategory.CONFIG: 'config'>,
|
||||
'entity_id': 'number.mock_filter_low_pulse_duration',
|
||||
'has_entity_name': True,
|
||||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
'original_device_class': <NumberDeviceClass.DURATION: 'duration'>,
|
||||
'original_icon': None,
|
||||
'original_name': 'Low pulse duration',
|
||||
'platform': 'eheimdigital',
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'low_pulse_time',
|
||||
'unique_id': '00:00:00:00:00:04_low_pulse_time',
|
||||
'unit_of_measurement': <UnitOfTime.SECONDS: 's'>,
|
||||
})
|
||||
# ---
|
||||
# name: test_setup[number.mock_filter_low_pulse_duration-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'device_class': 'duration',
|
||||
'friendly_name': 'Mock filter Low pulse duration',
|
||||
'max': 200000,
|
||||
'min': 5,
|
||||
'mode': <NumberMode.AUTO: 'auto'>,
|
||||
'step': 1,
|
||||
'unit_of_measurement': <UnitOfTime.SECONDS: 's'>,
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'number.mock_filter_low_pulse_duration',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'unknown',
|
||||
})
|
||||
# ---
|
||||
# name: test_setup[number.mock_filter_system_led_brightness-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
'area_id': None,
|
||||
'capabilities': dict({
|
||||
'max': 100,
|
||||
'min': 0,
|
||||
'mode': <NumberMode.AUTO: 'auto'>,
|
||||
'step': 1,
|
||||
}),
|
||||
'config_entry_id': <ANY>,
|
||||
'config_subentry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'number',
|
||||
'entity_category': <EntityCategory.CONFIG: 'config'>,
|
||||
'entity_id': 'number.mock_filter_system_led_brightness',
|
||||
'has_entity_name': True,
|
||||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
'original_device_class': None,
|
||||
'original_icon': None,
|
||||
'original_name': 'System LED brightness',
|
||||
'platform': 'eheimdigital',
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'system_led',
|
||||
'unique_id': '00:00:00:00:00:04_system_led',
|
||||
'unit_of_measurement': '%',
|
||||
})
|
||||
# ---
|
||||
# name: test_setup[number.mock_filter_system_led_brightness-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'friendly_name': 'Mock filter System LED brightness',
|
||||
'max': 100,
|
||||
'min': 0,
|
||||
'mode': <NumberMode.AUTO: 'auto'>,
|
||||
'step': 1,
|
||||
'unit_of_measurement': '%',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'number.mock_filter_system_led_brightness',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'unknown',
|
||||
})
|
||||
# ---
|
||||
# name: test_setup[number.mock_heater_night_temperature_offset-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
|
||||
@@ -58,3 +58,568 @@
|
||||
'state': 'unknown',
|
||||
})
|
||||
# ---
|
||||
# name: test_setup[select.mock_filter_constant_flow_speed-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
'area_id': None,
|
||||
'capabilities': dict({
|
||||
'options': list([
|
||||
'400',
|
||||
'440',
|
||||
'480',
|
||||
'515',
|
||||
'550',
|
||||
'585',
|
||||
'620',
|
||||
'650',
|
||||
'680',
|
||||
'710',
|
||||
'740',
|
||||
'770',
|
||||
'800',
|
||||
'830',
|
||||
'860',
|
||||
]),
|
||||
}),
|
||||
'config_entry_id': <ANY>,
|
||||
'config_subentry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'select',
|
||||
'entity_category': <EntityCategory.CONFIG: 'config'>,
|
||||
'entity_id': 'select.mock_filter_constant_flow_speed',
|
||||
'has_entity_name': True,
|
||||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
'original_device_class': None,
|
||||
'original_icon': None,
|
||||
'original_name': 'Constant flow speed',
|
||||
'platform': 'eheimdigital',
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'const_flow_speed',
|
||||
'unique_id': '00:00:00:00:00:04_const_flow_speed',
|
||||
'unit_of_measurement': <UnitOfVolumeFlowRate.LITERS_PER_HOUR: 'L/h'>,
|
||||
})
|
||||
# ---
|
||||
# name: test_setup[select.mock_filter_constant_flow_speed-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'friendly_name': 'Mock filter Constant flow speed',
|
||||
'options': list([
|
||||
'400',
|
||||
'440',
|
||||
'480',
|
||||
'515',
|
||||
'550',
|
||||
'585',
|
||||
'620',
|
||||
'650',
|
||||
'680',
|
||||
'710',
|
||||
'740',
|
||||
'770',
|
||||
'800',
|
||||
'830',
|
||||
'860',
|
||||
]),
|
||||
'unit_of_measurement': <UnitOfVolumeFlowRate.LITERS_PER_HOUR: 'L/h'>,
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'select.mock_filter_constant_flow_speed',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'unknown',
|
||||
})
|
||||
# ---
|
||||
# name: test_setup[select.mock_filter_day_speed-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
'area_id': None,
|
||||
'capabilities': dict({
|
||||
'options': list([
|
||||
'400',
|
||||
'440',
|
||||
'480',
|
||||
'515',
|
||||
'550',
|
||||
'585',
|
||||
'620',
|
||||
'650',
|
||||
'680',
|
||||
'710',
|
||||
'740',
|
||||
'770',
|
||||
'800',
|
||||
'830',
|
||||
'860',
|
||||
]),
|
||||
}),
|
||||
'config_entry_id': <ANY>,
|
||||
'config_subentry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'select',
|
||||
'entity_category': <EntityCategory.CONFIG: 'config'>,
|
||||
'entity_id': 'select.mock_filter_day_speed',
|
||||
'has_entity_name': True,
|
||||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
'original_device_class': None,
|
||||
'original_icon': None,
|
||||
'original_name': 'Day speed',
|
||||
'platform': 'eheimdigital',
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'day_speed',
|
||||
'unique_id': '00:00:00:00:00:04_day_speed',
|
||||
'unit_of_measurement': <UnitOfVolumeFlowRate.LITERS_PER_HOUR: 'L/h'>,
|
||||
})
|
||||
# ---
|
||||
# name: test_setup[select.mock_filter_day_speed-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'friendly_name': 'Mock filter Day speed',
|
||||
'options': list([
|
||||
'400',
|
||||
'440',
|
||||
'480',
|
||||
'515',
|
||||
'550',
|
||||
'585',
|
||||
'620',
|
||||
'650',
|
||||
'680',
|
||||
'710',
|
||||
'740',
|
||||
'770',
|
||||
'800',
|
||||
'830',
|
||||
'860',
|
||||
]),
|
||||
'unit_of_measurement': <UnitOfVolumeFlowRate.LITERS_PER_HOUR: 'L/h'>,
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'select.mock_filter_day_speed',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'unknown',
|
||||
})
|
||||
# ---
|
||||
# name: test_setup[select.mock_filter_filter_mode-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
'area_id': None,
|
||||
'capabilities': dict({
|
||||
'options': list([
|
||||
'manual',
|
||||
'constant_flow',
|
||||
'pulse',
|
||||
'bio',
|
||||
]),
|
||||
}),
|
||||
'config_entry_id': <ANY>,
|
||||
'config_subentry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'select',
|
||||
'entity_category': <EntityCategory.CONFIG: 'config'>,
|
||||
'entity_id': 'select.mock_filter_filter_mode',
|
||||
'has_entity_name': True,
|
||||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
'original_device_class': None,
|
||||
'original_icon': None,
|
||||
'original_name': 'Filter mode',
|
||||
'platform': 'eheimdigital',
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'filter_mode',
|
||||
'unique_id': '00:00:00:00:00:04_filter_mode',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
# name: test_setup[select.mock_filter_filter_mode-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'friendly_name': 'Mock filter Filter mode',
|
||||
'options': list([
|
||||
'manual',
|
||||
'constant_flow',
|
||||
'pulse',
|
||||
'bio',
|
||||
]),
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'select.mock_filter_filter_mode',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'unknown',
|
||||
})
|
||||
# ---
|
||||
# name: test_setup[select.mock_filter_high_pulse_speed-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
'area_id': None,
|
||||
'capabilities': dict({
|
||||
'options': list([
|
||||
'400',
|
||||
'440',
|
||||
'480',
|
||||
'515',
|
||||
'550',
|
||||
'585',
|
||||
'620',
|
||||
'650',
|
||||
'680',
|
||||
'710',
|
||||
'740',
|
||||
'770',
|
||||
'800',
|
||||
'830',
|
||||
'860',
|
||||
]),
|
||||
}),
|
||||
'config_entry_id': <ANY>,
|
||||
'config_subentry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'select',
|
||||
'entity_category': <EntityCategory.CONFIG: 'config'>,
|
||||
'entity_id': 'select.mock_filter_high_pulse_speed',
|
||||
'has_entity_name': True,
|
||||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
'original_device_class': None,
|
||||
'original_icon': None,
|
||||
'original_name': 'High pulse speed',
|
||||
'platform': 'eheimdigital',
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'high_pulse_speed',
|
||||
'unique_id': '00:00:00:00:00:04_high_pulse_speed',
|
||||
'unit_of_measurement': <UnitOfVolumeFlowRate.LITERS_PER_HOUR: 'L/h'>,
|
||||
})
|
||||
# ---
|
||||
# name: test_setup[select.mock_filter_high_pulse_speed-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'friendly_name': 'Mock filter High pulse speed',
|
||||
'options': list([
|
||||
'400',
|
||||
'440',
|
||||
'480',
|
||||
'515',
|
||||
'550',
|
||||
'585',
|
||||
'620',
|
||||
'650',
|
||||
'680',
|
||||
'710',
|
||||
'740',
|
||||
'770',
|
||||
'800',
|
||||
'830',
|
||||
'860',
|
||||
]),
|
||||
'unit_of_measurement': <UnitOfVolumeFlowRate.LITERS_PER_HOUR: 'L/h'>,
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'select.mock_filter_high_pulse_speed',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'unknown',
|
||||
})
|
||||
# ---
|
||||
# name: test_setup[select.mock_filter_low_pulse_speed-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
'area_id': None,
|
||||
'capabilities': dict({
|
||||
'options': list([
|
||||
'400',
|
||||
'440',
|
||||
'480',
|
||||
'515',
|
||||
'550',
|
||||
'585',
|
||||
'620',
|
||||
'650',
|
||||
'680',
|
||||
'710',
|
||||
'740',
|
||||
'770',
|
||||
'800',
|
||||
'830',
|
||||
'860',
|
||||
]),
|
||||
}),
|
||||
'config_entry_id': <ANY>,
|
||||
'config_subentry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'select',
|
||||
'entity_category': <EntityCategory.CONFIG: 'config'>,
|
||||
'entity_id': 'select.mock_filter_low_pulse_speed',
|
||||
'has_entity_name': True,
|
||||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
'original_device_class': None,
|
||||
'original_icon': None,
|
||||
'original_name': 'Low pulse speed',
|
||||
'platform': 'eheimdigital',
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'low_pulse_speed',
|
||||
'unique_id': '00:00:00:00:00:04_low_pulse_speed',
|
||||
'unit_of_measurement': <UnitOfVolumeFlowRate.LITERS_PER_HOUR: 'L/h'>,
|
||||
})
|
||||
# ---
|
||||
# name: test_setup[select.mock_filter_low_pulse_speed-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'friendly_name': 'Mock filter Low pulse speed',
|
||||
'options': list([
|
||||
'400',
|
||||
'440',
|
||||
'480',
|
||||
'515',
|
||||
'550',
|
||||
'585',
|
||||
'620',
|
||||
'650',
|
||||
'680',
|
||||
'710',
|
||||
'740',
|
||||
'770',
|
||||
'800',
|
||||
'830',
|
||||
'860',
|
||||
]),
|
||||
'unit_of_measurement': <UnitOfVolumeFlowRate.LITERS_PER_HOUR: 'L/h'>,
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'select.mock_filter_low_pulse_speed',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'unknown',
|
||||
})
|
||||
# ---
|
||||
# name: test_setup[select.mock_filter_manual_speed-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
'area_id': None,
|
||||
'capabilities': dict({
|
||||
'options': list([
|
||||
'35',
|
||||
'37.5',
|
||||
'40.5',
|
||||
'43',
|
||||
'45.5',
|
||||
'48',
|
||||
'51',
|
||||
'53.5',
|
||||
'56',
|
||||
'59',
|
||||
'61.5',
|
||||
'64',
|
||||
'66.5',
|
||||
'69.5',
|
||||
'72',
|
||||
]),
|
||||
}),
|
||||
'config_entry_id': <ANY>,
|
||||
'config_subentry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'select',
|
||||
'entity_category': <EntityCategory.CONFIG: 'config'>,
|
||||
'entity_id': 'select.mock_filter_manual_speed',
|
||||
'has_entity_name': True,
|
||||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
'original_device_class': None,
|
||||
'original_icon': None,
|
||||
'original_name': 'Manual speed',
|
||||
'platform': 'eheimdigital',
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'manual_speed',
|
||||
'unique_id': '00:00:00:00:00:04_manual_speed',
|
||||
'unit_of_measurement': <UnitOfFrequency.HERTZ: 'Hz'>,
|
||||
})
|
||||
# ---
|
||||
# name: test_setup[select.mock_filter_manual_speed-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'friendly_name': 'Mock filter Manual speed',
|
||||
'options': list([
|
||||
'35',
|
||||
'37.5',
|
||||
'40.5',
|
||||
'43',
|
||||
'45.5',
|
||||
'48',
|
||||
'51',
|
||||
'53.5',
|
||||
'56',
|
||||
'59',
|
||||
'61.5',
|
||||
'64',
|
||||
'66.5',
|
||||
'69.5',
|
||||
'72',
|
||||
]),
|
||||
'unit_of_measurement': <UnitOfFrequency.HERTZ: 'Hz'>,
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'select.mock_filter_manual_speed',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'unknown',
|
||||
})
|
||||
# ---
|
||||
# name: test_setup[select.mock_filter_night_speed-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
'area_id': None,
|
||||
'capabilities': dict({
|
||||
'options': list([
|
||||
'400',
|
||||
'440',
|
||||
'480',
|
||||
'515',
|
||||
'550',
|
||||
'585',
|
||||
'620',
|
||||
'650',
|
||||
'680',
|
||||
'710',
|
||||
'740',
|
||||
'770',
|
||||
'800',
|
||||
'830',
|
||||
'860',
|
||||
]),
|
||||
}),
|
||||
'config_entry_id': <ANY>,
|
||||
'config_subentry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'select',
|
||||
'entity_category': <EntityCategory.CONFIG: 'config'>,
|
||||
'entity_id': 'select.mock_filter_night_speed',
|
||||
'has_entity_name': True,
|
||||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
'original_device_class': None,
|
||||
'original_icon': None,
|
||||
'original_name': 'Night speed',
|
||||
'platform': 'eheimdigital',
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'night_speed',
|
||||
'unique_id': '00:00:00:00:00:04_night_speed',
|
||||
'unit_of_measurement': <UnitOfVolumeFlowRate.LITERS_PER_HOUR: 'L/h'>,
|
||||
})
|
||||
# ---
|
||||
# name: test_setup[select.mock_filter_night_speed-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'friendly_name': 'Mock filter Night speed',
|
||||
'options': list([
|
||||
'400',
|
||||
'440',
|
||||
'480',
|
||||
'515',
|
||||
'550',
|
||||
'585',
|
||||
'620',
|
||||
'650',
|
||||
'680',
|
||||
'710',
|
||||
'740',
|
||||
'770',
|
||||
'800',
|
||||
'830',
|
||||
'860',
|
||||
]),
|
||||
'unit_of_measurement': <UnitOfVolumeFlowRate.LITERS_PER_HOUR: 'L/h'>,
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'select.mock_filter_night_speed',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'unknown',
|
||||
})
|
||||
# ---
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# serializer version: 1
|
||||
# name: test_setup_classic_vario[sensor.mock_classicvario_current_speed-entry]
|
||||
# name: test_setup[sensor.mock_classicvario_current_speed-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
@@ -34,7 +34,7 @@
|
||||
'unit_of_measurement': '%',
|
||||
})
|
||||
# ---
|
||||
# name: test_setup_classic_vario[sensor.mock_classicvario_current_speed-state]
|
||||
# name: test_setup[sensor.mock_classicvario_current_speed-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'friendly_name': 'Mock classicVARIO Current speed',
|
||||
@@ -48,7 +48,7 @@
|
||||
'state': 'unknown',
|
||||
})
|
||||
# ---
|
||||
# name: test_setup_classic_vario[sensor.mock_classicvario_error_code-entry]
|
||||
# name: test_setup[sensor.mock_classicvario_error_code-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
@@ -89,7 +89,7 @@
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
# name: test_setup_classic_vario[sensor.mock_classicvario_error_code-state]
|
||||
# name: test_setup[sensor.mock_classicvario_error_code-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'device_class': 'enum',
|
||||
@@ -108,7 +108,7 @@
|
||||
'state': 'unknown',
|
||||
})
|
||||
# ---
|
||||
# name: test_setup_classic_vario[sensor.mock_classicvario_remaining_hours_until_service-entry]
|
||||
# name: test_setup[sensor.mock_classicvario_remaining_hours_until_service-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
@@ -149,7 +149,7 @@
|
||||
'unit_of_measurement': <UnitOfTime.DAYS: 'd'>,
|
||||
})
|
||||
# ---
|
||||
# name: test_setup_classic_vario[sensor.mock_classicvario_remaining_hours_until_service-state]
|
||||
# name: test_setup[sensor.mock_classicvario_remaining_hours_until_service-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'device_class': 'duration',
|
||||
@@ -164,3 +164,112 @@
|
||||
'state': 'unknown',
|
||||
})
|
||||
# ---
|
||||
# name: test_setup[sensor.mock_filter_current_speed-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
'area_id': None,
|
||||
'capabilities': None,
|
||||
'config_entry_id': <ANY>,
|
||||
'config_subentry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'sensor',
|
||||
'entity_category': None,
|
||||
'entity_id': 'sensor.mock_filter_current_speed',
|
||||
'has_entity_name': True,
|
||||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
'sensor': dict({
|
||||
'suggested_display_precision': 1,
|
||||
}),
|
||||
}),
|
||||
'original_device_class': <SensorDeviceClass.FREQUENCY: 'frequency'>,
|
||||
'original_icon': None,
|
||||
'original_name': 'Current speed',
|
||||
'platform': 'eheimdigital',
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'current_speed',
|
||||
'unique_id': '00:00:00:00:00:04_current_speed',
|
||||
'unit_of_measurement': <UnitOfFrequency.HERTZ: 'Hz'>,
|
||||
})
|
||||
# ---
|
||||
# name: test_setup[sensor.mock_filter_current_speed-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'device_class': 'frequency',
|
||||
'friendly_name': 'Mock filter Current speed',
|
||||
'unit_of_measurement': <UnitOfFrequency.HERTZ: 'Hz'>,
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.mock_filter_current_speed',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'unknown',
|
||||
})
|
||||
# ---
|
||||
# name: test_setup[sensor.mock_filter_remaining_hours_until_service-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
'area_id': None,
|
||||
'capabilities': None,
|
||||
'config_entry_id': <ANY>,
|
||||
'config_subentry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'sensor',
|
||||
'entity_category': <EntityCategory.DIAGNOSTIC: 'diagnostic'>,
|
||||
'entity_id': 'sensor.mock_filter_remaining_hours_until_service',
|
||||
'has_entity_name': True,
|
||||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
'sensor': dict({
|
||||
'suggested_display_precision': 2,
|
||||
}),
|
||||
'sensor.private': dict({
|
||||
'suggested_unit_of_measurement': <UnitOfTime.DAYS: 'd'>,
|
||||
}),
|
||||
}),
|
||||
'original_device_class': <SensorDeviceClass.DURATION: 'duration'>,
|
||||
'original_icon': None,
|
||||
'original_name': 'Remaining hours until service',
|
||||
'platform': 'eheimdigital',
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'service_hours',
|
||||
'unique_id': '00:00:00:00:00:04_service_hours',
|
||||
'unit_of_measurement': <UnitOfTime.DAYS: 'd'>,
|
||||
})
|
||||
# ---
|
||||
# name: test_setup[sensor.mock_filter_remaining_hours_until_service-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'device_class': 'duration',
|
||||
'friendly_name': 'Mock filter Remaining hours until service',
|
||||
'unit_of_measurement': <UnitOfTime.DAYS: 'd'>,
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.mock_filter_remaining_hours_until_service',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'unknown',
|
||||
})
|
||||
# ---
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# serializer version: 1
|
||||
# name: test_setup_classic_vario[switch.mock_classicvario-entry]
|
||||
# name: test_setup[switch.mock_classicvario-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
@@ -34,7 +34,7 @@
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
# name: test_setup_classic_vario[switch.mock_classicvario-state]
|
||||
# name: test_setup[switch.mock_classicvario-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'friendly_name': 'Mock classicVARIO',
|
||||
@@ -47,3 +47,51 @@
|
||||
'state': 'on',
|
||||
})
|
||||
# ---
|
||||
# name: test_setup[switch.mock_filter-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
'area_id': None,
|
||||
'capabilities': None,
|
||||
'config_entry_id': <ANY>,
|
||||
'config_subentry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'switch',
|
||||
'entity_category': None,
|
||||
'entity_id': 'switch.mock_filter',
|
||||
'has_entity_name': True,
|
||||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
'original_device_class': None,
|
||||
'original_icon': None,
|
||||
'original_name': None,
|
||||
'platform': 'eheimdigital',
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'filter_active',
|
||||
'unique_id': '00:00:00:00:00:04',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
# name: test_setup[switch.mock_filter-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'friendly_name': 'Mock filter',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'switch.mock_filter',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'on',
|
||||
})
|
||||
# ---
|
||||
|
||||
@@ -95,6 +95,102 @@
|
||||
'state': 'unknown',
|
||||
})
|
||||
# ---
|
||||
# name: test_setup[time.mock_filter_day_start_time-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
'area_id': None,
|
||||
'capabilities': None,
|
||||
'config_entry_id': <ANY>,
|
||||
'config_subentry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'time',
|
||||
'entity_category': <EntityCategory.CONFIG: 'config'>,
|
||||
'entity_id': 'time.mock_filter_day_start_time',
|
||||
'has_entity_name': True,
|
||||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
'original_device_class': None,
|
||||
'original_icon': None,
|
||||
'original_name': 'Day start time',
|
||||
'platform': 'eheimdigital',
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'day_start_time',
|
||||
'unique_id': '00:00:00:00:00:04_day_start_time',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
# name: test_setup[time.mock_filter_day_start_time-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'friendly_name': 'Mock filter Day start time',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'time.mock_filter_day_start_time',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'unknown',
|
||||
})
|
||||
# ---
|
||||
# name: test_setup[time.mock_filter_night_start_time-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
'area_id': None,
|
||||
'capabilities': None,
|
||||
'config_entry_id': <ANY>,
|
||||
'config_subentry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'time',
|
||||
'entity_category': <EntityCategory.CONFIG: 'config'>,
|
||||
'entity_id': 'time.mock_filter_night_start_time',
|
||||
'has_entity_name': True,
|
||||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
'original_device_class': None,
|
||||
'original_icon': None,
|
||||
'original_name': 'Night start time',
|
||||
'platform': 'eheimdigital',
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'night_start_time',
|
||||
'unique_id': '00:00:00:00:00:04_night_start_time',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
# name: test_setup[time.mock_filter_night_start_time-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'friendly_name': 'Mock filter Night start time',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'time.mock_filter_night_start_time',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'unknown',
|
||||
})
|
||||
# ---
|
||||
# name: test_setup[time.mock_heater_day_start_time-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
|
||||
@@ -19,7 +19,6 @@ from .conftest import init_integration
|
||||
from tests.common import MockConfigEntry, snapshot_platform
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("classic_vario_mock", "heater_mock")
|
||||
async def test_setup(
|
||||
hass: HomeAssistant,
|
||||
eheimdigital_hub_mock: MagicMock,
|
||||
@@ -48,7 +47,6 @@ async def test_setup(
|
||||
await snapshot_platform(hass, entity_registry, snapshot, mock_config_entry.entry_id)
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("classic_vario_mock", "heater_mock")
|
||||
@pytest.mark.parametrize(
|
||||
("device_name", "entity_list"),
|
||||
[
|
||||
@@ -104,6 +102,23 @@ async def test_setup(
|
||||
),
|
||||
],
|
||||
),
|
||||
(
|
||||
"filter_mock",
|
||||
[
|
||||
(
|
||||
"number.mock_filter_low_pulse_duration",
|
||||
20,
|
||||
"time_low",
|
||||
20,
|
||||
),
|
||||
(
|
||||
"number.mock_filter_high_pulse_duration",
|
||||
20,
|
||||
"time_high",
|
||||
20,
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
)
|
||||
async def test_set_value(
|
||||
@@ -135,7 +150,6 @@ async def test_set_value(
|
||||
assert calls[-1][1][0][item[2]] == item[3]
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("classic_vario_mock", "heater_mock")
|
||||
@pytest.mark.parametrize(
|
||||
("device_name", "entity_list"),
|
||||
[
|
||||
@@ -198,6 +212,32 @@ async def test_set_value(
|
||||
),
|
||||
],
|
||||
),
|
||||
(
|
||||
"filter_mock",
|
||||
[
|
||||
(
|
||||
"number.mock_filter_low_pulse_duration",
|
||||
"filter_data",
|
||||
"pm_time_low",
|
||||
20,
|
||||
20,
|
||||
),
|
||||
(
|
||||
"number.mock_filter_high_pulse_duration",
|
||||
"filter_data",
|
||||
"pm_time_high",
|
||||
20,
|
||||
20,
|
||||
),
|
||||
(
|
||||
"number.mock_filter_system_led_brightness",
|
||||
"usrdta",
|
||||
"sysLED",
|
||||
20,
|
||||
20,
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
)
|
||||
async def test_state_update(
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
from unittest.mock import AsyncMock, MagicMock, patch
|
||||
|
||||
from eheimdigital.types import FilterMode
|
||||
from eheimdigital.types import FilterMode, FilterModeProf
|
||||
import pytest
|
||||
from syrupy.assertion import SnapshotAssertion
|
||||
|
||||
@@ -20,7 +20,6 @@ from .conftest import init_integration
|
||||
from tests.common import MockConfigEntry, snapshot_platform
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("classic_vario_mock")
|
||||
async def test_setup(
|
||||
hass: HomeAssistant,
|
||||
eheimdigital_hub_mock: MagicMock,
|
||||
@@ -49,7 +48,6 @@ async def test_setup(
|
||||
await snapshot_platform(hass, entity_registry, snapshot, mock_config_entry.entry_id)
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("classic_vario_mock")
|
||||
@pytest.mark.parametrize(
|
||||
("device_name", "entity_list"),
|
||||
[
|
||||
@@ -64,6 +62,28 @@ async def test_setup(
|
||||
),
|
||||
],
|
||||
),
|
||||
(
|
||||
"filter_mock",
|
||||
[
|
||||
(
|
||||
"select.mock_filter_filter_mode",
|
||||
"constant_flow",
|
||||
"title",
|
||||
"START_FILTER_NORMAL_MODE_WITH_COMP",
|
||||
),
|
||||
(
|
||||
"select.mock_filter_manual_speed",
|
||||
"61.5",
|
||||
"frequency",
|
||||
int(61.5 * 100),
|
||||
),
|
||||
("select.mock_filter_constant_flow_speed", "440", "flow_rate", 1),
|
||||
("select.mock_filter_day_speed", "480", "dfs_soll_day", 2),
|
||||
("select.mock_filter_night_speed", "860", "dfs_soll_night", 14),
|
||||
("select.mock_filter_high_pulse_speed", "620", "dfs_soll_high", 6),
|
||||
("select.mock_filter_low_pulse_speed", "770", "dfs_soll_low", 11),
|
||||
],
|
||||
),
|
||||
],
|
||||
)
|
||||
async def test_set_value(
|
||||
@@ -111,6 +131,60 @@ async def test_set_value(
|
||||
),
|
||||
],
|
||||
),
|
||||
(
|
||||
"filter_mock",
|
||||
[
|
||||
(
|
||||
"select.mock_filter_filter_mode",
|
||||
"filter_data",
|
||||
"pumpMode",
|
||||
int(FilterModeProf.CONSTANT_FLOW),
|
||||
"constant_flow",
|
||||
),
|
||||
(
|
||||
"select.mock_filter_manual_speed",
|
||||
"filter_data",
|
||||
"freqSoll",
|
||||
int(61.5 * 100),
|
||||
"61.5",
|
||||
),
|
||||
(
|
||||
"select.mock_filter_constant_flow_speed",
|
||||
"filter_data",
|
||||
"sollStep",
|
||||
1,
|
||||
"440",
|
||||
),
|
||||
(
|
||||
"select.mock_filter_day_speed",
|
||||
"filter_data",
|
||||
"nm_dfs_soll_day",
|
||||
2,
|
||||
"480",
|
||||
),
|
||||
(
|
||||
"select.mock_filter_night_speed",
|
||||
"filter_data",
|
||||
"nm_dfs_soll_night",
|
||||
14,
|
||||
"860",
|
||||
),
|
||||
(
|
||||
"select.mock_filter_high_pulse_speed",
|
||||
"filter_data",
|
||||
"pm_dfs_soll_high",
|
||||
6,
|
||||
"620",
|
||||
),
|
||||
(
|
||||
"select.mock_filter_low_pulse_speed",
|
||||
"filter_data",
|
||||
"pm_dfs_soll_low",
|
||||
11,
|
||||
"770",
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
)
|
||||
async def test_state_update(
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
from unittest.mock import AsyncMock, MagicMock, patch
|
||||
|
||||
from eheimdigital.types import EheimDeviceType, FilterErrorCode
|
||||
from eheimdigital.types import FilterErrorCode
|
||||
import pytest
|
||||
from syrupy.assertion import SnapshotAssertion
|
||||
|
||||
@@ -15,8 +15,7 @@ from .conftest import init_integration
|
||||
from tests.common import MockConfigEntry, get_sensor_display_state, snapshot_platform
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("classic_vario_mock")
|
||||
async def test_setup_classic_vario(
|
||||
async def test_setup(
|
||||
hass: HomeAssistant,
|
||||
eheimdigital_hub_mock: MagicMock,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
@@ -35,15 +34,15 @@ async def test_setup_classic_vario(
|
||||
):
|
||||
await hass.config_entries.async_setup(mock_config_entry.entry_id)
|
||||
|
||||
await eheimdigital_hub_mock.call_args.kwargs["device_found_callback"](
|
||||
"00:00:00:00:00:03", EheimDeviceType.VERSION_EHEIM_CLASSIC_VARIO
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
for device in eheimdigital_hub_mock.return_value.devices:
|
||||
await eheimdigital_hub_mock.call_args.kwargs["device_found_callback"](
|
||||
device, eheimdigital_hub_mock.return_value.devices[device].device_type
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
await snapshot_platform(hass, entity_registry, snapshot, mock_config_entry.entry_id)
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("classic_vario_mock")
|
||||
@pytest.mark.parametrize(
|
||||
("device_name", "entity_list"),
|
||||
[
|
||||
@@ -73,6 +72,25 @@ async def test_setup_classic_vario(
|
||||
),
|
||||
],
|
||||
),
|
||||
(
|
||||
"filter_mock",
|
||||
[
|
||||
(
|
||||
"sensor.mock_filter_current_speed",
|
||||
"filter_data",
|
||||
"freq",
|
||||
7200,
|
||||
str(round(72.0, 1)),
|
||||
),
|
||||
(
|
||||
"sensor.mock_filter_remaining_hours_until_service",
|
||||
"filter_data",
|
||||
"serviceHour",
|
||||
100,
|
||||
str(round(100 / 24, 2)),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
)
|
||||
async def test_state_update(
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
from unittest.mock import AsyncMock, MagicMock, patch
|
||||
|
||||
from eheimdigital.types import EheimDeviceType
|
||||
import pytest
|
||||
from syrupy.assertion import SnapshotAssertion
|
||||
|
||||
@@ -21,8 +20,7 @@ from .conftest import init_integration
|
||||
from tests.common import MockConfigEntry, snapshot_platform
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("classic_vario_mock")
|
||||
async def test_setup_classic_vario(
|
||||
async def test_setup(
|
||||
hass: HomeAssistant,
|
||||
eheimdigital_hub_mock: MagicMock,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
@@ -41,10 +39,11 @@ async def test_setup_classic_vario(
|
||||
):
|
||||
await hass.config_entries.async_setup(mock_config_entry.entry_id)
|
||||
|
||||
await eheimdigital_hub_mock.call_args.kwargs["device_found_callback"](
|
||||
"00:00:00:00:00:03", EheimDeviceType.VERSION_EHEIM_CLASSIC_VARIO
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
for device in eheimdigital_hub_mock.return_value.devices:
|
||||
await eheimdigital_hub_mock.call_args.kwargs["device_found_callback"](
|
||||
device, eheimdigital_hub_mock.return_value.devices[device].device_type
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
await snapshot_platform(hass, entity_registry, snapshot, mock_config_entry.entry_id)
|
||||
|
||||
@@ -52,37 +51,45 @@ async def test_setup_classic_vario(
|
||||
@pytest.mark.parametrize(
|
||||
("service", "active"), [(SERVICE_TURN_OFF, False), (SERVICE_TURN_ON, True)]
|
||||
)
|
||||
@pytest.mark.parametrize(
|
||||
("device_name", "entity_id", "property_name"),
|
||||
[
|
||||
("classic_vario_mock", "switch.mock_classicvario", "filterActive"),
|
||||
("filter_mock", "switch.mock_filter", "active"),
|
||||
],
|
||||
)
|
||||
async def test_turn_on_off(
|
||||
hass: HomeAssistant,
|
||||
eheimdigital_hub_mock: MagicMock,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
classic_vario_mock: MagicMock,
|
||||
device_name: str,
|
||||
entity_id: str,
|
||||
property_name: str,
|
||||
service: str,
|
||||
active: bool,
|
||||
request: pytest.FixtureRequest,
|
||||
) -> None:
|
||||
"""Test turning on/off the switch."""
|
||||
device: MagicMock = request.getfixturevalue(device_name)
|
||||
await init_integration(hass, mock_config_entry)
|
||||
|
||||
await eheimdigital_hub_mock.call_args.kwargs["device_found_callback"](
|
||||
"00:00:00:00:00:03", EheimDeviceType.VERSION_EHEIM_CLASSIC_VARIO
|
||||
device.mac_address, device.device_type
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
await hass.services.async_call(
|
||||
SWITCH_DOMAIN,
|
||||
service,
|
||||
{ATTR_ENTITY_ID: "switch.mock_classicvario"},
|
||||
{ATTR_ENTITY_ID: entity_id},
|
||||
blocking=True,
|
||||
)
|
||||
|
||||
calls = [
|
||||
call for call in classic_vario_mock.hub.mock_calls if call[0] == "send_packet"
|
||||
]
|
||||
assert len(calls) == 1
|
||||
assert calls[0][1][0].get("filterActive") == int(active)
|
||||
calls = [call for call in device.hub.mock_calls if call[0] == "send_packet"]
|
||||
assert calls[-1][1][0][property_name] == int(active)
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("classic_vario_mock")
|
||||
@pytest.mark.usefixtures("classic_vario_mock", "filter_mock")
|
||||
@pytest.mark.parametrize(
|
||||
("device_name", "entity_list"),
|
||||
[
|
||||
@@ -105,6 +112,25 @@ async def test_turn_on_off(
|
||||
),
|
||||
],
|
||||
),
|
||||
(
|
||||
"filter_mock",
|
||||
[
|
||||
(
|
||||
"switch.mock_filter",
|
||||
"filter_data",
|
||||
"filterActive",
|
||||
1,
|
||||
"on",
|
||||
),
|
||||
(
|
||||
"switch.mock_filter",
|
||||
"filter_data",
|
||||
"filterActive",
|
||||
0,
|
||||
"off",
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
)
|
||||
async def test_state_update(
|
||||
|
||||
@@ -20,7 +20,6 @@ from .conftest import init_integration
|
||||
from tests.common import MockConfigEntry, snapshot_platform
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("classic_vario_mock", "heater_mock")
|
||||
async def test_setup(
|
||||
hass: HomeAssistant,
|
||||
eheimdigital_hub_mock: MagicMock,
|
||||
@@ -49,7 +48,6 @@ async def test_setup(
|
||||
await snapshot_platform(hass, entity_registry, snapshot, mock_config_entry.entry_id)
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("classic_vario_mock", "heater_mock")
|
||||
@pytest.mark.parametrize(
|
||||
("device_name", "entity_list"),
|
||||
[
|
||||
@@ -87,6 +85,23 @@ async def test_setup(
|
||||
),
|
||||
],
|
||||
),
|
||||
(
|
||||
"filter_mock",
|
||||
[
|
||||
(
|
||||
"time.mock_filter_day_start_time",
|
||||
time(9, 0, tzinfo=timezone(timedelta(hours=1))),
|
||||
"end_time_night_mode",
|
||||
9 * 60,
|
||||
),
|
||||
(
|
||||
"time.mock_filter_night_start_time",
|
||||
time(19, 0, tzinfo=timezone(timedelta(hours=1))),
|
||||
"start_time_night_mode",
|
||||
19 * 60,
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
)
|
||||
async def test_set_value(
|
||||
@@ -118,7 +133,6 @@ async def test_set_value(
|
||||
assert calls[-1][1][0][item[2]] == item[3]
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("classic_vario_mock", "heater_mock")
|
||||
@pytest.mark.parametrize(
|
||||
("device_name", "entity_list"),
|
||||
[
|
||||
@@ -160,6 +174,25 @@ async def test_set_value(
|
||||
),
|
||||
],
|
||||
),
|
||||
(
|
||||
"filter_mock",
|
||||
[
|
||||
(
|
||||
"time.mock_filter_day_start_time",
|
||||
"filter_data",
|
||||
"end_time_night_mode",
|
||||
540,
|
||||
time(9, 0, tzinfo=timezone(timedelta(hours=1))).isoformat(),
|
||||
),
|
||||
(
|
||||
"time.mock_filter_night_start_time",
|
||||
"filter_data",
|
||||
"start_time_night_mode",
|
||||
1320,
|
||||
time(22, 0, tzinfo=timezone(timedelta(hours=1))).isoformat(),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
)
|
||||
async def test_state_update(
|
||||
|
||||
@@ -22,16 +22,12 @@ from homeassistant.components.hassio import (
|
||||
)
|
||||
from homeassistant.components.hassio.config import STORAGE_KEY
|
||||
from homeassistant.components.hassio.const import (
|
||||
ATTR_WS_EVENT,
|
||||
EVENT_NETWORK_CHANGED,
|
||||
EVENT_SUPERVISOR_EVENT,
|
||||
HASSIO_UPDATE_INTERVAL,
|
||||
REQUEST_REFRESH_DELAY,
|
||||
)
|
||||
from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import device_registry as dr, issue_registry as ir
|
||||
from homeassistant.helpers.dispatcher import async_dispatcher_send
|
||||
from homeassistant.helpers.hassio import is_hassio
|
||||
from homeassistant.setup import async_setup_component
|
||||
from homeassistant.util import dt as dt_util
|
||||
@@ -1392,26 +1388,3 @@ async def test_deprecated_installation_issue_supported_board(
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert len(issue_registry.issues) == 0
|
||||
|
||||
|
||||
async def test_network_change_event(hass: HomeAssistant) -> None:
|
||||
"""Test network change event from supervisor triggers network notification."""
|
||||
with (
|
||||
patch.dict(os.environ, MOCK_ENVIRON),
|
||||
patch(
|
||||
"homeassistant.components.hassio.HassIO.is_connected",
|
||||
return_value=True,
|
||||
),
|
||||
patch(
|
||||
"homeassistant.components.network.async_notify_network_change"
|
||||
) as mock_notify,
|
||||
):
|
||||
assert await async_setup_component(hass, DOMAIN, {})
|
||||
await hass.async_block_till_done()
|
||||
|
||||
async_dispatcher_send(
|
||||
hass, EVENT_SUPERVISOR_EVENT, {ATTR_WS_EVENT: EVENT_NETWORK_CHANGED}
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
mock_notify.assert_called_once_with(hass)
|
||||
|
||||
@@ -850,77 +850,3 @@ async def test_repair_docker_host_network_without_host_networking(
|
||||
|
||||
assert (issue := issue_registry.async_get_issue(DOMAIN, "docker_host_network"))
|
||||
assert issue == snapshot
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"mock_socket",
|
||||
[
|
||||
[
|
||||
(MDNS_TARGET_IP, _mock_cond_socket(NO_LOOPBACK_IPADDR)),
|
||||
]
|
||||
],
|
||||
indirect=True,
|
||||
)
|
||||
@pytest.mark.usefixtures("mock_socket")
|
||||
async def test_network_change_callbacks(hass: HomeAssistant) -> None:
|
||||
"""Test network change callbacks are called only when adapters change."""
|
||||
assert await async_setup_component(hass, DOMAIN, {DOMAIN: {}})
|
||||
await hass.async_block_till_done()
|
||||
|
||||
callback_calls = []
|
||||
|
||||
def mock_callback(adapters):
|
||||
"""Mock callback to track calls."""
|
||||
callback_calls.append(adapters)
|
||||
|
||||
# Register callback
|
||||
unregister = network.async_register_network_change_callback(hass, mock_callback)
|
||||
|
||||
# Get initial adapters
|
||||
network_obj = hass.data[DOMAIN]
|
||||
initial_adapters = network_obj.adapters
|
||||
|
||||
# Trigger network change with same adapters - callback should NOT be called
|
||||
with patch(
|
||||
"homeassistant.components.network.util.async_load_adapters",
|
||||
return_value=initial_adapters,
|
||||
):
|
||||
await network.async_notify_network_change(hass)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert len(callback_calls) == 0
|
||||
|
||||
# Trigger network change with different adapters - callback SHOULD be called
|
||||
new_adapters = [
|
||||
{
|
||||
"index": 2,
|
||||
"auto": True,
|
||||
"default": True,
|
||||
"enabled": True,
|
||||
"ipv4": [{"address": "192.168.2.10", "network_prefix": 24}],
|
||||
"ipv6": [],
|
||||
"name": "eth1",
|
||||
}
|
||||
]
|
||||
with patch(
|
||||
"homeassistant.components.network.util.async_load_adapters",
|
||||
return_value=new_adapters,
|
||||
):
|
||||
await network.async_notify_network_change(hass)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert len(callback_calls) == 1
|
||||
assert callback_calls[0] == new_adapters
|
||||
|
||||
# Unregister callback
|
||||
unregister()
|
||||
|
||||
# Trigger another change - callback should NOT be called
|
||||
with patch(
|
||||
"homeassistant.components.network.util.async_load_adapters",
|
||||
return_value=initial_adapters,
|
||||
):
|
||||
await network.async_notify_network_change(hass)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert len(callback_calls) == 1
|
||||
|
||||
@@ -2,8 +2,24 @@
|
||||
|
||||
import json
|
||||
from typing import Any
|
||||
from unittest.mock import patch
|
||||
|
||||
from tests.common import load_fixture
|
||||
from homeassistant.config_entries import ConfigEntryState
|
||||
from homeassistant.core import HomeAssistant
|
||||
|
||||
from tests.common import MockConfigEntry, load_fixture
|
||||
|
||||
|
||||
async def setup_platform(hass: HomeAssistant, config_entry: MockConfigEntry) -> None:
|
||||
"""Set up the NINA platform."""
|
||||
with patch(
|
||||
"pynina.baseApi.BaseAPI._makeRequest",
|
||||
wraps=mocked_request_function,
|
||||
):
|
||||
await hass.config_entries.async_setup(config_entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert config_entry.state is ConfigEntryState.LOADED
|
||||
|
||||
|
||||
def mocked_request_function(url: str) -> dict[str, Any]:
|
||||
|
||||
257
tests/components/nina/snapshots/test_binary_sensor.ambr
Normal file
257
tests/components/nina/snapshots/test_binary_sensor.ambr
Normal file
@@ -0,0 +1,257 @@
|
||||
# serializer version: 1
|
||||
# name: test_sensors[binary_sensor.nina_warning_aach_1-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
'area_id': None,
|
||||
'capabilities': None,
|
||||
'config_entry_id': <ANY>,
|
||||
'config_subentry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'binary_sensor',
|
||||
'entity_category': None,
|
||||
'entity_id': 'binary_sensor.nina_warning_aach_1',
|
||||
'has_entity_name': True,
|
||||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
'original_device_class': <BinarySensorDeviceClass.SAFETY: 'safety'>,
|
||||
'original_icon': None,
|
||||
'original_name': 'Warning: Aach 1',
|
||||
'platform': 'nina',
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': None,
|
||||
'unique_id': '095760000000-1',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
# name: test_sensors[binary_sensor.nina_warning_aach_1-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'affected_areas': 'Gemeinde Oberreichenbach, Gemeinde Neuweiler, Stadt Nagold, Stadt Neubulach, Gemeinde Schömberg, Gemeinde Simmersfeld, Gemeinde Simmozheim, Gemeinde Rohrdorf, Gemeinde Ostelsheim, Gemeinde Ebhausen, Gemeinde Egenhausen, Gemeinde Dobel, Stadt Bad Liebenzell, Stadt Solingen, Stadt Haiterbach, Stadt Bad Herrenalb, Gemeinde Höfen an der Enz, Gemeinde Gechingen, Gemeinde Enzklösterle, Gemeinde Gutach (Schwarzwaldbahn) und 3392 weitere.',
|
||||
'description': 'Es treten Sturmböen mit Geschwindigkeiten zwischen 70 km/h (20m/s, 38kn, Bft 8) und 85 km/h (24m/s, 47kn, Bft 9) aus westlicher Richtung auf. In Schauernähe sowie in exponierten Lagen muss mit schweren Sturmböen bis 90 km/h (25m/s, 48kn, Bft 10) gerechnet werden.',
|
||||
'device_class': 'safety',
|
||||
'expires': '3021-11-22T05:19:00+01:00',
|
||||
'friendly_name': 'NINA Warning: Aach 1',
|
||||
'headline': 'Ausfall Notruf 112',
|
||||
'id': 'mow.DE-NW-BN-SE030-20201014-30-000',
|
||||
'recommended_actions': '',
|
||||
'sender': 'Deutscher Wetterdienst',
|
||||
'sent': '2021-10-11T05:20:00+01:00',
|
||||
'severity': 'Minor',
|
||||
'start': '2021-11-01T05:20:00+01:00',
|
||||
'web': 'https://www.wettergefahren.de',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'binary_sensor.nina_warning_aach_1',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'on',
|
||||
})
|
||||
# ---
|
||||
# name: test_sensors[binary_sensor.nina_warning_aach_2-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
'area_id': None,
|
||||
'capabilities': None,
|
||||
'config_entry_id': <ANY>,
|
||||
'config_subentry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'binary_sensor',
|
||||
'entity_category': None,
|
||||
'entity_id': 'binary_sensor.nina_warning_aach_2',
|
||||
'has_entity_name': True,
|
||||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
'original_device_class': <BinarySensorDeviceClass.SAFETY: 'safety'>,
|
||||
'original_icon': None,
|
||||
'original_name': 'Warning: Aach 2',
|
||||
'platform': 'nina',
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': None,
|
||||
'unique_id': '095760000000-2',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
# name: test_sensors[binary_sensor.nina_warning_aach_2-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'device_class': 'safety',
|
||||
'friendly_name': 'NINA Warning: Aach 2',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'binary_sensor.nina_warning_aach_2',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'off',
|
||||
})
|
||||
# ---
|
||||
# name: test_sensors[binary_sensor.nina_warning_aach_3-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
'area_id': None,
|
||||
'capabilities': None,
|
||||
'config_entry_id': <ANY>,
|
||||
'config_subentry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'binary_sensor',
|
||||
'entity_category': None,
|
||||
'entity_id': 'binary_sensor.nina_warning_aach_3',
|
||||
'has_entity_name': True,
|
||||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
'original_device_class': <BinarySensorDeviceClass.SAFETY: 'safety'>,
|
||||
'original_icon': None,
|
||||
'original_name': 'Warning: Aach 3',
|
||||
'platform': 'nina',
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': None,
|
||||
'unique_id': '095760000000-3',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
# name: test_sensors[binary_sensor.nina_warning_aach_3-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'device_class': 'safety',
|
||||
'friendly_name': 'NINA Warning: Aach 3',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'binary_sensor.nina_warning_aach_3',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'off',
|
||||
})
|
||||
# ---
|
||||
# name: test_sensors[binary_sensor.nina_warning_aach_4-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
'area_id': None,
|
||||
'capabilities': None,
|
||||
'config_entry_id': <ANY>,
|
||||
'config_subentry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'binary_sensor',
|
||||
'entity_category': None,
|
||||
'entity_id': 'binary_sensor.nina_warning_aach_4',
|
||||
'has_entity_name': True,
|
||||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
'original_device_class': <BinarySensorDeviceClass.SAFETY: 'safety'>,
|
||||
'original_icon': None,
|
||||
'original_name': 'Warning: Aach 4',
|
||||
'platform': 'nina',
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': None,
|
||||
'unique_id': '095760000000-4',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
# name: test_sensors[binary_sensor.nina_warning_aach_4-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'device_class': 'safety',
|
||||
'friendly_name': 'NINA Warning: Aach 4',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'binary_sensor.nina_warning_aach_4',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'off',
|
||||
})
|
||||
# ---
|
||||
# name: test_sensors[binary_sensor.nina_warning_aach_5-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
'area_id': None,
|
||||
'capabilities': None,
|
||||
'config_entry_id': <ANY>,
|
||||
'config_subentry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'binary_sensor',
|
||||
'entity_category': None,
|
||||
'entity_id': 'binary_sensor.nina_warning_aach_5',
|
||||
'has_entity_name': True,
|
||||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
'original_device_class': <BinarySensorDeviceClass.SAFETY: 'safety'>,
|
||||
'original_icon': None,
|
||||
'original_name': 'Warning: Aach 5',
|
||||
'platform': 'nina',
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': None,
|
||||
'unique_id': '095760000000-5',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
# name: test_sensors[binary_sensor.nina_warning_aach_5-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'device_class': 'safety',
|
||||
'friendly_name': 'NINA Warning: Aach 5',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'binary_sensor.nina_warning_aach_5',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'off',
|
||||
})
|
||||
# ---
|
||||
@@ -3,40 +3,17 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
from unittest.mock import patch
|
||||
|
||||
from homeassistant.components.binary_sensor import BinarySensorDeviceClass
|
||||
from homeassistant.components.nina.const import (
|
||||
ATTR_AFFECTED_AREAS,
|
||||
ATTR_DESCRIPTION,
|
||||
ATTR_EXPIRES,
|
||||
ATTR_HEADLINE,
|
||||
ATTR_ID,
|
||||
ATTR_RECOMMENDED_ACTIONS,
|
||||
ATTR_SENDER,
|
||||
ATTR_SENT,
|
||||
ATTR_SEVERITY,
|
||||
ATTR_START,
|
||||
ATTR_WEB,
|
||||
DOMAIN,
|
||||
)
|
||||
from homeassistant.config_entries import ConfigEntryState
|
||||
from syrupy.assertion import SnapshotAssertion
|
||||
|
||||
from homeassistant.components.nina.const import ATTR_HEADLINE, DOMAIN
|
||||
from homeassistant.const import STATE_OFF, STATE_ON
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import entity_registry as er
|
||||
|
||||
from . import mocked_request_function
|
||||
from . import setup_platform
|
||||
|
||||
from tests.common import MockConfigEntry
|
||||
|
||||
ENTRY_DATA: dict[str, Any] = {
|
||||
"slots": 5,
|
||||
"regions": {"083350000000": "Aach, Stadt"},
|
||||
"filters": {
|
||||
"headline_filter": ".*corona.*",
|
||||
"area_filter": ".*",
|
||||
},
|
||||
}
|
||||
from tests.common import MockConfigEntry, snapshot_platform
|
||||
|
||||
ENTRY_DATA_NO_CORONA: dict[str, Any] = {
|
||||
"slots": 5,
|
||||
@@ -47,7 +24,7 @@ ENTRY_DATA_NO_CORONA: dict[str, Any] = {
|
||||
},
|
||||
}
|
||||
|
||||
ENTRY_DATA_NO_AREA: dict[str, Any] = {
|
||||
ENTRY_DATA_SPECIFIC_AREA: dict[str, Any] = {
|
||||
"slots": 5,
|
||||
"regions": {"083350000000": "Aach, Stadt"},
|
||||
"filters": {
|
||||
@@ -57,321 +34,93 @@ ENTRY_DATA_NO_AREA: dict[str, Any] = {
|
||||
}
|
||||
|
||||
|
||||
async def test_sensors(hass: HomeAssistant, entity_registry: er.EntityRegistry) -> None:
|
||||
async def test_sensors(
|
||||
hass: HomeAssistant,
|
||||
entity_registry: er.EntityRegistry,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
snapshot: SnapshotAssertion,
|
||||
) -> None:
|
||||
"""Test the creation and values of the NINA sensors."""
|
||||
|
||||
with patch(
|
||||
"pynina.baseApi.BaseAPI._makeRequest",
|
||||
wraps=mocked_request_function,
|
||||
):
|
||||
conf_entry: MockConfigEntry = MockConfigEntry(
|
||||
domain=DOMAIN, title="NINA", data=ENTRY_DATA, version=1, minor_version=3
|
||||
)
|
||||
conf_entry.add_to_hass(hass)
|
||||
|
||||
await hass.config_entries.async_setup(conf_entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert conf_entry.state is ConfigEntryState.LOADED
|
||||
|
||||
state_w1 = hass.states.get("binary_sensor.nina_warning_aach_stadt_1")
|
||||
entry_w1 = entity_registry.async_get("binary_sensor.nina_warning_aach_stadt_1")
|
||||
|
||||
assert state_w1.state == STATE_ON
|
||||
assert state_w1.attributes.get(ATTR_HEADLINE) == "Ausfall Notruf 112"
|
||||
assert (
|
||||
state_w1.attributes.get(ATTR_DESCRIPTION)
|
||||
== "Es treten Sturmböen mit Geschwindigkeiten zwischen 70 km/h (20m/s, 38kn, Bft 8) und 85 km/h (24m/s, 47kn, Bft 9) aus westlicher Richtung auf. In Schauernähe sowie in exponierten Lagen muss mit schweren Sturmböen bis 90 km/h (25m/s, 48kn, Bft 10) gerechnet werden."
|
||||
)
|
||||
assert state_w1.attributes.get(ATTR_SENDER) == "Deutscher Wetterdienst"
|
||||
assert state_w1.attributes.get(ATTR_SEVERITY) == "Minor"
|
||||
assert state_w1.attributes.get(ATTR_RECOMMENDED_ACTIONS) == ""
|
||||
assert state_w1.attributes.get(ATTR_WEB) == "https://www.wettergefahren.de"
|
||||
assert (
|
||||
state_w1.attributes.get(ATTR_AFFECTED_AREAS)
|
||||
== "Gemeinde Oberreichenbach, Gemeinde Neuweiler, Stadt Nagold, Stadt Neubulach, Gemeinde Schömberg, Gemeinde Simmersfeld, Gemeinde Simmozheim, Gemeinde Rohrdorf, Gemeinde Ostelsheim, Gemeinde Ebhausen, Gemeinde Egenhausen, Gemeinde Dobel, Stadt Bad Liebenzell, Stadt Solingen, Stadt Haiterbach, Stadt Bad Herrenalb, Gemeinde Höfen an der Enz, Gemeinde Gechingen, Gemeinde Enzklösterle, Gemeinde Gutach (Schwarzwaldbahn) und 3392 weitere."
|
||||
)
|
||||
assert state_w1.attributes.get(ATTR_ID) == "mow.DE-NW-BN-SE030-20201014-30-000"
|
||||
assert state_w1.attributes.get(ATTR_SENT) == "2021-10-11T05:20:00+01:00"
|
||||
assert state_w1.attributes.get(ATTR_START) == "2021-11-01T05:20:00+01:00"
|
||||
assert state_w1.attributes.get(ATTR_EXPIRES) == "3021-11-22T05:19:00+01:00"
|
||||
|
||||
assert entry_w1.unique_id == "083350000000-1"
|
||||
assert state_w1.attributes.get("device_class") == BinarySensorDeviceClass.SAFETY
|
||||
|
||||
state_w2 = hass.states.get("binary_sensor.nina_warning_aach_stadt_2")
|
||||
entry_w2 = entity_registry.async_get("binary_sensor.nina_warning_aach_stadt_2")
|
||||
|
||||
assert state_w2.state == STATE_OFF
|
||||
assert state_w2.attributes.get(ATTR_HEADLINE) is None
|
||||
assert state_w2.attributes.get(ATTR_DESCRIPTION) is None
|
||||
assert state_w2.attributes.get(ATTR_SENDER) is None
|
||||
assert state_w2.attributes.get(ATTR_SEVERITY) is None
|
||||
assert state_w2.attributes.get(ATTR_RECOMMENDED_ACTIONS) is None
|
||||
assert state_w2.attributes.get(ATTR_WEB) is None
|
||||
assert state_w2.attributes.get(ATTR_AFFECTED_AREAS) is None
|
||||
assert state_w2.attributes.get(ATTR_ID) is None
|
||||
assert state_w2.attributes.get(ATTR_SENT) is None
|
||||
assert state_w2.attributes.get(ATTR_START) is None
|
||||
assert state_w2.attributes.get(ATTR_EXPIRES) is None
|
||||
|
||||
assert entry_w2.unique_id == "083350000000-2"
|
||||
assert state_w2.attributes.get("device_class") == BinarySensorDeviceClass.SAFETY
|
||||
|
||||
state_w3 = hass.states.get("binary_sensor.nina_warning_aach_stadt_3")
|
||||
entry_w3 = entity_registry.async_get("binary_sensor.nina_warning_aach_stadt_3")
|
||||
|
||||
assert state_w3.state == STATE_OFF
|
||||
assert state_w3.attributes.get(ATTR_HEADLINE) is None
|
||||
assert state_w3.attributes.get(ATTR_DESCRIPTION) is None
|
||||
assert state_w3.attributes.get(ATTR_SENDER) is None
|
||||
assert state_w3.attributes.get(ATTR_SEVERITY) is None
|
||||
assert state_w3.attributes.get(ATTR_RECOMMENDED_ACTIONS) is None
|
||||
assert state_w3.attributes.get(ATTR_WEB) is None
|
||||
assert state_w3.attributes.get(ATTR_AFFECTED_AREAS) is None
|
||||
assert state_w3.attributes.get(ATTR_ID) is None
|
||||
assert state_w3.attributes.get(ATTR_SENT) is None
|
||||
assert state_w3.attributes.get(ATTR_START) is None
|
||||
assert state_w3.attributes.get(ATTR_EXPIRES) is None
|
||||
|
||||
assert entry_w3.unique_id == "083350000000-3"
|
||||
assert state_w3.attributes.get("device_class") == BinarySensorDeviceClass.SAFETY
|
||||
|
||||
state_w4 = hass.states.get("binary_sensor.nina_warning_aach_stadt_4")
|
||||
entry_w4 = entity_registry.async_get("binary_sensor.nina_warning_aach_stadt_4")
|
||||
|
||||
assert state_w4.state == STATE_OFF
|
||||
assert state_w4.attributes.get(ATTR_HEADLINE) is None
|
||||
assert state_w4.attributes.get(ATTR_DESCRIPTION) is None
|
||||
assert state_w4.attributes.get(ATTR_SENDER) is None
|
||||
assert state_w4.attributes.get(ATTR_SEVERITY) is None
|
||||
assert state_w4.attributes.get(ATTR_RECOMMENDED_ACTIONS) is None
|
||||
assert state_w4.attributes.get(ATTR_WEB) is None
|
||||
assert state_w4.attributes.get(ATTR_AFFECTED_AREAS) is None
|
||||
assert state_w4.attributes.get(ATTR_ID) is None
|
||||
assert state_w4.attributes.get(ATTR_SENT) is None
|
||||
assert state_w4.attributes.get(ATTR_START) is None
|
||||
assert state_w4.attributes.get(ATTR_EXPIRES) is None
|
||||
|
||||
assert entry_w4.unique_id == "083350000000-4"
|
||||
assert state_w4.attributes.get("device_class") == BinarySensorDeviceClass.SAFETY
|
||||
|
||||
state_w5 = hass.states.get("binary_sensor.nina_warning_aach_stadt_5")
|
||||
entry_w5 = entity_registry.async_get("binary_sensor.nina_warning_aach_stadt_5")
|
||||
|
||||
assert state_w5.state == STATE_OFF
|
||||
assert state_w5.attributes.get(ATTR_HEADLINE) is None
|
||||
assert state_w5.attributes.get(ATTR_DESCRIPTION) is None
|
||||
assert state_w5.attributes.get(ATTR_SENDER) is None
|
||||
assert state_w5.attributes.get(ATTR_SEVERITY) is None
|
||||
assert state_w5.attributes.get(ATTR_RECOMMENDED_ACTIONS) is None
|
||||
assert state_w5.attributes.get(ATTR_WEB) is None
|
||||
assert state_w5.attributes.get(ATTR_AFFECTED_AREAS) is None
|
||||
assert state_w5.attributes.get(ATTR_ID) is None
|
||||
assert state_w5.attributes.get(ATTR_SENT) is None
|
||||
assert state_w5.attributes.get(ATTR_START) is None
|
||||
assert state_w5.attributes.get(ATTR_EXPIRES) is None
|
||||
|
||||
assert entry_w5.unique_id == "083350000000-5"
|
||||
assert state_w5.attributes.get("device_class") == BinarySensorDeviceClass.SAFETY
|
||||
await setup_platform(hass, mock_config_entry)
|
||||
await snapshot_platform(hass, entity_registry, snapshot, mock_config_entry.entry_id)
|
||||
|
||||
|
||||
async def test_sensors_without_corona_filter(
|
||||
hass: HomeAssistant, entity_registry: er.EntityRegistry
|
||||
hass: HomeAssistant, entity_registry: er.EntityRegistry, snapshot: SnapshotAssertion
|
||||
) -> None:
|
||||
"""Test the creation and values of the NINA sensors without the corona filter."""
|
||||
|
||||
with patch(
|
||||
"pynina.baseApi.BaseAPI._makeRequest",
|
||||
wraps=mocked_request_function,
|
||||
):
|
||||
conf_entry: MockConfigEntry = MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
title="NINA",
|
||||
data=ENTRY_DATA_NO_CORONA,
|
||||
version=1,
|
||||
minor_version=3,
|
||||
)
|
||||
conf_entry.add_to_hass(hass)
|
||||
conf_entry: MockConfigEntry = MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
title="NINA",
|
||||
data=ENTRY_DATA_NO_CORONA,
|
||||
version=1,
|
||||
minor_version=3,
|
||||
)
|
||||
conf_entry.add_to_hass(hass)
|
||||
|
||||
await hass.config_entries.async_setup(conf_entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
await setup_platform(hass, conf_entry)
|
||||
|
||||
assert conf_entry.state is ConfigEntryState.LOADED
|
||||
state_w1 = hass.states.get("binary_sensor.nina_warning_aach_stadt_1")
|
||||
|
||||
state_w1 = hass.states.get("binary_sensor.nina_warning_aach_stadt_1")
|
||||
entry_w1 = entity_registry.async_get("binary_sensor.nina_warning_aach_stadt_1")
|
||||
assert state_w1.state == STATE_ON
|
||||
assert (
|
||||
state_w1.attributes.get(ATTR_HEADLINE)
|
||||
== "Corona-Verordnung des Landes: Warnstufe durch Landesgesundheitsamt ausgerufen"
|
||||
)
|
||||
|
||||
assert state_w1.state == STATE_ON
|
||||
assert (
|
||||
state_w1.attributes.get(ATTR_HEADLINE)
|
||||
== "Corona-Verordnung des Landes: Warnstufe durch Landesgesundheitsamt ausgerufen"
|
||||
)
|
||||
assert (
|
||||
state_w1.attributes.get(ATTR_DESCRIPTION)
|
||||
== "Die Zahl der mit dem Corona-Virus infizierten Menschen steigt gegenwärtig stark an. Es wächst daher die Gefahr einer weiteren Verbreitung der Infektion und - je nach Einzelfall - auch von schweren Erkrankungen."
|
||||
)
|
||||
assert state_w1.attributes.get(ATTR_SENDER) == ""
|
||||
assert state_w1.attributes.get(ATTR_SEVERITY) == "Minor"
|
||||
assert (
|
||||
state_w1.attributes.get(ATTR_RECOMMENDED_ACTIONS)
|
||||
== "Waschen sich regelmäßig und gründlich die Hände."
|
||||
)
|
||||
assert state_w1.attributes.get(ATTR_WEB) == ""
|
||||
assert (
|
||||
state_w1.attributes.get(ATTR_AFFECTED_AREAS)
|
||||
== "Bundesland: Freie Hansestadt Bremen, Land Berlin, Land Hessen, Land Nordrhein-Westfalen, Land Brandenburg, Freistaat Bayern, Land Mecklenburg-Vorpommern, Land Rheinland-Pfalz, Freistaat Sachsen, Land Schleswig-Holstein, Freie und Hansestadt Hamburg, Freistaat Thüringen, Land Niedersachsen, Land Saarland, Land Sachsen-Anhalt, Land Baden-Württemberg"
|
||||
)
|
||||
assert state_w1.attributes.get(ATTR_ID) == "mow.DE-BW-S-SE018-20211102-18-001"
|
||||
assert state_w1.attributes.get(ATTR_SENT) == "2021-11-02T20:07:16+01:00"
|
||||
assert state_w1.attributes.get(ATTR_START) == ""
|
||||
assert state_w1.attributes.get(ATTR_EXPIRES) == ""
|
||||
state_w2 = hass.states.get("binary_sensor.nina_warning_aach_stadt_2")
|
||||
|
||||
assert entry_w1.unique_id == "083350000000-1"
|
||||
assert state_w1.attributes.get("device_class") == BinarySensorDeviceClass.SAFETY
|
||||
assert state_w2.state == STATE_ON
|
||||
assert state_w2.attributes.get(ATTR_HEADLINE) == "Ausfall Notruf 112"
|
||||
|
||||
state_w2 = hass.states.get("binary_sensor.nina_warning_aach_stadt_2")
|
||||
entry_w2 = entity_registry.async_get("binary_sensor.nina_warning_aach_stadt_2")
|
||||
state_w3 = hass.states.get("binary_sensor.nina_warning_aach_stadt_3")
|
||||
|
||||
assert state_w2.state == STATE_ON
|
||||
assert state_w2.attributes.get(ATTR_HEADLINE) == "Ausfall Notruf 112"
|
||||
assert (
|
||||
state_w2.attributes.get(ATTR_DESCRIPTION)
|
||||
== "Es treten Sturmböen mit Geschwindigkeiten zwischen 70 km/h (20m/s, 38kn, Bft 8) und 85 km/h (24m/s, 47kn, Bft 9) aus westlicher Richtung auf. In Schauernähe sowie in exponierten Lagen muss mit schweren Sturmböen bis 90 km/h (25m/s, 48kn, Bft 10) gerechnet werden."
|
||||
)
|
||||
assert (
|
||||
state_w2.attributes.get(ATTR_AFFECTED_AREAS)
|
||||
== "Gemeinde Oberreichenbach, Gemeinde Neuweiler, Stadt Nagold, Stadt Neubulach, Gemeinde Schömberg, Gemeinde Simmersfeld, Gemeinde Simmozheim, Gemeinde Rohrdorf, Gemeinde Ostelsheim, Gemeinde Ebhausen, Gemeinde Egenhausen, Gemeinde Dobel, Stadt Bad Liebenzell, Stadt Solingen, Stadt Haiterbach, Stadt Bad Herrenalb, Gemeinde Höfen an der Enz, Gemeinde Gechingen, Gemeinde Enzklösterle, Gemeinde Gutach (Schwarzwaldbahn) und 3392 weitere."
|
||||
)
|
||||
assert state_w2.attributes.get(ATTR_SENDER) == "Deutscher Wetterdienst"
|
||||
assert state_w2.attributes.get(ATTR_SEVERITY) == "Minor"
|
||||
assert state_w2.attributes.get(ATTR_RECOMMENDED_ACTIONS) == ""
|
||||
assert state_w2.attributes.get(ATTR_WEB) == "https://www.wettergefahren.de"
|
||||
assert state_w2.attributes.get(ATTR_ID) == "mow.DE-NW-BN-SE030-20201014-30-000"
|
||||
assert state_w2.attributes.get(ATTR_SENT) == "2021-10-11T05:20:00+01:00"
|
||||
assert state_w2.attributes.get(ATTR_START) == "2021-11-01T05:20:00+01:00"
|
||||
assert state_w2.attributes.get(ATTR_EXPIRES) == "3021-11-22T05:19:00+01:00"
|
||||
assert state_w3.state == STATE_OFF
|
||||
|
||||
assert entry_w2.unique_id == "083350000000-2"
|
||||
assert state_w2.attributes.get("device_class") == BinarySensorDeviceClass.SAFETY
|
||||
state_w4 = hass.states.get("binary_sensor.nina_warning_aach_stadt_4")
|
||||
|
||||
state_w3 = hass.states.get("binary_sensor.nina_warning_aach_stadt_3")
|
||||
entry_w3 = entity_registry.async_get("binary_sensor.nina_warning_aach_stadt_3")
|
||||
assert state_w4.state == STATE_OFF
|
||||
|
||||
assert state_w3.state == STATE_OFF
|
||||
assert state_w3.attributes.get(ATTR_HEADLINE) is None
|
||||
assert state_w3.attributes.get(ATTR_DESCRIPTION) is None
|
||||
assert state_w3.attributes.get(ATTR_SENDER) is None
|
||||
assert state_w3.attributes.get(ATTR_SEVERITY) is None
|
||||
assert state_w3.attributes.get(ATTR_RECOMMENDED_ACTIONS) is None
|
||||
assert state_w3.attributes.get(ATTR_WEB) is None
|
||||
assert state_w3.attributes.get(ATTR_AFFECTED_AREAS) is None
|
||||
assert state_w3.attributes.get(ATTR_ID) is None
|
||||
assert state_w3.attributes.get(ATTR_SENT) is None
|
||||
assert state_w3.attributes.get(ATTR_START) is None
|
||||
assert state_w3.attributes.get(ATTR_EXPIRES) is None
|
||||
state_w5 = hass.states.get("binary_sensor.nina_warning_aach_stadt_5")
|
||||
|
||||
assert entry_w3.unique_id == "083350000000-3"
|
||||
assert state_w3.attributes.get("device_class") == BinarySensorDeviceClass.SAFETY
|
||||
|
||||
state_w4 = hass.states.get("binary_sensor.nina_warning_aach_stadt_4")
|
||||
entry_w4 = entity_registry.async_get("binary_sensor.nina_warning_aach_stadt_4")
|
||||
|
||||
assert state_w4.state == STATE_OFF
|
||||
assert state_w4.attributes.get(ATTR_HEADLINE) is None
|
||||
assert state_w4.attributes.get(ATTR_DESCRIPTION) is None
|
||||
assert state_w4.attributes.get(ATTR_SENDER) is None
|
||||
assert state_w4.attributes.get(ATTR_SEVERITY) is None
|
||||
assert state_w4.attributes.get(ATTR_RECOMMENDED_ACTIONS) is None
|
||||
assert state_w4.attributes.get(ATTR_WEB) is None
|
||||
assert state_w4.attributes.get(ATTR_AFFECTED_AREAS) is None
|
||||
assert state_w4.attributes.get(ATTR_ID) is None
|
||||
assert state_w4.attributes.get(ATTR_SENT) is None
|
||||
assert state_w4.attributes.get(ATTR_START) is None
|
||||
assert state_w4.attributes.get(ATTR_EXPIRES) is None
|
||||
|
||||
assert entry_w4.unique_id == "083350000000-4"
|
||||
assert state_w4.attributes.get("device_class") == BinarySensorDeviceClass.SAFETY
|
||||
|
||||
state_w5 = hass.states.get("binary_sensor.nina_warning_aach_stadt_5")
|
||||
entry_w5 = entity_registry.async_get("binary_sensor.nina_warning_aach_stadt_5")
|
||||
|
||||
assert state_w5.state == STATE_OFF
|
||||
assert state_w5.attributes.get(ATTR_HEADLINE) is None
|
||||
assert state_w5.attributes.get(ATTR_DESCRIPTION) is None
|
||||
assert state_w5.attributes.get(ATTR_SENDER) is None
|
||||
assert state_w5.attributes.get(ATTR_SEVERITY) is None
|
||||
assert state_w5.attributes.get(ATTR_RECOMMENDED_ACTIONS) is None
|
||||
assert state_w5.attributes.get(ATTR_WEB) is None
|
||||
assert state_w5.attributes.get(ATTR_AFFECTED_AREAS) is None
|
||||
assert state_w5.attributes.get(ATTR_ID) is None
|
||||
assert state_w5.attributes.get(ATTR_SENT) is None
|
||||
assert state_w5.attributes.get(ATTR_START) is None
|
||||
assert state_w5.attributes.get(ATTR_EXPIRES) is None
|
||||
|
||||
assert entry_w5.unique_id == "083350000000-5"
|
||||
assert state_w5.attributes.get("device_class") == BinarySensorDeviceClass.SAFETY
|
||||
assert state_w5.state == STATE_OFF
|
||||
|
||||
|
||||
async def test_sensors_with_area_filter(
|
||||
hass: HomeAssistant, entity_registry: er.EntityRegistry
|
||||
hass: HomeAssistant, entity_registry: er.EntityRegistry, snapshot: SnapshotAssertion
|
||||
) -> None:
|
||||
"""Test the creation and values of the NINA sensors with an area filter."""
|
||||
"""Test the creation and values of the NINA sensors with a restrictive area filter."""
|
||||
|
||||
with patch(
|
||||
"pynina.baseApi.BaseAPI._makeRequest",
|
||||
wraps=mocked_request_function,
|
||||
):
|
||||
conf_entry: MockConfigEntry = MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
title="NINA",
|
||||
data=ENTRY_DATA_NO_AREA,
|
||||
version=1,
|
||||
minor_version=3,
|
||||
)
|
||||
conf_entry.add_to_hass(hass)
|
||||
conf_entry: MockConfigEntry = MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
title="NINA",
|
||||
data=ENTRY_DATA_SPECIFIC_AREA,
|
||||
version=1,
|
||||
minor_version=3,
|
||||
)
|
||||
conf_entry.add_to_hass(hass)
|
||||
|
||||
await hass.config_entries.async_setup(conf_entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
await setup_platform(hass, conf_entry)
|
||||
|
||||
assert conf_entry.state is ConfigEntryState.LOADED
|
||||
state_w1 = hass.states.get("binary_sensor.nina_warning_aach_stadt_1")
|
||||
|
||||
state_w1 = hass.states.get("binary_sensor.nina_warning_aach_stadt_1")
|
||||
entry_w1 = entity_registry.async_get("binary_sensor.nina_warning_aach_stadt_1")
|
||||
assert state_w1.state == STATE_ON
|
||||
assert state_w1.attributes.get(ATTR_HEADLINE) == "Ausfall Notruf 112"
|
||||
|
||||
assert state_w1.state == STATE_ON
|
||||
state_w2 = hass.states.get("binary_sensor.nina_warning_aach_stadt_2")
|
||||
|
||||
assert entry_w1.unique_id == "083350000000-1"
|
||||
assert state_w1.attributes.get("device_class") == BinarySensorDeviceClass.SAFETY
|
||||
assert state_w2.state == STATE_OFF
|
||||
|
||||
state_w2 = hass.states.get("binary_sensor.nina_warning_aach_stadt_2")
|
||||
entry_w2 = entity_registry.async_get("binary_sensor.nina_warning_aach_stadt_2")
|
||||
state_w3 = hass.states.get("binary_sensor.nina_warning_aach_stadt_3")
|
||||
|
||||
assert state_w2.state == STATE_OFF
|
||||
assert state_w3.state == STATE_OFF
|
||||
|
||||
assert entry_w2.unique_id == "083350000000-2"
|
||||
assert state_w2.attributes.get("device_class") == BinarySensorDeviceClass.SAFETY
|
||||
state_w4 = hass.states.get("binary_sensor.nina_warning_aach_stadt_4")
|
||||
|
||||
state_w3 = hass.states.get("binary_sensor.nina_warning_aach_stadt_3")
|
||||
entry_w3 = entity_registry.async_get("binary_sensor.nina_warning_aach_stadt_3")
|
||||
assert state_w4.state == STATE_OFF
|
||||
|
||||
assert state_w3.state == STATE_OFF
|
||||
state_w5 = hass.states.get("binary_sensor.nina_warning_aach_stadt_5")
|
||||
|
||||
assert entry_w3.unique_id == "083350000000-3"
|
||||
assert state_w3.attributes.get("device_class") == BinarySensorDeviceClass.SAFETY
|
||||
|
||||
state_w4 = hass.states.get("binary_sensor.nina_warning_aach_stadt_4")
|
||||
entry_w4 = entity_registry.async_get("binary_sensor.nina_warning_aach_stadt_4")
|
||||
|
||||
assert state_w4.state == STATE_OFF
|
||||
|
||||
assert entry_w4.unique_id == "083350000000-4"
|
||||
assert state_w4.attributes.get("device_class") == BinarySensorDeviceClass.SAFETY
|
||||
|
||||
state_w5 = hass.states.get("binary_sensor.nina_warning_aach_stadt_5")
|
||||
entry_w5 = entity_registry.async_get("binary_sensor.nina_warning_aach_stadt_5")
|
||||
|
||||
assert state_w5.state == STATE_OFF
|
||||
|
||||
assert entry_w5.unique_id == "083350000000-5"
|
||||
assert state_w5.attributes.get("device_class") == BinarySensorDeviceClass.SAFETY
|
||||
assert state_w5.state == STATE_OFF
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from copy import deepcopy
|
||||
import json
|
||||
from typing import Any
|
||||
from unittest.mock import AsyncMock, patch
|
||||
|
||||
@@ -28,14 +27,10 @@ from homeassistant.core import HomeAssistant
|
||||
from homeassistant.data_entry_flow import FlowResultType
|
||||
from homeassistant.helpers import entity_registry as er
|
||||
|
||||
from . import mocked_request_function
|
||||
from . import mocked_request_function, setup_platform
|
||||
from .const import DUMMY_CONFIG_ENTRY, DUMMY_USER_INPUT
|
||||
|
||||
from tests.common import MockConfigEntry, load_fixture
|
||||
|
||||
DUMMY_RESPONSE_REGIONS: dict[str, Any] = json.loads(
|
||||
load_fixture("sample_regions.json", "nina")
|
||||
)
|
||||
from tests.common import MockConfigEntry
|
||||
|
||||
|
||||
def assert_dummy_entry_created(result: dict[str, Any]) -> None:
|
||||
@@ -141,15 +136,15 @@ async def test_options_flow_init(
|
||||
hass: HomeAssistant, mock_setup_entry: AsyncMock, mock_config_entry: MockConfigEntry
|
||||
) -> None:
|
||||
"""Test config flow options."""
|
||||
|
||||
await setup_platform(hass, mock_config_entry)
|
||||
|
||||
with (
|
||||
patch(
|
||||
"pynina.baseApi.BaseAPI._makeRequest",
|
||||
wraps=mocked_request_function,
|
||||
),
|
||||
):
|
||||
await hass.config_entries.async_setup(mock_config_entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
result = await hass.config_entries.options.async_init(
|
||||
mock_config_entry.entry_id
|
||||
)
|
||||
@@ -195,15 +190,15 @@ async def test_options_flow_with_no_selection(
|
||||
hass: HomeAssistant, mock_setup_entry: AsyncMock, mock_config_entry: MockConfigEntry
|
||||
) -> None:
|
||||
"""Test config flow options with no selection."""
|
||||
|
||||
await setup_platform(hass, mock_config_entry)
|
||||
|
||||
with (
|
||||
patch(
|
||||
"pynina.baseApi.BaseAPI._makeRequest",
|
||||
wraps=mocked_request_function,
|
||||
),
|
||||
):
|
||||
await hass.config_entries.async_setup(mock_config_entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
result = await hass.config_entries.options.async_init(
|
||||
mock_config_entry.entry_id
|
||||
)
|
||||
@@ -264,13 +259,13 @@ async def test_options_flow_connection_error(
|
||||
hass: HomeAssistant, mock_setup_entry: AsyncMock, mock_config_entry: MockConfigEntry
|
||||
) -> None:
|
||||
"""Test config flow options but no connection."""
|
||||
|
||||
await setup_platform(hass, mock_config_entry)
|
||||
|
||||
with patch(
|
||||
"pynina.baseApi.BaseAPI._makeRequest",
|
||||
side_effect=ApiError("Could not connect to Api"),
|
||||
):
|
||||
await hass.config_entries.async_setup(mock_config_entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
result = await hass.config_entries.options.async_init(
|
||||
mock_config_entry.entry_id
|
||||
)
|
||||
@@ -283,15 +278,15 @@ async def test_options_flow_unexpected_exception(
|
||||
hass: HomeAssistant, mock_setup_entry: AsyncMock, mock_config_entry: MockConfigEntry
|
||||
) -> None:
|
||||
"""Test config flow options but with an unexpected exception."""
|
||||
|
||||
await setup_platform(hass, mock_config_entry)
|
||||
|
||||
with (
|
||||
patch(
|
||||
"pynina.baseApi.BaseAPI._makeRequest",
|
||||
side_effect=Exception("DUMMY"),
|
||||
),
|
||||
):
|
||||
await hass.config_entries.async_setup(mock_config_entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
result = await hass.config_entries.options.async_init(
|
||||
mock_config_entry.entry_id
|
||||
)
|
||||
@@ -313,15 +308,14 @@ async def test_options_flow_entity_removal(
|
||||
)
|
||||
config_entry.add_to_hass(hass)
|
||||
|
||||
await setup_platform(hass, config_entry)
|
||||
|
||||
with (
|
||||
patch(
|
||||
"pynina.baseApi.BaseAPI._makeRequest",
|
||||
wraps=mocked_request_function,
|
||||
),
|
||||
):
|
||||
await hass.config_entries.async_setup(config_entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
result = await hass.config_entries.options.async_init(config_entry.entry_id)
|
||||
|
||||
result = await hass.config_entries.options.async_configure(
|
||||
|
||||
@@ -158,6 +158,57 @@
|
||||
'state': '13027.0',
|
||||
})
|
||||
# ---
|
||||
# name: test_sensors[e1][sensor.ruuvi_air_884f_indoor_air_quality_score-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
'area_id': None,
|
||||
'capabilities': dict({
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
}),
|
||||
'config_entry_id': <ANY>,
|
||||
'config_subentry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'sensor',
|
||||
'entity_category': None,
|
||||
'entity_id': 'sensor.ruuvi_air_884f_indoor_air_quality_score',
|
||||
'has_entity_name': True,
|
||||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
'original_device_class': None,
|
||||
'original_icon': None,
|
||||
'original_name': 'Indoor air quality score',
|
||||
'platform': 'ruuvitag_ble',
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'iaqs',
|
||||
'unique_id': '01:03:05:07:12:34-iaqs',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
# name: test_sensors[e1][sensor.ruuvi_air_884f_indoor_air_quality_score-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'friendly_name': 'Ruuvi Air 884F Indoor air quality score',
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.ruuvi_air_884f_indoor_air_quality_score',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': '81',
|
||||
})
|
||||
# ---
|
||||
# name: test_sensors[e1][sensor.ruuvi_air_884f_nox_index-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
@@ -1329,6 +1380,57 @@
|
||||
'state': '13027',
|
||||
})
|
||||
# ---
|
||||
# name: test_sensors[v6][sensor.ruuvitag_884f_indoor_air_quality_score-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
'area_id': None,
|
||||
'capabilities': dict({
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
}),
|
||||
'config_entry_id': <ANY>,
|
||||
'config_subentry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'sensor',
|
||||
'entity_category': None,
|
||||
'entity_id': 'sensor.ruuvitag_884f_indoor_air_quality_score',
|
||||
'has_entity_name': True,
|
||||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
'original_device_class': None,
|
||||
'original_icon': None,
|
||||
'original_name': 'Indoor air quality score',
|
||||
'platform': 'ruuvitag_ble',
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'iaqs',
|
||||
'unique_id': '01:03:05:07:12:34-iaqs',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
# name: test_sensors[v6][sensor.ruuvitag_884f_indoor_air_quality_score-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'friendly_name': 'RuuviTag 884F Indoor air quality score',
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.ruuvitag_884f_indoor_air_quality_score',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': '81',
|
||||
})
|
||||
# ---
|
||||
# name: test_sensors[v6][sensor.ruuvitag_884f_nox_index-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
|
||||
@@ -383,6 +383,13 @@ async def test_smoke_co_notification_sensors(
|
||||
assert entity_entry
|
||||
assert entity_entry.entity_category == EntityCategory.DIAGNOSTIC
|
||||
|
||||
# Test that no idle states are created as entities
|
||||
entity_id = "binary_sensor.zcombo_g_smoke_co_alarm_idle"
|
||||
state = hass.states.get(entity_id)
|
||||
assert state is None
|
||||
entity_entry = entity_registry.async_get(entity_id)
|
||||
assert entity_entry is None
|
||||
|
||||
# Test state updates for smoke alarm
|
||||
event = Event(
|
||||
type="value updated",
|
||||
|
||||
Reference in New Issue
Block a user