mirror of
https://github.com/home-assistant/core.git
synced 2025-07-26 06:37:52 +00:00
Bump whirlpool to 0.21.1 (#147611)
This commit is contained in:
parent
8cc4105984
commit
78c2405e61
@ -42,14 +42,21 @@ async def async_setup_entry(
|
|||||||
async_add_entities: AddConfigEntryEntitiesCallback,
|
async_add_entities: AddConfigEntryEntitiesCallback,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Config flow entry for Whirlpool binary sensors."""
|
"""Config flow entry for Whirlpool binary sensors."""
|
||||||
entities: list = []
|
|
||||||
appliances_manager = config_entry.runtime_data
|
appliances_manager = config_entry.runtime_data
|
||||||
for washer_dryer in appliances_manager.washer_dryers:
|
|
||||||
entities.extend(
|
washer_binary_sensors = [
|
||||||
WhirlpoolBinarySensor(washer_dryer, description)
|
WhirlpoolBinarySensor(washer, description)
|
||||||
|
for washer in appliances_manager.washers
|
||||||
for description in WASHER_DRYER_SENSORS
|
for description in WASHER_DRYER_SENSORS
|
||||||
)
|
]
|
||||||
async_add_entities(entities)
|
|
||||||
|
dryer_binary_sensors = [
|
||||||
|
WhirlpoolBinarySensor(dryer, description)
|
||||||
|
for dryer in appliances_manager.dryers
|
||||||
|
for description in WASHER_DRYER_SENSORS
|
||||||
|
]
|
||||||
|
|
||||||
|
async_add_entities([*washer_binary_sensors, *dryer_binary_sensors])
|
||||||
|
|
||||||
|
|
||||||
class WhirlpoolBinarySensor(WhirlpoolEntity, BinarySensorEntity):
|
class WhirlpoolBinarySensor(WhirlpoolEntity, BinarySensorEntity):
|
||||||
|
@ -70,7 +70,11 @@ async def authenticate(
|
|||||||
appliances_manager = AppliancesManager(backend_selector, auth, session)
|
appliances_manager = AppliancesManager(backend_selector, auth, session)
|
||||||
await appliances_manager.fetch_appliances()
|
await appliances_manager.fetch_appliances()
|
||||||
|
|
||||||
if not appliances_manager.aircons and not appliances_manager.washer_dryers:
|
if (
|
||||||
|
not appliances_manager.aircons
|
||||||
|
and not appliances_manager.washers
|
||||||
|
and not appliances_manager.dryers
|
||||||
|
):
|
||||||
return "no_appliances"
|
return "no_appliances"
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
@ -37,9 +37,13 @@ async def async_get_config_entry_diagnostics(
|
|||||||
|
|
||||||
appliances_manager = config_entry.runtime_data
|
appliances_manager = config_entry.runtime_data
|
||||||
diagnostics_data = {
|
diagnostics_data = {
|
||||||
"washer_dryers": {
|
"washers": {
|
||||||
wd.name: get_appliance_diagnostics(wd)
|
washer.name: get_appliance_diagnostics(washer)
|
||||||
for wd in appliances_manager.washer_dryers
|
for washer in appliances_manager.washers
|
||||||
|
},
|
||||||
|
"dryers": {
|
||||||
|
dryer.name: get_appliance_diagnostics(dryer)
|
||||||
|
for dryer in appliances_manager.dryers
|
||||||
},
|
},
|
||||||
"aircons": {
|
"aircons": {
|
||||||
ac.name: get_appliance_diagnostics(ac) for ac in appliances_manager.aircons
|
ac.name: get_appliance_diagnostics(ac) for ac in appliances_manager.aircons
|
||||||
|
@ -8,5 +8,5 @@
|
|||||||
"iot_class": "cloud_push",
|
"iot_class": "cloud_push",
|
||||||
"loggers": ["whirlpool"],
|
"loggers": ["whirlpool"],
|
||||||
"quality_scale": "bronze",
|
"quality_scale": "bronze",
|
||||||
"requirements": ["whirlpool-sixth-sense==0.20.0"]
|
"requirements": ["whirlpool-sixth-sense==0.21.1"]
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,14 @@
|
|||||||
"""The Washer/Dryer Sensor for Whirlpool Appliances."""
|
"""The Washer/Dryer Sensor for Whirlpool Appliances."""
|
||||||
|
|
||||||
|
from abc import ABC, abstractmethod
|
||||||
from collections.abc import Callable
|
from collections.abc import Callable
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
from typing import override
|
from typing import override
|
||||||
|
|
||||||
from whirlpool.appliance import Appliance
|
from whirlpool.appliance import Appliance
|
||||||
from whirlpool.washerdryer import MachineState, WasherDryer
|
from whirlpool.dryer import Dryer, MachineState as DryerMachineState
|
||||||
|
from whirlpool.washer import MachineState as WasherMachineState, Washer
|
||||||
|
|
||||||
from homeassistant.components.sensor import (
|
from homeassistant.components.sensor import (
|
||||||
RestoreSensor,
|
RestoreSensor,
|
||||||
@ -33,26 +35,49 @@ WASHER_TANK_FILL = {
|
|||||||
5: "active",
|
5: "active",
|
||||||
}
|
}
|
||||||
|
|
||||||
WASHER_DRYER_MACHINE_STATE = {
|
WASHER_MACHINE_STATE = {
|
||||||
MachineState.Standby: "standby",
|
WasherMachineState.Standby: "standby",
|
||||||
MachineState.Setting: "setting",
|
WasherMachineState.Setting: "setting",
|
||||||
MachineState.DelayCountdownMode: "delay_countdown",
|
WasherMachineState.DelayCountdownMode: "delay_countdown",
|
||||||
MachineState.DelayPause: "delay_paused",
|
WasherMachineState.DelayPause: "delay_paused",
|
||||||
MachineState.SmartDelay: "smart_delay",
|
WasherMachineState.SmartDelay: "smart_delay",
|
||||||
MachineState.SmartGridPause: "smart_grid_pause",
|
WasherMachineState.SmartGridPause: "smart_grid_pause",
|
||||||
MachineState.Pause: "pause",
|
WasherMachineState.Pause: "pause",
|
||||||
MachineState.RunningMainCycle: "running_maincycle",
|
WasherMachineState.RunningMainCycle: "running_maincycle",
|
||||||
MachineState.RunningPostCycle: "running_postcycle",
|
WasherMachineState.RunningPostCycle: "running_postcycle",
|
||||||
MachineState.Exceptions: "exception",
|
WasherMachineState.Exceptions: "exception",
|
||||||
MachineState.Complete: "complete",
|
WasherMachineState.Complete: "complete",
|
||||||
MachineState.PowerFailure: "power_failure",
|
WasherMachineState.PowerFailure: "power_failure",
|
||||||
MachineState.ServiceDiagnostic: "service_diagnostic_mode",
|
WasherMachineState.ServiceDiagnostic: "service_diagnostic_mode",
|
||||||
MachineState.FactoryDiagnostic: "factory_diagnostic_mode",
|
WasherMachineState.FactoryDiagnostic: "factory_diagnostic_mode",
|
||||||
MachineState.LifeTest: "life_test",
|
WasherMachineState.LifeTest: "life_test",
|
||||||
MachineState.CustomerFocusMode: "customer_focus_mode",
|
WasherMachineState.CustomerFocusMode: "customer_focus_mode",
|
||||||
MachineState.DemoMode: "demo_mode",
|
WasherMachineState.DemoMode: "demo_mode",
|
||||||
MachineState.HardStopOrError: "hard_stop_or_error",
|
WasherMachineState.HardStopOrError: "hard_stop_or_error",
|
||||||
MachineState.SystemInit: "system_initialize",
|
WasherMachineState.SystemInit: "system_initialize",
|
||||||
|
}
|
||||||
|
|
||||||
|
DRYER_MACHINE_STATE = {
|
||||||
|
DryerMachineState.Standby: "standby",
|
||||||
|
DryerMachineState.Setting: "setting",
|
||||||
|
DryerMachineState.DelayCountdownMode: "delay_countdown",
|
||||||
|
DryerMachineState.DelayPause: "delay_paused",
|
||||||
|
DryerMachineState.SmartDelay: "smart_delay",
|
||||||
|
DryerMachineState.SmartGridPause: "smart_grid_pause",
|
||||||
|
DryerMachineState.Pause: "pause",
|
||||||
|
DryerMachineState.RunningMainCycle: "running_maincycle",
|
||||||
|
DryerMachineState.RunningPostCycle: "running_postcycle",
|
||||||
|
DryerMachineState.Exceptions: "exception",
|
||||||
|
DryerMachineState.Complete: "complete",
|
||||||
|
DryerMachineState.PowerFailure: "power_failure",
|
||||||
|
DryerMachineState.ServiceDiagnostic: "service_diagnostic_mode",
|
||||||
|
DryerMachineState.FactoryDiagnostic: "factory_diagnostic_mode",
|
||||||
|
DryerMachineState.LifeTest: "life_test",
|
||||||
|
DryerMachineState.CustomerFocusMode: "customer_focus_mode",
|
||||||
|
DryerMachineState.DemoMode: "demo_mode",
|
||||||
|
DryerMachineState.HardStopOrError: "hard_stop_or_error",
|
||||||
|
DryerMachineState.SystemInit: "system_initialize",
|
||||||
|
DryerMachineState.Cancelled: "cancelled",
|
||||||
}
|
}
|
||||||
|
|
||||||
STATE_CYCLE_FILLING = "cycle_filling"
|
STATE_CYCLE_FILLING = "cycle_filling"
|
||||||
@ -64,29 +89,44 @@ STATE_CYCLE_WASHING = "cycle_washing"
|
|||||||
STATE_DOOR_OPEN = "door_open"
|
STATE_DOOR_OPEN = "door_open"
|
||||||
|
|
||||||
|
|
||||||
def washer_dryer_state(washer_dryer: WasherDryer) -> str | None:
|
def washer_state(washer: Washer) -> str | None:
|
||||||
"""Determine correct states for a washer/dryer."""
|
"""Determine correct states for a washer."""
|
||||||
|
|
||||||
if washer_dryer.get_door_open():
|
if washer.get_door_open():
|
||||||
return STATE_DOOR_OPEN
|
return STATE_DOOR_OPEN
|
||||||
|
|
||||||
machine_state = washer_dryer.get_machine_state()
|
machine_state = washer.get_machine_state()
|
||||||
|
|
||||||
if machine_state == MachineState.RunningMainCycle:
|
if machine_state == WasherMachineState.RunningMainCycle:
|
||||||
if washer_dryer.get_cycle_status_filling():
|
if washer.get_cycle_status_filling():
|
||||||
return STATE_CYCLE_FILLING
|
return STATE_CYCLE_FILLING
|
||||||
if washer_dryer.get_cycle_status_rinsing():
|
if washer.get_cycle_status_rinsing():
|
||||||
return STATE_CYCLE_RINSING
|
return STATE_CYCLE_RINSING
|
||||||
if washer_dryer.get_cycle_status_sensing():
|
if washer.get_cycle_status_sensing():
|
||||||
return STATE_CYCLE_SENSING
|
return STATE_CYCLE_SENSING
|
||||||
if washer_dryer.get_cycle_status_soaking():
|
if washer.get_cycle_status_soaking():
|
||||||
return STATE_CYCLE_SOAKING
|
return STATE_CYCLE_SOAKING
|
||||||
if washer_dryer.get_cycle_status_spinning():
|
if washer.get_cycle_status_spinning():
|
||||||
return STATE_CYCLE_SPINNING
|
return STATE_CYCLE_SPINNING
|
||||||
if washer_dryer.get_cycle_status_washing():
|
if washer.get_cycle_status_washing():
|
||||||
return STATE_CYCLE_WASHING
|
return STATE_CYCLE_WASHING
|
||||||
|
|
||||||
return WASHER_DRYER_MACHINE_STATE.get(machine_state)
|
return WASHER_MACHINE_STATE.get(machine_state)
|
||||||
|
|
||||||
|
|
||||||
|
def dryer_state(dryer: Dryer) -> str | None:
|
||||||
|
"""Determine correct states for a dryer."""
|
||||||
|
|
||||||
|
if dryer.get_door_open():
|
||||||
|
return STATE_DOOR_OPEN
|
||||||
|
|
||||||
|
machine_state = dryer.get_machine_state()
|
||||||
|
|
||||||
|
if machine_state == DryerMachineState.RunningMainCycle:
|
||||||
|
if dryer.get_cycle_status_sensing():
|
||||||
|
return STATE_CYCLE_SENSING
|
||||||
|
|
||||||
|
return DRYER_MACHINE_STATE.get(machine_state)
|
||||||
|
|
||||||
|
|
||||||
@dataclass(frozen=True, kw_only=True)
|
@dataclass(frozen=True, kw_only=True)
|
||||||
@ -96,8 +136,8 @@ class WhirlpoolSensorEntityDescription(SensorEntityDescription):
|
|||||||
value_fn: Callable[[Appliance], str | None]
|
value_fn: Callable[[Appliance], str | None]
|
||||||
|
|
||||||
|
|
||||||
WASHER_DRYER_STATE_OPTIONS = [
|
WASHER_STATE_OPTIONS = [
|
||||||
*WASHER_DRYER_MACHINE_STATE.values(),
|
*WASHER_MACHINE_STATE.values(),
|
||||||
STATE_CYCLE_FILLING,
|
STATE_CYCLE_FILLING,
|
||||||
STATE_CYCLE_RINSING,
|
STATE_CYCLE_RINSING,
|
||||||
STATE_CYCLE_SENSING,
|
STATE_CYCLE_SENSING,
|
||||||
@ -107,13 +147,19 @@ WASHER_DRYER_STATE_OPTIONS = [
|
|||||||
STATE_DOOR_OPEN,
|
STATE_DOOR_OPEN,
|
||||||
]
|
]
|
||||||
|
|
||||||
|
DRYER_STATE_OPTIONS = [
|
||||||
|
*DRYER_MACHINE_STATE.values(),
|
||||||
|
STATE_CYCLE_SENSING,
|
||||||
|
STATE_DOOR_OPEN,
|
||||||
|
]
|
||||||
|
|
||||||
WASHER_SENSORS: tuple[WhirlpoolSensorEntityDescription, ...] = (
|
WASHER_SENSORS: tuple[WhirlpoolSensorEntityDescription, ...] = (
|
||||||
WhirlpoolSensorEntityDescription(
|
WhirlpoolSensorEntityDescription(
|
||||||
key="state",
|
key="state",
|
||||||
translation_key="washer_state",
|
translation_key="washer_state",
|
||||||
device_class=SensorDeviceClass.ENUM,
|
device_class=SensorDeviceClass.ENUM,
|
||||||
options=WASHER_DRYER_STATE_OPTIONS,
|
options=WASHER_STATE_OPTIONS,
|
||||||
value_fn=washer_dryer_state,
|
value_fn=washer_state,
|
||||||
),
|
),
|
||||||
WhirlpoolSensorEntityDescription(
|
WhirlpoolSensorEntityDescription(
|
||||||
key="DispenseLevel",
|
key="DispenseLevel",
|
||||||
@ -130,8 +176,8 @@ DRYER_SENSORS: tuple[WhirlpoolSensorEntityDescription, ...] = (
|
|||||||
key="state",
|
key="state",
|
||||||
translation_key="dryer_state",
|
translation_key="dryer_state",
|
||||||
device_class=SensorDeviceClass.ENUM,
|
device_class=SensorDeviceClass.ENUM,
|
||||||
options=WASHER_DRYER_STATE_OPTIONS,
|
options=DRYER_STATE_OPTIONS,
|
||||||
value_fn=washer_dryer_state,
|
value_fn=dryer_state,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -151,24 +197,40 @@ async def async_setup_entry(
|
|||||||
async_add_entities: AddConfigEntryEntitiesCallback,
|
async_add_entities: AddConfigEntryEntitiesCallback,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Config flow entry for Whirlpool sensors."""
|
"""Config flow entry for Whirlpool sensors."""
|
||||||
entities: list = []
|
|
||||||
appliances_manager = config_entry.runtime_data
|
appliances_manager = config_entry.runtime_data
|
||||||
for washer_dryer in appliances_manager.washer_dryers:
|
|
||||||
sensor_descriptions = (
|
|
||||||
DRYER_SENSORS
|
|
||||||
if "dryer" in washer_dryer.appliance_info.data_model.lower()
|
|
||||||
else WASHER_SENSORS
|
|
||||||
)
|
|
||||||
|
|
||||||
entities.extend(
|
washer_sensors = [
|
||||||
WhirlpoolSensor(washer_dryer, description)
|
WhirlpoolSensor(washer, description)
|
||||||
for description in sensor_descriptions
|
for washer in appliances_manager.washers
|
||||||
)
|
for description in WASHER_SENSORS
|
||||||
entities.extend(
|
]
|
||||||
WasherDryerTimeSensor(washer_dryer, description)
|
|
||||||
|
washer_time_sensors = [
|
||||||
|
WasherTimeSensor(washer, description)
|
||||||
|
for washer in appliances_manager.washers
|
||||||
for description in WASHER_DRYER_TIME_SENSORS
|
for description in WASHER_DRYER_TIME_SENSORS
|
||||||
|
]
|
||||||
|
|
||||||
|
dryer_sensors = [
|
||||||
|
WhirlpoolSensor(dryer, description)
|
||||||
|
for dryer in appliances_manager.dryers
|
||||||
|
for description in DRYER_SENSORS
|
||||||
|
]
|
||||||
|
|
||||||
|
dryer_time_sensors = [
|
||||||
|
DryerTimeSensor(dryer, description)
|
||||||
|
for dryer in appliances_manager.dryers
|
||||||
|
for description in WASHER_DRYER_TIME_SENSORS
|
||||||
|
]
|
||||||
|
|
||||||
|
async_add_entities(
|
||||||
|
[
|
||||||
|
*washer_sensors,
|
||||||
|
*washer_time_sensors,
|
||||||
|
*dryer_sensors,
|
||||||
|
*dryer_time_sensors,
|
||||||
|
]
|
||||||
)
|
)
|
||||||
async_add_entities(entities)
|
|
||||||
|
|
||||||
|
|
||||||
class WhirlpoolSensor(WhirlpoolEntity, SensorEntity):
|
class WhirlpoolSensor(WhirlpoolEntity, SensorEntity):
|
||||||
@ -187,22 +249,30 @@ class WhirlpoolSensor(WhirlpoolEntity, SensorEntity):
|
|||||||
return self.entity_description.value_fn(self._appliance)
|
return self.entity_description.value_fn(self._appliance)
|
||||||
|
|
||||||
|
|
||||||
class WasherDryerTimeSensor(WhirlpoolEntity, RestoreSensor):
|
class WasherDryerTimeSensorBase(WhirlpoolEntity, RestoreSensor, ABC):
|
||||||
"""A timestamp class for the Whirlpool washer/dryer."""
|
"""Abstract base class for Whirlpool washer/dryer time sensors."""
|
||||||
|
|
||||||
_attr_should_poll = True
|
_attr_should_poll = True
|
||||||
|
_appliance: Washer | Dryer
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self, washer_dryer: WasherDryer, description: SensorEntityDescription
|
self, appliance: Washer | Dryer, description: SensorEntityDescription
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Initialize the washer sensor."""
|
"""Initialize the washer/dryer sensor."""
|
||||||
super().__init__(washer_dryer, unique_id_suffix=f"-{description.key}")
|
super().__init__(appliance, unique_id_suffix=f"-{description.key}")
|
||||||
self.entity_description = description
|
self.entity_description = description
|
||||||
|
|
||||||
self._wd = washer_dryer
|
|
||||||
self._running: bool | None = None
|
self._running: bool | None = None
|
||||||
self._value: datetime | None = None
|
self._value: datetime | None = None
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def _is_machine_state_finished(self) -> bool:
|
||||||
|
"""Return true if the machine is in a finished state."""
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def _is_machine_state_running(self) -> bool:
|
||||||
|
"""Return true if the machine is in a running state."""
|
||||||
|
|
||||||
async def async_added_to_hass(self) -> None:
|
async def async_added_to_hass(self) -> None:
|
||||||
"""Register attribute updates callback."""
|
"""Register attribute updates callback."""
|
||||||
if restored_data := await self.async_get_last_sensor_data():
|
if restored_data := await self.async_get_last_sensor_data():
|
||||||
@ -212,28 +282,62 @@ class WasherDryerTimeSensor(WhirlpoolEntity, RestoreSensor):
|
|||||||
|
|
||||||
async def async_update(self) -> None:
|
async def async_update(self) -> None:
|
||||||
"""Update status of Whirlpool."""
|
"""Update status of Whirlpool."""
|
||||||
await self._wd.fetch_data()
|
await self._appliance.fetch_data()
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@property
|
@property
|
||||||
def native_value(self) -> datetime | None:
|
def native_value(self) -> datetime | None:
|
||||||
"""Calculate the time stamp for completion."""
|
"""Calculate the time stamp for completion."""
|
||||||
machine_state = self._wd.get_machine_state()
|
|
||||||
now = utcnow()
|
now = utcnow()
|
||||||
if (
|
|
||||||
machine_state.value
|
if self._is_machine_state_finished() and self._running:
|
||||||
in {MachineState.Complete.value, MachineState.Standby.value}
|
|
||||||
and self._running
|
|
||||||
):
|
|
||||||
self._running = False
|
self._running = False
|
||||||
self._value = now
|
self._value = now
|
||||||
|
|
||||||
if machine_state is MachineState.RunningMainCycle:
|
if self._is_machine_state_running():
|
||||||
self._running = True
|
self._running = True
|
||||||
new_timestamp = now + timedelta(seconds=self._wd.get_time_remaining())
|
new_timestamp = now + timedelta(
|
||||||
|
seconds=self._appliance.get_time_remaining()
|
||||||
|
)
|
||||||
if self._value is None or (
|
if self._value is None or (
|
||||||
isinstance(self._value, datetime)
|
isinstance(self._value, datetime)
|
||||||
and abs(new_timestamp - self._value) > timedelta(seconds=60)
|
and abs(new_timestamp - self._value) > timedelta(seconds=60)
|
||||||
):
|
):
|
||||||
self._value = new_timestamp
|
self._value = new_timestamp
|
||||||
return self._value
|
return self._value
|
||||||
|
|
||||||
|
|
||||||
|
class WasherTimeSensor(WasherDryerTimeSensorBase):
|
||||||
|
"""A timestamp class for Whirlpool washers."""
|
||||||
|
|
||||||
|
_appliance: Washer
|
||||||
|
|
||||||
|
def _is_machine_state_finished(self) -> bool:
|
||||||
|
"""Return true if the machine is in a finished state."""
|
||||||
|
return self._appliance.get_machine_state() in {
|
||||||
|
WasherMachineState.Complete,
|
||||||
|
WasherMachineState.Standby,
|
||||||
|
}
|
||||||
|
|
||||||
|
def _is_machine_state_running(self) -> bool:
|
||||||
|
"""Return true if the machine is in a running state."""
|
||||||
|
return (
|
||||||
|
self._appliance.get_machine_state() is WasherMachineState.RunningMainCycle
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class DryerTimeSensor(WasherDryerTimeSensorBase):
|
||||||
|
"""A timestamp class for Whirlpool dryers."""
|
||||||
|
|
||||||
|
_appliance: Dryer
|
||||||
|
|
||||||
|
def _is_machine_state_finished(self) -> bool:
|
||||||
|
"""Return true if the machine is in a finished state."""
|
||||||
|
return self._appliance.get_machine_state() in {
|
||||||
|
DryerMachineState.Complete,
|
||||||
|
DryerMachineState.Standby,
|
||||||
|
}
|
||||||
|
|
||||||
|
def _is_machine_state_running(self) -> bool:
|
||||||
|
"""Return true if the machine is in a running state."""
|
||||||
|
return self._appliance.get_machine_state() is DryerMachineState.RunningMainCycle
|
||||||
|
2
requirements_all.txt
generated
2
requirements_all.txt
generated
@ -3102,7 +3102,7 @@ webmin-xmlrpc==0.0.2
|
|||||||
weheat==2025.6.10
|
weheat==2025.6.10
|
||||||
|
|
||||||
# homeassistant.components.whirlpool
|
# homeassistant.components.whirlpool
|
||||||
whirlpool-sixth-sense==0.20.0
|
whirlpool-sixth-sense==0.21.1
|
||||||
|
|
||||||
# homeassistant.components.whois
|
# homeassistant.components.whois
|
||||||
whois==0.9.27
|
whois==0.9.27
|
||||||
|
2
requirements_test_all.txt
generated
2
requirements_test_all.txt
generated
@ -2555,7 +2555,7 @@ webmin-xmlrpc==0.0.2
|
|||||||
weheat==2025.6.10
|
weheat==2025.6.10
|
||||||
|
|
||||||
# homeassistant.components.whirlpool
|
# homeassistant.components.whirlpool
|
||||||
whirlpool-sixth-sense==0.20.0
|
whirlpool-sixth-sense==0.21.1
|
||||||
|
|
||||||
# homeassistant.components.whois
|
# homeassistant.components.whois
|
||||||
whois==0.9.27
|
whois==0.9.27
|
||||||
|
@ -4,7 +4,7 @@ from unittest import mock
|
|||||||
from unittest.mock import Mock
|
from unittest.mock import Mock
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
from whirlpool import aircon, appliancesmanager, auth, washerdryer
|
from whirlpool import aircon, appliancesmanager, auth, dryer, washer
|
||||||
from whirlpool.backendselector import Brand, Region
|
from whirlpool.backendselector import Brand, Region
|
||||||
|
|
||||||
from .const import MOCK_SAID1, MOCK_SAID2
|
from .const import MOCK_SAID1, MOCK_SAID2
|
||||||
@ -66,10 +66,8 @@ def fixture_mock_appliances_manager_api(
|
|||||||
mock_aircon1_api,
|
mock_aircon1_api,
|
||||||
mock_aircon2_api,
|
mock_aircon2_api,
|
||||||
]
|
]
|
||||||
mock_appliances_manager.return_value.washer_dryers = [
|
mock_appliances_manager.return_value.washers = [mock_washer_api]
|
||||||
mock_washer_api,
|
mock_appliances_manager.return_value.dryers = [mock_dryer_api]
|
||||||
mock_dryer_api,
|
|
||||||
]
|
|
||||||
yield mock_appliances_manager
|
yield mock_appliances_manager
|
||||||
|
|
||||||
|
|
||||||
@ -123,15 +121,13 @@ def fixture_mock_aircon2_api():
|
|||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def mock_washer_api():
|
def mock_washer_api():
|
||||||
"""Get a mock of a washer."""
|
"""Get a mock of a washer."""
|
||||||
mock_washer = Mock(spec=washerdryer.WasherDryer, said="said_washer")
|
mock_washer = Mock(spec=washer.Washer, said="said_washer")
|
||||||
mock_washer.name = "Washer"
|
mock_washer.name = "Washer"
|
||||||
mock_washer.appliance_info = Mock(
|
mock_washer.appliance_info = Mock(
|
||||||
data_model="washer", category="washer_dryer", model_number="12345"
|
data_model="washer", category="washer_dryer", model_number="12345"
|
||||||
)
|
)
|
||||||
mock_washer.get_online.return_value = True
|
mock_washer.get_online.return_value = True
|
||||||
mock_washer.get_machine_state.return_value = (
|
mock_washer.get_machine_state.return_value = washer.MachineState.RunningMainCycle
|
||||||
washerdryer.MachineState.RunningMainCycle
|
|
||||||
)
|
|
||||||
mock_washer.get_door_open.return_value = False
|
mock_washer.get_door_open.return_value = False
|
||||||
mock_washer.get_dispense_1_level.return_value = 3
|
mock_washer.get_dispense_1_level.return_value = 3
|
||||||
mock_washer.get_time_remaining.return_value = 3540
|
mock_washer.get_time_remaining.return_value = 3540
|
||||||
@ -148,21 +144,14 @@ def mock_washer_api():
|
|||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def mock_dryer_api():
|
def mock_dryer_api():
|
||||||
"""Get a mock of a dryer."""
|
"""Get a mock of a dryer."""
|
||||||
mock_dryer = mock.Mock(spec=washerdryer.WasherDryer, said="said_dryer")
|
mock_dryer = mock.Mock(spec=dryer.Dryer, said="said_dryer")
|
||||||
mock_dryer.name = "Dryer"
|
mock_dryer.name = "Dryer"
|
||||||
mock_dryer.appliance_info = Mock(
|
mock_dryer.appliance_info = Mock(
|
||||||
data_model="dryer", category="washer_dryer", model_number="12345"
|
data_model="dryer", category="washer_dryer", model_number="12345"
|
||||||
)
|
)
|
||||||
mock_dryer.get_online.return_value = True
|
mock_dryer.get_online.return_value = True
|
||||||
mock_dryer.get_machine_state.return_value = (
|
mock_dryer.get_machine_state.return_value = dryer.MachineState.RunningMainCycle
|
||||||
washerdryer.MachineState.RunningMainCycle
|
|
||||||
)
|
|
||||||
mock_dryer.get_door_open.return_value = False
|
mock_dryer.get_door_open.return_value = False
|
||||||
mock_dryer.get_time_remaining.return_value = 3540
|
mock_dryer.get_time_remaining.return_value = 3540
|
||||||
mock_dryer.get_cycle_status_filling.return_value = False
|
|
||||||
mock_dryer.get_cycle_status_rinsing.return_value = False
|
|
||||||
mock_dryer.get_cycle_status_sensing.return_value = False
|
mock_dryer.get_cycle_status_sensing.return_value = False
|
||||||
mock_dryer.get_cycle_status_soaking.return_value = False
|
|
||||||
mock_dryer.get_cycle_status_spinning.return_value = False
|
|
||||||
mock_dryer.get_cycle_status_washing.return_value = False
|
|
||||||
return mock_dryer
|
return mock_dryer
|
||||||
|
@ -14,14 +14,16 @@
|
|||||||
'model_number': '12345',
|
'model_number': '12345',
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
'ovens': dict({
|
'dryers': dict({
|
||||||
}),
|
|
||||||
'washer_dryers': dict({
|
|
||||||
'Dryer': dict({
|
'Dryer': dict({
|
||||||
'category': 'washer_dryer',
|
'category': 'washer_dryer',
|
||||||
'data_model': 'dryer',
|
'data_model': 'dryer',
|
||||||
'model_number': '12345',
|
'model_number': '12345',
|
||||||
}),
|
}),
|
||||||
|
}),
|
||||||
|
'ovens': dict({
|
||||||
|
}),
|
||||||
|
'washers': dict({
|
||||||
'Washer': dict({
|
'Washer': dict({
|
||||||
'category': 'washer_dryer',
|
'category': 'washer_dryer',
|
||||||
'data_model': 'washer',
|
'data_model': 'washer',
|
||||||
|
@ -75,12 +75,8 @@
|
|||||||
'demo_mode',
|
'demo_mode',
|
||||||
'hard_stop_or_error',
|
'hard_stop_or_error',
|
||||||
'system_initialize',
|
'system_initialize',
|
||||||
'cycle_filling',
|
'cancelled',
|
||||||
'cycle_rinsing',
|
|
||||||
'cycle_sensing',
|
'cycle_sensing',
|
||||||
'cycle_soaking',
|
|
||||||
'cycle_spinning',
|
|
||||||
'cycle_washing',
|
|
||||||
'door_open',
|
'door_open',
|
||||||
]),
|
]),
|
||||||
}),
|
}),
|
||||||
@ -138,12 +134,8 @@
|
|||||||
'demo_mode',
|
'demo_mode',
|
||||||
'hard_stop_or_error',
|
'hard_stop_or_error',
|
||||||
'system_initialize',
|
'system_initialize',
|
||||||
'cycle_filling',
|
'cancelled',
|
||||||
'cycle_rinsing',
|
|
||||||
'cycle_sensing',
|
'cycle_sensing',
|
||||||
'cycle_soaking',
|
|
||||||
'cycle_spinning',
|
|
||||||
'cycle_washing',
|
|
||||||
'door_open',
|
'door_open',
|
||||||
]),
|
]),
|
||||||
}),
|
}),
|
||||||
|
@ -208,7 +208,8 @@ async def test_no_appliances_flow(
|
|||||||
|
|
||||||
original_aircons = mock_appliances_manager_api.return_value.aircons
|
original_aircons = mock_appliances_manager_api.return_value.aircons
|
||||||
mock_appliances_manager_api.return_value.aircons = []
|
mock_appliances_manager_api.return_value.aircons = []
|
||||||
mock_appliances_manager_api.return_value.washer_dryers = []
|
mock_appliances_manager_api.return_value.washers = []
|
||||||
|
mock_appliances_manager_api.return_value.dryers = []
|
||||||
result = await hass.config_entries.flow.async_configure(
|
result = await hass.config_entries.flow.async_configure(
|
||||||
result["flow_id"], CONFIG_INPUT | {CONF_REGION: region[0], CONF_BRAND: brand[0]}
|
result["flow_id"], CONFIG_INPUT | {CONF_REGION: region[0], CONF_BRAND: brand[0]}
|
||||||
)
|
)
|
||||||
|
@ -80,7 +80,8 @@ async def test_setup_no_appliances(
|
|||||||
) -> None:
|
) -> None:
|
||||||
"""Test setup when there are no appliances available."""
|
"""Test setup when there are no appliances available."""
|
||||||
mock_appliances_manager_api.return_value.aircons = []
|
mock_appliances_manager_api.return_value.aircons = []
|
||||||
mock_appliances_manager_api.return_value.washer_dryers = []
|
mock_appliances_manager_api.return_value.washers = []
|
||||||
|
mock_appliances_manager_api.return_value.dryers = []
|
||||||
await init_integration(hass)
|
await init_integration(hass)
|
||||||
assert len(hass.states.async_all()) == 0
|
assert len(hass.states.async_all()) == 0
|
||||||
|
|
||||||
|
@ -5,7 +5,8 @@ from datetime import UTC, datetime, timedelta
|
|||||||
from freezegun.api import FrozenDateTimeFactory
|
from freezegun.api import FrozenDateTimeFactory
|
||||||
import pytest
|
import pytest
|
||||||
from syrupy.assertion import SnapshotAssertion
|
from syrupy.assertion import SnapshotAssertion
|
||||||
from whirlpool.washerdryer import MachineState
|
from whirlpool.dryer import MachineState as DryerMachineState
|
||||||
|
from whirlpool.washer import MachineState as WasherMachineState
|
||||||
|
|
||||||
from homeassistant.components.whirlpool.sensor import SCAN_INTERVAL
|
from homeassistant.components.whirlpool.sensor import SCAN_INTERVAL
|
||||||
from homeassistant.const import STATE_UNKNOWN, Platform
|
from homeassistant.const import STATE_UNKNOWN, Platform
|
||||||
@ -63,7 +64,7 @@ async def test_washer_dryer_time_sensor(
|
|||||||
)
|
)
|
||||||
|
|
||||||
mock_instance = request.getfixturevalue(mock_fixture)
|
mock_instance = request.getfixturevalue(mock_fixture)
|
||||||
mock_instance.get_machine_state.return_value = MachineState.Pause
|
mock_instance.get_machine_state.return_value = WasherMachineState.Pause
|
||||||
await init_integration(hass)
|
await init_integration(hass)
|
||||||
|
|
||||||
# Test restored state.
|
# Test restored state.
|
||||||
@ -77,7 +78,15 @@ async def test_washer_dryer_time_sensor(
|
|||||||
assert state.state == restored_datetime.isoformat()
|
assert state.state == restored_datetime.isoformat()
|
||||||
|
|
||||||
# Test new time when machine starts a cycle.
|
# Test new time when machine starts a cycle.
|
||||||
mock_instance.get_machine_state.return_value = MachineState.RunningMainCycle
|
if "washer" in entity_id:
|
||||||
|
mock_instance.get_machine_state.return_value = (
|
||||||
|
WasherMachineState.RunningMainCycle
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
mock_instance.get_machine_state.return_value = (
|
||||||
|
DryerMachineState.RunningMainCycle
|
||||||
|
)
|
||||||
|
|
||||||
mock_instance.get_time_remaining.return_value = 60
|
mock_instance.get_time_remaining.return_value = 60
|
||||||
await trigger_attr_callback(hass, mock_instance)
|
await trigger_attr_callback(hass, mock_instance)
|
||||||
|
|
||||||
@ -127,7 +136,10 @@ async def test_washer_dryer_time_sensor_no_restore(
|
|||||||
now = utcnow()
|
now = utcnow()
|
||||||
|
|
||||||
mock_instance = request.getfixturevalue(mock_fixture)
|
mock_instance = request.getfixturevalue(mock_fixture)
|
||||||
mock_instance.get_machine_state.return_value = MachineState.Pause
|
if "washer" in entity_id:
|
||||||
|
mock_instance.get_machine_state.return_value = WasherMachineState.Pause
|
||||||
|
else:
|
||||||
|
mock_instance.get_machine_state.return_value = DryerMachineState.Pause
|
||||||
await init_integration(hass)
|
await init_integration(hass)
|
||||||
|
|
||||||
state = hass.states.get(entity_id)
|
state = hass.states.get(entity_id)
|
||||||
@ -140,7 +152,14 @@ async def test_washer_dryer_time_sensor_no_restore(
|
|||||||
assert state.state == STATE_UNKNOWN
|
assert state.state == STATE_UNKNOWN
|
||||||
|
|
||||||
# Test new time when machine starts a cycle.
|
# Test new time when machine starts a cycle.
|
||||||
mock_instance.get_machine_state.return_value = MachineState.RunningMainCycle
|
if "washer" in entity_id:
|
||||||
|
mock_instance.get_machine_state.return_value = (
|
||||||
|
WasherMachineState.RunningMainCycle
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
mock_instance.get_machine_state.return_value = (
|
||||||
|
DryerMachineState.RunningMainCycle
|
||||||
|
)
|
||||||
mock_instance.get_time_remaining.return_value = 60
|
mock_instance.get_time_remaining.return_value = 60
|
||||||
await trigger_attr_callback(hass, mock_instance)
|
await trigger_attr_callback(hass, mock_instance)
|
||||||
|
|
||||||
@ -149,63 +168,87 @@ async def test_washer_dryer_time_sensor_no_restore(
|
|||||||
assert state.state == expected_time
|
assert state.state == expected_time
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
|
||||||
("entity_id", "mock_fixture"),
|
|
||||||
[
|
|
||||||
("sensor.washer_state", "mock_washer_api"),
|
|
||||||
("sensor.dryer_state", "mock_dryer_api"),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
("machine_state", "expected_state"),
|
("machine_state", "expected_state"),
|
||||||
[
|
[
|
||||||
(MachineState.Standby, "standby"),
|
(WasherMachineState.Standby, "standby"),
|
||||||
(MachineState.Setting, "setting"),
|
(WasherMachineState.Setting, "setting"),
|
||||||
(MachineState.DelayCountdownMode, "delay_countdown"),
|
(WasherMachineState.DelayCountdownMode, "delay_countdown"),
|
||||||
(MachineState.DelayPause, "delay_paused"),
|
(WasherMachineState.DelayPause, "delay_paused"),
|
||||||
(MachineState.SmartDelay, "smart_delay"),
|
(WasherMachineState.SmartDelay, "smart_delay"),
|
||||||
(MachineState.SmartGridPause, "smart_grid_pause"),
|
(WasherMachineState.SmartGridPause, "smart_grid_pause"),
|
||||||
(MachineState.Pause, "pause"),
|
(WasherMachineState.Pause, "pause"),
|
||||||
(MachineState.RunningMainCycle, "running_maincycle"),
|
(WasherMachineState.RunningMainCycle, "running_maincycle"),
|
||||||
(MachineState.RunningPostCycle, "running_postcycle"),
|
(WasherMachineState.RunningPostCycle, "running_postcycle"),
|
||||||
(MachineState.Exceptions, "exception"),
|
(WasherMachineState.Exceptions, "exception"),
|
||||||
(MachineState.Complete, "complete"),
|
(WasherMachineState.Complete, "complete"),
|
||||||
(MachineState.PowerFailure, "power_failure"),
|
(WasherMachineState.PowerFailure, "power_failure"),
|
||||||
(MachineState.ServiceDiagnostic, "service_diagnostic_mode"),
|
(WasherMachineState.ServiceDiagnostic, "service_diagnostic_mode"),
|
||||||
(MachineState.FactoryDiagnostic, "factory_diagnostic_mode"),
|
(WasherMachineState.FactoryDiagnostic, "factory_diagnostic_mode"),
|
||||||
(MachineState.LifeTest, "life_test"),
|
(WasherMachineState.LifeTest, "life_test"),
|
||||||
(MachineState.CustomerFocusMode, "customer_focus_mode"),
|
(WasherMachineState.CustomerFocusMode, "customer_focus_mode"),
|
||||||
(MachineState.DemoMode, "demo_mode"),
|
(WasherMachineState.DemoMode, "demo_mode"),
|
||||||
(MachineState.HardStopOrError, "hard_stop_or_error"),
|
(WasherMachineState.HardStopOrError, "hard_stop_or_error"),
|
||||||
(MachineState.SystemInit, "system_initialize"),
|
(WasherMachineState.SystemInit, "system_initialize"),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
async def test_washer_dryer_machine_states(
|
async def test_washer_machine_states(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
entity_id: str,
|
machine_state: WasherMachineState,
|
||||||
mock_fixture: str,
|
|
||||||
machine_state: MachineState,
|
|
||||||
expected_state: str,
|
expected_state: str,
|
||||||
request: pytest.FixtureRequest,
|
mock_washer_api,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test Washer/Dryer machine states."""
|
"""Test Washer machine states."""
|
||||||
mock_instance = request.getfixturevalue(mock_fixture)
|
|
||||||
await init_integration(hass)
|
await init_integration(hass)
|
||||||
|
|
||||||
mock_instance.get_machine_state.return_value = machine_state
|
mock_washer_api.get_machine_state.return_value = machine_state
|
||||||
await trigger_attr_callback(hass, mock_instance)
|
await trigger_attr_callback(hass, mock_washer_api)
|
||||||
state = hass.states.get(entity_id)
|
state = hass.states.get("sensor.washer_state")
|
||||||
assert state is not None
|
assert state is not None
|
||||||
assert state.state == expected_state
|
assert state.state == expected_state
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
("entity_id", "mock_fixture"),
|
("machine_state", "expected_state"),
|
||||||
[
|
[
|
||||||
("sensor.washer_state", "mock_washer_api"),
|
(DryerMachineState.Standby, "standby"),
|
||||||
("sensor.dryer_state", "mock_dryer_api"),
|
(DryerMachineState.Setting, "setting"),
|
||||||
|
(DryerMachineState.DelayCountdownMode, "delay_countdown"),
|
||||||
|
(DryerMachineState.DelayPause, "delay_paused"),
|
||||||
|
(DryerMachineState.SmartDelay, "smart_delay"),
|
||||||
|
(DryerMachineState.SmartGridPause, "smart_grid_pause"),
|
||||||
|
(DryerMachineState.Pause, "pause"),
|
||||||
|
(DryerMachineState.RunningMainCycle, "running_maincycle"),
|
||||||
|
(DryerMachineState.RunningPostCycle, "running_postcycle"),
|
||||||
|
(DryerMachineState.Exceptions, "exception"),
|
||||||
|
(DryerMachineState.Complete, "complete"),
|
||||||
|
(DryerMachineState.PowerFailure, "power_failure"),
|
||||||
|
(DryerMachineState.ServiceDiagnostic, "service_diagnostic_mode"),
|
||||||
|
(DryerMachineState.FactoryDiagnostic, "factory_diagnostic_mode"),
|
||||||
|
(DryerMachineState.LifeTest, "life_test"),
|
||||||
|
(DryerMachineState.CustomerFocusMode, "customer_focus_mode"),
|
||||||
|
(DryerMachineState.DemoMode, "demo_mode"),
|
||||||
|
(DryerMachineState.HardStopOrError, "hard_stop_or_error"),
|
||||||
|
(DryerMachineState.SystemInit, "system_initialize"),
|
||||||
|
(DryerMachineState.Cancelled, "cancelled"),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
async def test_dryer_machine_states(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
machine_state: DryerMachineState,
|
||||||
|
expected_state: str,
|
||||||
|
mock_dryer_api,
|
||||||
|
) -> None:
|
||||||
|
"""Test Dryer machine states."""
|
||||||
|
await init_integration(hass)
|
||||||
|
|
||||||
|
mock_dryer_api.get_machine_state.return_value = machine_state
|
||||||
|
await trigger_attr_callback(hass, mock_dryer_api)
|
||||||
|
state = hass.states.get("sensor.dryer_state")
|
||||||
|
assert state is not None
|
||||||
|
assert state.state == expected_state
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
(
|
(
|
||||||
"filling",
|
"filling",
|
||||||
@ -225,10 +268,8 @@ async def test_washer_dryer_machine_states(
|
|||||||
(False, False, False, False, False, True, "cycle_washing"),
|
(False, False, False, False, False, True, "cycle_washing"),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
async def test_washer_dryer_running_states(
|
async def test_washer_running_states(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
entity_id: str,
|
|
||||||
mock_fixture: str,
|
|
||||||
filling: bool,
|
filling: bool,
|
||||||
rinsing: bool,
|
rinsing: bool,
|
||||||
sensing: bool,
|
sensing: bool,
|
||||||
@ -236,22 +277,21 @@ async def test_washer_dryer_running_states(
|
|||||||
spinning: bool,
|
spinning: bool,
|
||||||
washing: bool,
|
washing: bool,
|
||||||
expected_state: str,
|
expected_state: str,
|
||||||
request: pytest.FixtureRequest,
|
mock_washer_api,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test Washer/Dryer machine states for RunningMainCycle."""
|
"""Test Washer machine states for RunningMainCycle."""
|
||||||
mock_instance = request.getfixturevalue(mock_fixture)
|
|
||||||
await init_integration(hass)
|
await init_integration(hass)
|
||||||
|
|
||||||
mock_instance.get_machine_state.return_value = MachineState.RunningMainCycle
|
mock_washer_api.get_machine_state.return_value = WasherMachineState.RunningMainCycle
|
||||||
mock_instance.get_cycle_status_filling.return_value = filling
|
mock_washer_api.get_cycle_status_filling.return_value = filling
|
||||||
mock_instance.get_cycle_status_rinsing.return_value = rinsing
|
mock_washer_api.get_cycle_status_rinsing.return_value = rinsing
|
||||||
mock_instance.get_cycle_status_sensing.return_value = sensing
|
mock_washer_api.get_cycle_status_sensing.return_value = sensing
|
||||||
mock_instance.get_cycle_status_soaking.return_value = soaking
|
mock_washer_api.get_cycle_status_soaking.return_value = soaking
|
||||||
mock_instance.get_cycle_status_spinning.return_value = spinning
|
mock_washer_api.get_cycle_status_spinning.return_value = spinning
|
||||||
mock_instance.get_cycle_status_washing.return_value = washing
|
mock_washer_api.get_cycle_status_washing.return_value = washing
|
||||||
|
|
||||||
await trigger_attr_callback(hass, mock_instance)
|
await trigger_attr_callback(hass, mock_washer_api)
|
||||||
state = hass.states.get(entity_id)
|
state = hass.states.get("sensor.washer_state")
|
||||||
assert state is not None
|
assert state is not None
|
||||||
assert state.state == expected_state
|
assert state.state == expected_state
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user