core/tests/components/whirlpool/test_sensor.py

390 lines
12 KiB
Python

"""Test the Whirlpool Sensor domain."""
from datetime import UTC, datetime
from unittest.mock import MagicMock
import pytest
from whirlpool.washerdryer import MachineState
from homeassistant.components.whirlpool.sensor import SCAN_INTERVAL
from homeassistant.core import CoreState, HomeAssistant, State
from homeassistant.helpers import entity_registry as er
from homeassistant.util.dt import as_timestamp, utc_from_timestamp, utcnow
from . import init_integration
from tests.common import async_fire_time_changed, mock_restore_cache_with_extra_data
async def update_sensor_state(
hass: HomeAssistant,
entity_id: str,
mock_sensor_api_instance: MagicMock,
) -> State:
"""Simulate an update trigger from the API."""
for call in mock_sensor_api_instance.register_attr_callback.call_args_list:
update_ha_state_cb = call[0][0]
update_ha_state_cb()
await hass.async_block_till_done()
return hass.states.get(entity_id)
def side_effect_function_open_door(*args, **kwargs):
"""Return correct value for attribute."""
if args[0] == "Cavity_TimeStatusEstTimeRemaining":
return 3540
if args[0] == "Cavity_OpStatusDoorOpen":
return "1"
if args[0] == "WashCavity_OpStatusBulkDispense1Level":
return "3"
return None
async def test_dryer_sensor_values(
hass: HomeAssistant,
mock_sensor_api_instances: MagicMock,
mock_sensor2_api: MagicMock,
entity_registry: er.EntityRegistry,
) -> None:
"""Test the sensor value callbacks."""
hass.set_state(CoreState.not_running)
thetimestamp: datetime = datetime(2022, 11, 29, 00, 00, 00, 00, UTC)
mock_restore_cache_with_extra_data(
hass,
(
(
State(
"sensor.washer_end_time",
"1",
),
{"native_value": thetimestamp, "native_unit_of_measurement": None},
),
(
State("sensor.dryer_end_time", "1"),
{"native_value": thetimestamp, "native_unit_of_measurement": None},
),
),
)
await init_integration(hass)
entity_id = "sensor.dryer_state"
mock_instance = mock_sensor2_api
entry = entity_registry.async_get(entity_id)
assert entry
state = hass.states.get(entity_id)
assert state is not None
assert state.state == "standby"
state = await update_sensor_state(hass, entity_id, mock_instance)
assert state is not None
state_id = f"{entity_id.split('_', maxsplit=1)[0]}_end_time"
state = hass.states.get(state_id)
assert state.state == thetimestamp.isoformat()
mock_instance.get_machine_state.return_value = MachineState.RunningMainCycle
mock_instance.get_cycle_status_filling.return_value = False
mock_instance.attr_value_to_bool.side_effect = [
False,
False,
False,
False,
False,
False,
]
state = await update_sensor_state(hass, entity_id, mock_instance)
assert state is not None
assert state.state == "running_maincycle"
mock_instance.get_machine_state.return_value = MachineState.Complete
state = await update_sensor_state(hass, entity_id, mock_instance)
assert state is not None
assert state.state == "complete"
async def test_washer_sensor_values(
hass: HomeAssistant,
mock_sensor_api_instances: MagicMock,
mock_sensor1_api: MagicMock,
entity_registry: er.EntityRegistry,
) -> None:
"""Test the sensor value callbacks."""
hass.set_state(CoreState.not_running)
thetimestamp: datetime = datetime(2022, 11, 29, 00, 00, 00, 00, UTC)
mock_restore_cache_with_extra_data(
hass,
(
(
State(
"sensor.washer_end_time",
"1",
),
{"native_value": thetimestamp, "native_unit_of_measurement": None},
),
(
State("sensor.dryer_end_time", "1"),
{"native_value": thetimestamp, "native_unit_of_measurement": None},
),
),
)
await init_integration(hass)
async_fire_time_changed(
hass,
utcnow() + SCAN_INTERVAL,
)
await hass.async_block_till_done()
entity_id = "sensor.washer_state"
mock_instance = mock_sensor1_api
entry = entity_registry.async_get(entity_id)
assert entry
state = hass.states.get(entity_id)
assert state is not None
assert state.state == "standby"
state = await update_sensor_state(hass, entity_id, mock_instance)
assert state is not None
state_id = f"{entity_id.split('_', maxsplit=1)[0]}_end_time"
state = hass.states.get(state_id)
assert state.state == thetimestamp.isoformat()
state_id = f"{entity_id.split('_', maxsplit=1)[0]}_detergent_level"
entry = entity_registry.async_get(state_id)
assert entry
assert entry.disabled
assert entry.disabled_by is er.RegistryEntryDisabler.INTEGRATION
update_entry = entity_registry.async_update_entity(
entry.entity_id, disabled_by=None
)
await hass.async_block_till_done()
assert update_entry != entry
assert update_entry.disabled is False
state = hass.states.get(state_id)
assert state is None
await hass.config_entries.async_reload(entry.config_entry_id)
state = hass.states.get(state_id)
assert state is not None
assert state.state == "50"
# Test the washer cycle states
mock_instance.get_machine_state.return_value = MachineState.RunningMainCycle
mock_instance.get_cycle_status_filling.return_value = True
mock_instance.attr_value_to_bool.side_effect = [
True,
False,
False,
False,
False,
False,
]
state = await update_sensor_state(hass, entity_id, mock_instance)
assert state is not None
assert state.state == "cycle_filling"
mock_instance.get_cycle_status_filling.return_value = False
mock_instance.get_cycle_status_rinsing.return_value = True
mock_instance.attr_value_to_bool.side_effect = [
False,
True,
False,
False,
False,
False,
]
state = await update_sensor_state(hass, entity_id, mock_instance)
assert state is not None
assert state.state == "cycle_rinsing"
mock_instance.get_cycle_status_rinsing.return_value = False
mock_instance.get_cycle_status_sensing.return_value = True
mock_instance.attr_value_to_bool.side_effect = [
False,
False,
True,
False,
False,
False,
]
state = await update_sensor_state(hass, entity_id, mock_instance)
assert state is not None
assert state.state == "cycle_sensing"
mock_instance.get_cycle_status_sensing.return_value = False
mock_instance.get_cycle_status_soaking.return_value = True
mock_instance.attr_value_to_bool.side_effect = [
False,
False,
False,
True,
False,
False,
]
state = await update_sensor_state(hass, entity_id, mock_instance)
assert state is not None
assert state.state == "cycle_soaking"
mock_instance.get_cycle_status_soaking.return_value = False
mock_instance.get_cycle_status_spinning.return_value = True
mock_instance.attr_value_to_bool.side_effect = [
False,
False,
False,
False,
True,
False,
]
state = await update_sensor_state(hass, entity_id, mock_instance)
assert state is not None
assert state.state == "cycle_spinning"
mock_instance.get_cycle_status_spinning.return_value = False
mock_instance.get_cycle_status_washing.return_value = True
mock_instance.attr_value_to_bool.side_effect = [
False,
False,
False,
False,
False,
True,
]
state = await update_sensor_state(hass, entity_id, mock_instance)
assert state is not None
assert state.state == "cycle_washing"
mock_instance.get_machine_state.return_value = MachineState.Complete
mock_instance.attr_value_to_bool.side_effect = None
mock_instance.get_attribute.side_effect = side_effect_function_open_door
state = await update_sensor_state(hass, entity_id, mock_instance)
assert state is not None
assert state.state == "door_open"
async def test_restore_state(
hass: HomeAssistant,
mock_sensor_api_instances: MagicMock,
) -> None:
"""Test sensor restore state."""
# Home assistant is not running yet
hass.set_state(CoreState.not_running)
thetimestamp: datetime = datetime(2022, 11, 29, 00, 00, 00, 00, UTC)
mock_restore_cache_with_extra_data(
hass,
(
(
State(
"sensor.washer_end_time",
"1",
),
{"native_value": thetimestamp, "native_unit_of_measurement": None},
),
(
State("sensor.dryer_end_time", "1"),
{"native_value": thetimestamp, "native_unit_of_measurement": None},
),
),
)
# create and add entry
await init_integration(hass)
# restore from cache
state = hass.states.get("sensor.washer_end_time")
assert state.state == thetimestamp.isoformat()
state = hass.states.get("sensor.dryer_end_time")
assert state.state == thetimestamp.isoformat()
async def test_no_restore_state(
hass: HomeAssistant,
mock_sensor_api_instances: MagicMock,
mock_sensor1_api: MagicMock,
) -> None:
"""Test sensor restore state with no restore."""
# create and add entry
entity_id = "sensor.washer_end_time"
await init_integration(hass)
# restore from cache
state = hass.states.get(entity_id)
assert state.state == "unknown"
mock_sensor1_api.get_machine_state.return_value = MachineState.RunningMainCycle
state = await update_sensor_state(hass, entity_id, mock_sensor1_api)
assert state.state != "unknown"
@pytest.mark.freeze_time("2022-11-30 00:00:00")
async def test_callback(
hass: HomeAssistant,
mock_sensor_api_instances: MagicMock,
mock_sensor1_api: MagicMock,
) -> None:
"""Test callback timestamp callback function."""
hass.set_state(CoreState.not_running)
thetimestamp: datetime = datetime(2022, 11, 29, 00, 00, 00, 00, UTC)
mock_restore_cache_with_extra_data(
hass,
(
(
State(
"sensor.washer_end_time",
"1",
),
{"native_value": thetimestamp, "native_unit_of_measurement": None},
),
(
State("sensor.dryer_end_time", "1"),
{"native_value": thetimestamp, "native_unit_of_measurement": None},
),
),
)
# create and add entry
await init_integration(hass)
# restore from cache
state = hass.states.get("sensor.washer_end_time")
assert state.state == thetimestamp.isoformat()
callback = mock_sensor1_api.register_attr_callback.call_args_list[1][0][0]
callback()
state = hass.states.get("sensor.washer_end_time")
assert state.state == thetimestamp.isoformat()
mock_sensor1_api.get_machine_state.return_value = MachineState.RunningMainCycle
mock_sensor1_api.get_attribute.side_effect = None
mock_sensor1_api.get_attribute.return_value = "60"
callback()
# Test new timestamp when machine starts a cycle.
state = hass.states.get("sensor.washer_end_time")
time = state.state
assert state.state != thetimestamp.isoformat()
# Test no timestamp change for < 60 seconds time change.
mock_sensor1_api.get_attribute.return_value = "65"
callback()
state = hass.states.get("sensor.washer_end_time")
assert state.state == time
# Test timestamp change for > 60 seconds.
mock_sensor1_api.get_attribute.return_value = "125"
callback()
state = hass.states.get("sensor.washer_end_time")
newtime = utc_from_timestamp(as_timestamp(time) + 65)
assert state.state == newtime.isoformat()