mirror of
https://github.com/home-assistant/core.git
synced 2025-11-08 02:19:31 +00:00
Co-authored-by: Erik Montnemery <erik@montnemery.com> Co-authored-by: Marc Mueller <30130371+cdce8p@users.noreply.github.com>
682 lines
29 KiB
Python
682 lines
29 KiB
Python
"""Tests for miele sensor module."""
|
|
|
|
from datetime import timedelta
|
|
from unittest.mock import MagicMock
|
|
|
|
from freezegun.api import FrozenDateTimeFactory
|
|
from pymiele import MieleDevices
|
|
import pytest
|
|
from syrupy.assertion import SnapshotAssertion
|
|
|
|
from homeassistant.components.miele.const import DOMAIN
|
|
from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN
|
|
from homeassistant.const import STATE_UNAVAILABLE, STATE_UNKNOWN
|
|
from homeassistant.core import HomeAssistant, State
|
|
from homeassistant.helpers import entity_registry as er
|
|
|
|
from tests.common import (
|
|
MockConfigEntry,
|
|
async_fire_time_changed,
|
|
async_load_json_object_fixture,
|
|
mock_restore_cache_with_extra_data,
|
|
snapshot_platform,
|
|
)
|
|
|
|
|
|
@pytest.mark.parametrize("platforms", [(SENSOR_DOMAIN,)])
|
|
@pytest.mark.usefixtures("entity_registry_enabled_by_default")
|
|
async def test_sensor_states(
|
|
hass: HomeAssistant,
|
|
mock_miele_client: MagicMock,
|
|
snapshot: SnapshotAssertion,
|
|
entity_registry: er.EntityRegistry,
|
|
setup_platform: MockConfigEntry,
|
|
) -> None:
|
|
"""Test sensor state after polling the API for data."""
|
|
|
|
await snapshot_platform(hass, entity_registry, snapshot, setup_platform.entry_id)
|
|
|
|
|
|
@pytest.mark.parametrize("platforms", [(SENSOR_DOMAIN,)])
|
|
@pytest.mark.usefixtures("entity_registry_enabled_by_default")
|
|
async def test_sensor_states_api_push(
|
|
hass: HomeAssistant,
|
|
mock_miele_client: MagicMock,
|
|
snapshot: SnapshotAssertion,
|
|
entity_registry: er.EntityRegistry,
|
|
setup_platform: MockConfigEntry,
|
|
push_data_and_actions: None,
|
|
) -> None:
|
|
"""Test sensor state when the API pushes data via SSE."""
|
|
|
|
await snapshot_platform(hass, entity_registry, snapshot, setup_platform.entry_id)
|
|
|
|
|
|
@pytest.mark.parametrize("load_device_file", ["hob.json"])
|
|
@pytest.mark.parametrize("platforms", [(SENSOR_DOMAIN,)])
|
|
@pytest.mark.usefixtures("entity_registry_enabled_by_default")
|
|
async def test_hob_sensor_states(
|
|
hass: HomeAssistant,
|
|
mock_miele_client: MagicMock,
|
|
snapshot: SnapshotAssertion,
|
|
entity_registry: er.EntityRegistry,
|
|
setup_platform: None,
|
|
) -> None:
|
|
"""Test sensor state."""
|
|
|
|
await snapshot_platform(hass, entity_registry, snapshot, setup_platform.entry_id)
|
|
|
|
|
|
@pytest.mark.parametrize("load_device_file", ["fridge_freezer.json"])
|
|
@pytest.mark.parametrize("platforms", [(SENSOR_DOMAIN,)])
|
|
@pytest.mark.usefixtures("entity_registry_enabled_by_default")
|
|
async def test_fridge_freezer_sensor_states(
|
|
hass: HomeAssistant,
|
|
mock_miele_client: MagicMock,
|
|
snapshot: SnapshotAssertion,
|
|
entity_registry: er.EntityRegistry,
|
|
setup_platform: None,
|
|
) -> None:
|
|
"""Test sensor state."""
|
|
|
|
await snapshot_platform(hass, entity_registry, snapshot, setup_platform.entry_id)
|
|
|
|
|
|
@pytest.mark.parametrize("load_device_file", ["oven.json"])
|
|
@pytest.mark.parametrize("platforms", [(SENSOR_DOMAIN,)])
|
|
async def test_oven_temperatures_scenario(
|
|
hass: HomeAssistant,
|
|
mock_miele_client: MagicMock,
|
|
setup_platform: None,
|
|
mock_config_entry: MockConfigEntry,
|
|
device_fixture: MieleDevices,
|
|
freezer: FrozenDateTimeFactory,
|
|
) -> None:
|
|
"""Parametrized test for verifying temperature sensors for oven devices."""
|
|
|
|
# Initial state when the oven is and created for the first time - don't know if it supports core temperature (probe)
|
|
check_sensor_state(hass, "sensor.oven_temperature", "unknown", 0)
|
|
check_sensor_state(hass, "sensor.oven_target_temperature", "unknown", 0)
|
|
check_sensor_state(hass, "sensor.oven_core_temperature", None, 0)
|
|
check_sensor_state(hass, "sensor.oven_core_target_temperature", None, 0)
|
|
|
|
# Simulate temperature settings, no probe temperature
|
|
device_fixture["DummyOven"]["state"]["targetTemperature"][0]["value_raw"] = 8000
|
|
device_fixture["DummyOven"]["state"]["targetTemperature"][0]["value_localized"] = (
|
|
80.0
|
|
)
|
|
device_fixture["DummyOven"]["state"]["temperature"][0]["value_raw"] = 2150
|
|
device_fixture["DummyOven"]["state"]["temperature"][0]["value_localized"] = 21.5
|
|
|
|
freezer.tick(timedelta(seconds=130))
|
|
async_fire_time_changed(hass)
|
|
await hass.async_block_till_done()
|
|
|
|
check_sensor_state(hass, "sensor.oven_temperature", "21.5", 1)
|
|
check_sensor_state(hass, "sensor.oven_target_temperature", "80.0", 1)
|
|
check_sensor_state(hass, "sensor.oven_core_temperature", None, 1)
|
|
check_sensor_state(hass, "sensor.oven_core_target_temperature", None, 1)
|
|
|
|
# Simulate unsetting temperature
|
|
device_fixture["DummyOven"]["state"]["targetTemperature"][0]["value_raw"] = -32768
|
|
device_fixture["DummyOven"]["state"]["targetTemperature"][0]["value_localized"] = (
|
|
None
|
|
)
|
|
device_fixture["DummyOven"]["state"]["temperature"][0]["value_raw"] = -32768
|
|
device_fixture["DummyOven"]["state"]["temperature"][0]["value_localized"] = None
|
|
|
|
freezer.tick(timedelta(seconds=130))
|
|
async_fire_time_changed(hass)
|
|
await hass.async_block_till_done()
|
|
|
|
check_sensor_state(hass, "sensor.oven_temperature", "unknown", 2)
|
|
check_sensor_state(hass, "sensor.oven_target_temperature", "unknown", 2)
|
|
check_sensor_state(hass, "sensor.oven_core_temperature", None, 2)
|
|
check_sensor_state(hass, "sensor.oven_core_target_temperature", None, 2)
|
|
|
|
# Simulate temperature settings with probe temperature
|
|
device_fixture["DummyOven"]["state"]["targetTemperature"][0]["value_raw"] = 8000
|
|
device_fixture["DummyOven"]["state"]["targetTemperature"][0]["value_localized"] = (
|
|
80.0
|
|
)
|
|
device_fixture["DummyOven"]["state"]["coreTargetTemperature"][0]["value_raw"] = 3000
|
|
device_fixture["DummyOven"]["state"]["coreTargetTemperature"][0][
|
|
"value_localized"
|
|
] = 30.0
|
|
device_fixture["DummyOven"]["state"]["temperature"][0]["value_raw"] = 2183
|
|
device_fixture["DummyOven"]["state"]["temperature"][0]["value_localized"] = 21.83
|
|
device_fixture["DummyOven"]["state"]["coreTemperature"][0]["value_raw"] = 2200
|
|
device_fixture["DummyOven"]["state"]["coreTemperature"][0]["value_localized"] = 22.0
|
|
|
|
freezer.tick(timedelta(seconds=130))
|
|
async_fire_time_changed(hass)
|
|
await hass.async_block_till_done()
|
|
|
|
check_sensor_state(hass, "sensor.oven_temperature", "21.83", 3)
|
|
check_sensor_state(hass, "sensor.oven_target_temperature", "80.0", 3)
|
|
check_sensor_state(hass, "sensor.oven_core_temperature", "22.0", 2)
|
|
check_sensor_state(hass, "sensor.oven_core_target_temperature", "30.0", 3)
|
|
|
|
# Simulate unsetting temperature
|
|
device_fixture["DummyOven"]["state"]["targetTemperature"][0]["value_raw"] = -32768
|
|
device_fixture["DummyOven"]["state"]["targetTemperature"][0]["value_localized"] = (
|
|
None
|
|
)
|
|
device_fixture["DummyOven"]["state"]["coreTargetTemperature"][0][
|
|
"value_raw"
|
|
] = -32768
|
|
device_fixture["DummyOven"]["state"]["coreTargetTemperature"][0][
|
|
"value_localized"
|
|
] = None
|
|
device_fixture["DummyOven"]["state"]["temperature"][0]["value_raw"] = -32768
|
|
device_fixture["DummyOven"]["state"]["temperature"][0]["value_localized"] = None
|
|
device_fixture["DummyOven"]["state"]["coreTemperature"][0]["value_raw"] = -32768
|
|
device_fixture["DummyOven"]["state"]["coreTemperature"][0]["value_localized"] = None
|
|
|
|
freezer.tick(timedelta(seconds=130))
|
|
async_fire_time_changed(hass)
|
|
await hass.async_block_till_done()
|
|
|
|
check_sensor_state(hass, "sensor.oven_temperature", "unknown", 4)
|
|
check_sensor_state(hass, "sensor.oven_target_temperature", "unknown", 4)
|
|
check_sensor_state(hass, "sensor.oven_core_temperature", "unknown", 4)
|
|
check_sensor_state(hass, "sensor.oven_core_target_temperature", "unknown", 4)
|
|
|
|
|
|
def check_sensor_state(
|
|
hass: HomeAssistant,
|
|
sensor_entity: str,
|
|
expected: str,
|
|
step: int,
|
|
):
|
|
"""Check the state of sensor matches the expected state."""
|
|
|
|
state = hass.states.get(sensor_entity)
|
|
|
|
if expected is None:
|
|
assert state is None, (
|
|
f"[{sensor_entity}] Step {step + 1}: got {state.state}, expected nothing"
|
|
)
|
|
else:
|
|
assert state is not None, f"Missing entity: {sensor_entity}"
|
|
assert state.state == expected, (
|
|
f"[{sensor_entity}] Step {step + 1}: got {state.state}, expected {expected}"
|
|
)
|
|
|
|
|
|
@pytest.mark.parametrize("load_device_file", ["oven.json"])
|
|
@pytest.mark.parametrize("platforms", [(SENSOR_DOMAIN,)])
|
|
async def test_temperature_sensor_registry_lookup(
|
|
hass: HomeAssistant,
|
|
mock_config_entry: MockConfigEntry,
|
|
mock_miele_client: MagicMock,
|
|
setup_platform: None,
|
|
device_fixture: MieleDevices,
|
|
freezer: FrozenDateTimeFactory,
|
|
) -> None:
|
|
"""Test that core temperature sensor is provided by the integration after looking up in entity registry."""
|
|
|
|
# Initial state, the oven is showing core temperature (probe)
|
|
freezer.tick(timedelta(seconds=130))
|
|
device_fixture["DummyOven"]["state"]["coreTemperature"][0]["value_raw"] = 2200
|
|
device_fixture["DummyOven"]["state"]["coreTemperature"][0]["value_localized"] = 22.0
|
|
async_fire_time_changed(hass)
|
|
await hass.async_block_till_done()
|
|
|
|
entity_id = "sensor.oven_core_temperature"
|
|
|
|
assert hass.states.get(entity_id) is not None
|
|
assert hass.states.get(entity_id).state == "22.0"
|
|
|
|
# reload device when turned off, reporting the invalid value
|
|
mock_miele_client.get_devices.return_value = await async_load_json_object_fixture(
|
|
hass, "oven.json", DOMAIN
|
|
)
|
|
|
|
# unload config entry and reload to make sure that the entity is still provided
|
|
await hass.config_entries.async_unload(mock_config_entry.entry_id)
|
|
await hass.async_block_till_done()
|
|
|
|
assert hass.states.get(entity_id).state == "unavailable"
|
|
|
|
await hass.config_entries.async_reload(mock_config_entry.entry_id)
|
|
await hass.async_block_till_done()
|
|
assert hass.states.get(entity_id).state == "unknown"
|
|
|
|
|
|
@pytest.mark.parametrize("load_device_file", ["vacuum_device.json"])
|
|
@pytest.mark.parametrize("platforms", [(SENSOR_DOMAIN,)])
|
|
@pytest.mark.usefixtures("entity_registry_enabled_by_default")
|
|
async def test_vacuum_sensor_states(
|
|
hass: HomeAssistant,
|
|
mock_miele_client: MagicMock,
|
|
snapshot: SnapshotAssertion,
|
|
entity_registry: er.EntityRegistry,
|
|
setup_platform: None,
|
|
) -> None:
|
|
"""Test robot vacuum cleaner sensor state."""
|
|
|
|
await snapshot_platform(hass, entity_registry, snapshot, setup_platform.entry_id)
|
|
|
|
|
|
@pytest.mark.parametrize("load_device_file", ["fan_devices.json"])
|
|
@pytest.mark.parametrize("platforms", [(SENSOR_DOMAIN,)])
|
|
@pytest.mark.usefixtures("entity_registry_enabled_by_default")
|
|
async def test_fan_hob_sensor_states(
|
|
hass: HomeAssistant,
|
|
mock_miele_client: MagicMock,
|
|
snapshot: SnapshotAssertion,
|
|
entity_registry: er.EntityRegistry,
|
|
setup_platform: None,
|
|
) -> None:
|
|
"""Test robot fan / hob sensor state."""
|
|
|
|
await snapshot_platform(hass, entity_registry, snapshot, setup_platform.entry_id)
|
|
|
|
|
|
@pytest.mark.parametrize("load_device_file", ["coffee_system.json"])
|
|
@pytest.mark.parametrize("platforms", [(SENSOR_DOMAIN,)])
|
|
@pytest.mark.usefixtures("entity_registry_enabled_by_default")
|
|
async def test_coffee_system_sensor_states(
|
|
hass: HomeAssistant,
|
|
mock_miele_client: MagicMock,
|
|
snapshot: SnapshotAssertion,
|
|
entity_registry: er.EntityRegistry,
|
|
setup_platform: None,
|
|
) -> None:
|
|
"""Test coffee system sensor state."""
|
|
|
|
await snapshot_platform(hass, entity_registry, snapshot, setup_platform.entry_id)
|
|
|
|
|
|
@pytest.mark.parametrize("load_device_file", ["laundry.json"])
|
|
@pytest.mark.parametrize("platforms", [(SENSOR_DOMAIN,)])
|
|
async def test_laundry_wash_scenario(
|
|
hass: HomeAssistant,
|
|
mock_miele_client: MagicMock,
|
|
setup_platform: None,
|
|
mock_config_entry: MockConfigEntry,
|
|
device_fixture: MieleDevices,
|
|
freezer: FrozenDateTimeFactory,
|
|
) -> None:
|
|
"""Parametrized test for verifying time sensors for wahsing machine devices when API glitches at program end."""
|
|
|
|
step = 0
|
|
|
|
# Initial state when the washing machine is off
|
|
check_sensor_state(hass, "sensor.washing_machine", "off", step)
|
|
check_sensor_state(hass, "sensor.washing_machine_program", "no_program", step)
|
|
check_sensor_state(
|
|
hass, "sensor.washing_machine_program_phase", "not_running", step
|
|
)
|
|
check_sensor_state(
|
|
hass, "sensor.washing_machine_target_temperature", "unknown", step
|
|
)
|
|
check_sensor_state(hass, "sensor.washing_machine_spin_speed", "unknown", step)
|
|
# OFF -> remaining forced to unknown
|
|
check_sensor_state(hass, "sensor.washing_machine_remaining_time", "unknown", step)
|
|
# OFF -> elapsed forced to unknown (some devices continue reporting last value of last cycle)
|
|
check_sensor_state(hass, "sensor.washing_machine_elapsed_time", "unknown", step)
|
|
# consumption sensors have to report "unknown" when the device is not working
|
|
check_sensor_state(
|
|
hass, "sensor.washing_machine_energy_consumption", "unknown", step
|
|
)
|
|
check_sensor_state(
|
|
hass, "sensor.washing_machine_water_consumption", "unknown", step
|
|
)
|
|
|
|
# Simulate program started
|
|
device_fixture["DummyWasher"]["state"]["status"]["value_raw"] = 5
|
|
device_fixture["DummyWasher"]["state"]["status"]["value_localized"] = "In use"
|
|
device_fixture["DummyWasher"]["state"]["ProgramID"]["value_raw"] = 3
|
|
device_fixture["DummyWasher"]["state"]["ProgramID"]["value_localized"] = (
|
|
"Minimum iron"
|
|
)
|
|
device_fixture["DummyWasher"]["state"]["programPhase"]["value_raw"] = 260
|
|
device_fixture["DummyWasher"]["state"]["programPhase"]["value_localized"] = (
|
|
"Main wash"
|
|
)
|
|
device_fixture["DummyWasher"]["state"]["remainingTime"][0] = 1
|
|
device_fixture["DummyWasher"]["state"]["remainingTime"][1] = 45
|
|
device_fixture["DummyWasher"]["state"]["targetTemperature"][0]["value_raw"] = 3000
|
|
device_fixture["DummyWasher"]["state"]["targetTemperature"][0][
|
|
"value_localized"
|
|
] = 30.0
|
|
device_fixture["DummyWasher"]["state"]["elapsedTime"][0] = 0
|
|
device_fixture["DummyWasher"]["state"]["elapsedTime"][1] = 12
|
|
device_fixture["DummyWasher"]["state"]["spinningSpeed"]["value_raw"] = 1200
|
|
device_fixture["DummyWasher"]["state"]["spinningSpeed"]["value_localized"] = "1200"
|
|
device_fixture["DummyWasher"]["state"]["ecoFeedback"] = {
|
|
"currentEnergyConsumption": {
|
|
"value": 0.9,
|
|
"unit": "kWh",
|
|
},
|
|
"currentWaterConsumption": {
|
|
"value": 52,
|
|
"unit": "l",
|
|
},
|
|
}
|
|
|
|
freezer.tick(timedelta(seconds=130))
|
|
async_fire_time_changed(hass)
|
|
await hass.async_block_till_done()
|
|
|
|
# at this point, appliance is working, but it started reporting a value from last cycle, so it is forced to 0
|
|
check_sensor_state(hass, "sensor.washing_machine_energy_consumption", "0", step)
|
|
check_sensor_state(hass, "sensor.washing_machine_water_consumption", "0", step)
|
|
|
|
# intermediate step, only to report new consumption values
|
|
device_fixture["DummyWasher"]["state"]["ecoFeedback"] = {
|
|
"currentEnergyConsumption": {
|
|
"value": 0.0,
|
|
"unit": "kWh",
|
|
},
|
|
"currentWaterConsumption": {
|
|
"value": 0,
|
|
"unit": "l",
|
|
},
|
|
}
|
|
|
|
freezer.tick(timedelta(seconds=130))
|
|
async_fire_time_changed(hass)
|
|
await hass.async_block_till_done()
|
|
|
|
step += 1
|
|
|
|
check_sensor_state(hass, "sensor.washing_machine", "in_use", step)
|
|
check_sensor_state(hass, "sensor.washing_machine_program", "minimum_iron", step)
|
|
check_sensor_state(hass, "sensor.washing_machine_program_phase", "main_wash", step)
|
|
check_sensor_state(hass, "sensor.washing_machine_target_temperature", "30.0", step)
|
|
check_sensor_state(hass, "sensor.washing_machine_spin_speed", "1200", step)
|
|
# IN_USE -> elapsed, remaining time from API (normal case)
|
|
check_sensor_state(hass, "sensor.washing_machine_remaining_time", "105", step)
|
|
check_sensor_state(hass, "sensor.washing_machine_elapsed_time", "12", step)
|
|
check_sensor_state(hass, "sensor.washing_machine_energy_consumption", "0.0", step)
|
|
check_sensor_state(hass, "sensor.washing_machine_water_consumption", "0", step)
|
|
|
|
# intermediate step, only to report new consumption values
|
|
device_fixture["DummyWasher"]["state"]["ecoFeedback"] = {
|
|
"currentEnergyConsumption": {
|
|
"value": 0.1,
|
|
"unit": "kWh",
|
|
},
|
|
"currentWaterConsumption": {
|
|
"value": 7,
|
|
"unit": "l",
|
|
},
|
|
}
|
|
|
|
freezer.tick(timedelta(seconds=130))
|
|
async_fire_time_changed(hass)
|
|
await hass.async_block_till_done()
|
|
|
|
# at this point, it starts reporting value from API
|
|
check_sensor_state(hass, "sensor.washing_machine_energy_consumption", "0.1", step)
|
|
check_sensor_state(hass, "sensor.washing_machine_water_consumption", "7", step)
|
|
|
|
# Simulate rinse hold phase
|
|
device_fixture["DummyWasher"]["state"]["status"]["value_raw"] = 11
|
|
device_fixture["DummyWasher"]["state"]["status"]["value_localized"] = "Rinse hold"
|
|
device_fixture["DummyWasher"]["state"]["programPhase"]["value_raw"] = 262
|
|
device_fixture["DummyWasher"]["state"]["programPhase"]["value_localized"] = (
|
|
"Rinse hold"
|
|
)
|
|
device_fixture["DummyWasher"]["state"]["remainingTime"][0] = 0
|
|
device_fixture["DummyWasher"]["state"]["remainingTime"][1] = 8
|
|
device_fixture["DummyWasher"]["state"]["elapsedTime"][0] = 1
|
|
device_fixture["DummyWasher"]["state"]["elapsedTime"][1] = 49
|
|
|
|
freezer.tick(timedelta(seconds=130))
|
|
async_fire_time_changed(hass)
|
|
await hass.async_block_till_done()
|
|
step += 1
|
|
|
|
check_sensor_state(hass, "sensor.washing_machine", "rinse_hold", step)
|
|
check_sensor_state(hass, "sensor.washing_machine_program", "minimum_iron", step)
|
|
check_sensor_state(hass, "sensor.washing_machine_program_phase", "rinse_hold", step)
|
|
check_sensor_state(hass, "sensor.washing_machine_target_temperature", "30.0", step)
|
|
check_sensor_state(hass, "sensor.washing_machine_spin_speed", "1200", step)
|
|
# RINSE HOLD -> elapsed, remaining time from API (normal case)
|
|
check_sensor_state(hass, "sensor.washing_machine_remaining_time", "8", step)
|
|
check_sensor_state(hass, "sensor.washing_machine_elapsed_time", "109", step)
|
|
|
|
# Simulate program ended
|
|
device_fixture["DummyWasher"]["state"]["status"]["value_raw"] = 7
|
|
device_fixture["DummyWasher"]["state"]["status"]["value_localized"] = "Finished"
|
|
device_fixture["DummyWasher"]["state"]["programPhase"]["value_raw"] = 267
|
|
device_fixture["DummyWasher"]["state"]["programPhase"]["value_localized"] = (
|
|
"Anti-crease"
|
|
)
|
|
device_fixture["DummyWasher"]["state"]["remainingTime"][0] = 0
|
|
device_fixture["DummyWasher"]["state"]["remainingTime"][1] = 0
|
|
device_fixture["DummyWasher"]["state"]["elapsedTime"][0] = 0
|
|
device_fixture["DummyWasher"]["state"]["elapsedTime"][1] = 0
|
|
device_fixture["DummyWasher"]["state"]["ecoFeedback"] = None
|
|
|
|
freezer.tick(timedelta(seconds=130))
|
|
async_fire_time_changed(hass)
|
|
await hass.async_block_till_done()
|
|
step += 1
|
|
|
|
check_sensor_state(hass, "sensor.washing_machine", "program_ended", step)
|
|
check_sensor_state(hass, "sensor.washing_machine_program", "minimum_iron", step)
|
|
check_sensor_state(
|
|
hass, "sensor.washing_machine_program_phase", "anti_crease", step
|
|
)
|
|
check_sensor_state(hass, "sensor.washing_machine_target_temperature", "30.0", step)
|
|
check_sensor_state(hass, "sensor.washing_machine_spin_speed", "1200", step)
|
|
# PROGRAM_ENDED -> remaining time forced to 0
|
|
check_sensor_state(hass, "sensor.washing_machine_remaining_time", "0", step)
|
|
# PROGRAM_ENDED -> elapsed time kept from last program (some devices immediately go to 0)
|
|
check_sensor_state(hass, "sensor.washing_machine_elapsed_time", "109", step)
|
|
# consumption values now are reporting last known value, API might start reporting null object
|
|
check_sensor_state(hass, "sensor.washing_machine_energy_consumption", "0.1", step)
|
|
check_sensor_state(hass, "sensor.washing_machine_water_consumption", "7", step)
|
|
|
|
# Simulate when door is opened after program ended
|
|
device_fixture["DummyWasher"]["state"]["status"]["value_raw"] = 3
|
|
device_fixture["DummyWasher"]["state"]["status"]["value_localized"] = (
|
|
"Programme selected"
|
|
)
|
|
device_fixture["DummyWasher"]["state"]["programPhase"]["value_raw"] = 256
|
|
device_fixture["DummyWasher"]["state"]["programPhase"]["value_localized"] = ""
|
|
device_fixture["DummyWasher"]["state"]["targetTemperature"][0]["value_raw"] = 4000
|
|
device_fixture["DummyWasher"]["state"]["targetTemperature"][0][
|
|
"value_localized"
|
|
] = 40.0
|
|
device_fixture["DummyWasher"]["state"]["remainingTime"][0] = 1
|
|
device_fixture["DummyWasher"]["state"]["remainingTime"][1] = 59
|
|
device_fixture["DummyWasher"]["state"]["elapsedTime"][0] = 0
|
|
device_fixture["DummyWasher"]["state"]["elapsedTime"][1] = 0
|
|
|
|
freezer.tick(timedelta(seconds=130))
|
|
async_fire_time_changed(hass)
|
|
await hass.async_block_till_done()
|
|
step += 1
|
|
|
|
check_sensor_state(hass, "sensor.washing_machine", "programmed", step)
|
|
check_sensor_state(hass, "sensor.washing_machine_program", "minimum_iron", step)
|
|
check_sensor_state(
|
|
hass, "sensor.washing_machine_program_phase", "not_running", step
|
|
)
|
|
check_sensor_state(hass, "sensor.washing_machine_target_temperature", "40.0", step)
|
|
check_sensor_state(hass, "sensor.washing_machine_spin_speed", "1200", step)
|
|
# PROGRAMMED -> elapsed, remaining time from API (normal case)
|
|
check_sensor_state(hass, "sensor.washing_machine_remaining_time", "119", step)
|
|
check_sensor_state(hass, "sensor.washing_machine_elapsed_time", "0", step)
|
|
|
|
|
|
@pytest.mark.parametrize("load_device_file", ["laundry.json"])
|
|
@pytest.mark.parametrize("platforms", [(SENSOR_DOMAIN,)])
|
|
async def test_laundry_dry_scenario(
|
|
hass: HomeAssistant,
|
|
mock_miele_client: MagicMock,
|
|
setup_platform: None,
|
|
mock_config_entry: MockConfigEntry,
|
|
device_fixture: MieleDevices,
|
|
freezer: FrozenDateTimeFactory,
|
|
) -> None:
|
|
"""Parametrized test for verifying time sensors for tumble dryer devices when API reports time value from last cycle, when device is off."""
|
|
|
|
step = 0
|
|
|
|
# Initial state when the washing machine is off
|
|
check_sensor_state(hass, "sensor.tumble_dryer", "off", step)
|
|
check_sensor_state(hass, "sensor.tumble_dryer_program", "no_program", step)
|
|
check_sensor_state(hass, "sensor.tumble_dryer_program_phase", "not_running", step)
|
|
check_sensor_state(hass, "sensor.tumble_dryer_drying_step", "unknown", step)
|
|
# OFF -> elapsed, remaining forced to unknown (some devices continue reporting last value of last cycle)
|
|
check_sensor_state(hass, "sensor.tumble_dryer_remaining_time", "unknown", step)
|
|
check_sensor_state(hass, "sensor.tumble_dryer_elapsed_time", "unknown", step)
|
|
|
|
# Simulate program started
|
|
device_fixture["DummyDryer"]["state"]["status"]["value_raw"] = 5
|
|
device_fixture["DummyDryer"]["state"]["status"]["value_localized"] = "In use"
|
|
device_fixture["DummyDryer"]["state"]["ProgramID"]["value_raw"] = 3
|
|
device_fixture["DummyDryer"]["state"]["ProgramID"]["value_localized"] = (
|
|
"Minimum iron"
|
|
)
|
|
device_fixture["DummyDryer"]["state"]["programPhase"]["value_raw"] = 514
|
|
device_fixture["DummyDryer"]["state"]["programPhase"]["value_localized"] = "Drying"
|
|
device_fixture["DummyDryer"]["state"]["remainingTime"][0] = 0
|
|
device_fixture["DummyDryer"]["state"]["remainingTime"][1] = 49
|
|
device_fixture["DummyDryer"]["state"]["elapsedTime"][0] = 0
|
|
device_fixture["DummyDryer"]["state"]["elapsedTime"][1] = 20
|
|
device_fixture["DummyDryer"]["state"]["dryingStep"]["value_raw"] = 2
|
|
device_fixture["DummyDryer"]["state"]["dryingStep"]["value_localized"] = "Normal"
|
|
|
|
freezer.tick(timedelta(seconds=130))
|
|
async_fire_time_changed(hass)
|
|
await hass.async_block_till_done()
|
|
step += 1
|
|
|
|
check_sensor_state(hass, "sensor.tumble_dryer", "in_use", step)
|
|
check_sensor_state(hass, "sensor.tumble_dryer_program", "minimum_iron", step)
|
|
check_sensor_state(hass, "sensor.tumble_dryer_program_phase", "drying", step)
|
|
check_sensor_state(hass, "sensor.tumble_dryer_drying_step", "normal", step)
|
|
# IN_USE -> elapsed, remaining time from API (normal case)
|
|
check_sensor_state(hass, "sensor.tumble_dryer_remaining_time", "49", step)
|
|
check_sensor_state(hass, "sensor.tumble_dryer_elapsed_time", "20", step)
|
|
|
|
# Simulate program end
|
|
device_fixture["DummyDryer"]["state"]["status"]["value_raw"] = 7
|
|
device_fixture["DummyDryer"]["state"]["status"]["value_localized"] = "Finished"
|
|
device_fixture["DummyDryer"]["state"]["programPhase"]["value_raw"] = 522
|
|
device_fixture["DummyDryer"]["state"]["programPhase"]["value_localized"] = (
|
|
"Finished"
|
|
)
|
|
device_fixture["DummyDryer"]["state"]["remainingTime"][0] = 0
|
|
device_fixture["DummyDryer"]["state"]["remainingTime"][1] = 0
|
|
device_fixture["DummyDryer"]["state"]["elapsedTime"][0] = 1
|
|
device_fixture["DummyDryer"]["state"]["elapsedTime"][1] = 18
|
|
|
|
freezer.tick(timedelta(seconds=130))
|
|
async_fire_time_changed(hass)
|
|
await hass.async_block_till_done()
|
|
step += 1
|
|
|
|
check_sensor_state(hass, "sensor.tumble_dryer", "program_ended", step)
|
|
check_sensor_state(hass, "sensor.tumble_dryer_program", "minimum_iron", step)
|
|
check_sensor_state(hass, "sensor.tumble_dryer_program_phase", "finished", step)
|
|
check_sensor_state(hass, "sensor.tumble_dryer_drying_step", "normal", step)
|
|
# PROGRAM_ENDED -> remaining time forced to 0
|
|
check_sensor_state(hass, "sensor.tumble_dryer_remaining_time", "0", step)
|
|
# PROGRAM_ENDED -> elapsed time kept from last program (some devices immediately go to 0)
|
|
check_sensor_state(hass, "sensor.tumble_dryer_elapsed_time", "20", step)
|
|
|
|
|
|
@pytest.mark.parametrize("restore_state", ["45", STATE_UNKNOWN, STATE_UNAVAILABLE])
|
|
@pytest.mark.parametrize("load_device_file", ["laundry.json"])
|
|
@pytest.mark.parametrize("platforms", [(SENSOR_DOMAIN,)])
|
|
async def test_elapsed_time_sensor_restored(
|
|
hass: HomeAssistant,
|
|
mock_config_entry: MockConfigEntry,
|
|
mock_miele_client: MagicMock,
|
|
setup_platform: None,
|
|
device_fixture: MieleDevices,
|
|
freezer: FrozenDateTimeFactory,
|
|
restore_state,
|
|
) -> None:
|
|
"""Test that elapsed time returns the restored value when program ended."""
|
|
|
|
entity_id = "sensor.washing_machine_elapsed_time"
|
|
|
|
# Simulate program started
|
|
device_fixture["DummyWasher"]["state"]["status"]["value_raw"] = 5
|
|
device_fixture["DummyWasher"]["state"]["status"]["value_localized"] = "In use"
|
|
device_fixture["DummyWasher"]["state"]["ProgramID"]["value_raw"] = 3
|
|
device_fixture["DummyWasher"]["state"]["ProgramID"]["value_localized"] = (
|
|
"Minimum iron"
|
|
)
|
|
device_fixture["DummyWasher"]["state"]["programPhase"]["value_raw"] = 260
|
|
device_fixture["DummyWasher"]["state"]["programPhase"]["value_localized"] = (
|
|
"Main wash"
|
|
)
|
|
device_fixture["DummyWasher"]["state"]["remainingTime"][0] = 1
|
|
device_fixture["DummyWasher"]["state"]["remainingTime"][1] = 45
|
|
device_fixture["DummyWasher"]["state"]["targetTemperature"][0]["value_raw"] = 3000
|
|
device_fixture["DummyWasher"]["state"]["targetTemperature"][0][
|
|
"value_localized"
|
|
] = 30.0
|
|
device_fixture["DummyWasher"]["state"]["elapsedTime"][0] = 0
|
|
device_fixture["DummyWasher"]["state"]["elapsedTime"][1] = 12
|
|
device_fixture["DummyWasher"]["state"]["spinningSpeed"]["value_raw"] = 1200
|
|
device_fixture["DummyWasher"]["state"]["spinningSpeed"]["value_localized"] = "1200"
|
|
|
|
freezer.tick(timedelta(seconds=130))
|
|
async_fire_time_changed(hass)
|
|
await hass.async_block_till_done()
|
|
|
|
assert hass.states.get(entity_id).state == "12"
|
|
|
|
# Simulate program ended
|
|
device_fixture["DummyWasher"]["state"]["status"]["value_raw"] = 7
|
|
device_fixture["DummyWasher"]["state"]["status"]["value_localized"] = "Finished"
|
|
device_fixture["DummyWasher"]["state"]["programPhase"]["value_raw"] = 267
|
|
device_fixture["DummyWasher"]["state"]["programPhase"]["value_localized"] = (
|
|
"Anti-crease"
|
|
)
|
|
device_fixture["DummyWasher"]["state"]["remainingTime"][0] = 0
|
|
device_fixture["DummyWasher"]["state"]["remainingTime"][1] = 0
|
|
device_fixture["DummyWasher"]["state"]["elapsedTime"][0] = 0
|
|
device_fixture["DummyWasher"]["state"]["elapsedTime"][1] = 0
|
|
|
|
freezer.tick(timedelta(seconds=130))
|
|
async_fire_time_changed(hass)
|
|
await hass.async_block_till_done()
|
|
|
|
# unload config entry and reload to make sure that the state is restored
|
|
|
|
await hass.config_entries.async_unload(mock_config_entry.entry_id)
|
|
await hass.async_block_till_done()
|
|
|
|
assert hass.states.get(entity_id).state == "unavailable"
|
|
|
|
# simulate restore with state different from native value
|
|
mock_restore_cache_with_extra_data(
|
|
hass,
|
|
[
|
|
(
|
|
State(
|
|
entity_id,
|
|
restore_state,
|
|
{
|
|
"unit_of_measurement": "min",
|
|
},
|
|
),
|
|
{
|
|
"native_value": "12",
|
|
"native_unit_of_measurement": "min",
|
|
},
|
|
),
|
|
],
|
|
)
|
|
|
|
await hass.config_entries.async_reload(mock_config_entry.entry_id)
|
|
await hass.async_block_till_done()
|
|
|
|
# check that elapsed time is the one restored and not the value reported by API (0)
|
|
state = hass.states.get(entity_id)
|
|
assert state is not None
|
|
assert state.state == "12"
|