mirror of
https://github.com/home-assistant/core.git
synced 2025-07-28 07:37:34 +00:00
Add miele devices dynamically (#144216)
* Use device class transation * WIP Cleanup tests * First 3 * First 3 * Button * Climate * Light * Switch * New and cleaner variant * Update homeassistant/components/miele/entity.py --------- Co-authored-by: Josef Zweck <josef@zweck.dev>
This commit is contained in:
parent
34dbd1fb10
commit
337c64d69d
@ -263,14 +263,24 @@ async def async_setup_entry(
|
||||
) -> None:
|
||||
"""Set up the binary sensor platform."""
|
||||
coordinator = config_entry.runtime_data
|
||||
added_devices: set[str] = set()
|
||||
|
||||
def _async_add_new_devices() -> None:
|
||||
nonlocal added_devices
|
||||
|
||||
new_devices_set, current_devices = coordinator.async_add_devices(added_devices)
|
||||
added_devices = current_devices
|
||||
|
||||
async_add_entities(
|
||||
MieleBinarySensor(coordinator, device_id, definition.description)
|
||||
for device_id, device in coordinator.data.devices.items()
|
||||
for definition in BINARY_SENSOR_TYPES
|
||||
if device.device_type in definition.types
|
||||
if device_id in new_devices_set and device.device_type in definition.types
|
||||
)
|
||||
|
||||
config_entry.async_on_unload(coordinator.async_add_listener(_async_add_new_devices))
|
||||
_async_add_new_devices()
|
||||
|
||||
|
||||
class MieleBinarySensor(MieleEntity, BinarySensorEntity):
|
||||
"""Representation of a Binary Sensor."""
|
||||
|
@ -111,14 +111,23 @@ async def async_setup_entry(
|
||||
) -> None:
|
||||
"""Set up the button platform."""
|
||||
coordinator = config_entry.runtime_data
|
||||
added_devices: set[str] = set()
|
||||
|
||||
def _async_add_new_devices() -> None:
|
||||
nonlocal added_devices
|
||||
new_devices_set, current_devices = coordinator.async_add_devices(added_devices)
|
||||
added_devices = current_devices
|
||||
|
||||
async_add_entities(
|
||||
MieleButton(coordinator, device_id, definition.description)
|
||||
for device_id, device in coordinator.data.devices.items()
|
||||
for definition in BUTTON_TYPES
|
||||
if device.device_type in definition.types
|
||||
if device_id in new_devices_set and device.device_type in definition.types
|
||||
)
|
||||
|
||||
config_entry.async_on_unload(coordinator.async_add_listener(_async_add_new_devices))
|
||||
_async_add_new_devices()
|
||||
|
||||
|
||||
class MieleButton(MieleEntity, ButtonEntity):
|
||||
"""Representation of a Button."""
|
||||
|
@ -131,16 +131,30 @@ async def async_setup_entry(
|
||||
) -> None:
|
||||
"""Set up the climate platform."""
|
||||
coordinator = config_entry.runtime_data
|
||||
added_devices: set[str] = set()
|
||||
|
||||
def _async_add_new_devices() -> None:
|
||||
nonlocal added_devices
|
||||
|
||||
new_devices_set, current_devices = coordinator.async_add_devices(added_devices)
|
||||
added_devices = current_devices
|
||||
|
||||
async_add_entities(
|
||||
MieleClimate(coordinator, device_id, definition.description)
|
||||
for device_id, device in coordinator.data.devices.items()
|
||||
for definition in CLIMATE_TYPES
|
||||
if (
|
||||
device.device_type in definition.types
|
||||
and (definition.description.value_fn(device) not in DISABLED_TEMP_ENTITIES)
|
||||
device_id in new_devices_set
|
||||
and device.device_type in definition.types
|
||||
and (
|
||||
definition.description.value_fn(device)
|
||||
not in DISABLED_TEMP_ENTITIES
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
config_entry.async_on_unload(coordinator.async_add_listener(_async_add_new_devices))
|
||||
_async_add_new_devices()
|
||||
|
||||
|
||||
class MieleClimate(MieleEntity, ClimateEntity):
|
||||
|
@ -3,6 +3,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import asyncio.timeouts
|
||||
from collections.abc import Callable
|
||||
from dataclasses import dataclass
|
||||
from datetime import timedelta
|
||||
import logging
|
||||
@ -33,6 +34,11 @@ class MieleCoordinatorData:
|
||||
class MieleDataUpdateCoordinator(DataUpdateCoordinator[MieleCoordinatorData]):
|
||||
"""Coordinator for Miele data."""
|
||||
|
||||
config_entry: MieleConfigEntry
|
||||
new_device_callbacks: list[Callable[[dict[str, MieleDevice]], None]] = []
|
||||
known_devices: set[str] = set()
|
||||
devices: dict[str, MieleDevice] = {}
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
hass: HomeAssistant,
|
||||
@ -56,12 +62,20 @@ class MieleDataUpdateCoordinator(DataUpdateCoordinator[MieleCoordinatorData]):
|
||||
device_id: MieleDevice(device)
|
||||
for device_id, device in devices_json.items()
|
||||
}
|
||||
self.devices = devices
|
||||
actions = {}
|
||||
for device_id in devices:
|
||||
actions_json = await self.api.get_actions(device_id)
|
||||
actions[device_id] = MieleAction(actions_json)
|
||||
return MieleCoordinatorData(devices=devices, actions=actions)
|
||||
|
||||
def async_add_devices(self, added_devices: set[str]) -> tuple[set[str], set[str]]:
|
||||
"""Add devices."""
|
||||
current_devices = set(self.devices)
|
||||
new_devices: set[str] = current_devices - added_devices
|
||||
|
||||
return (new_devices, current_devices)
|
||||
|
||||
async def callback_update_data(self, devices_json: dict[str, dict]) -> None:
|
||||
"""Handle data update from the API."""
|
||||
devices = {
|
||||
|
@ -65,14 +65,23 @@ async def async_setup_entry(
|
||||
) -> None:
|
||||
"""Set up the fan platform."""
|
||||
coordinator = config_entry.runtime_data
|
||||
added_devices: set[str] = set()
|
||||
|
||||
def _async_add_new_devices() -> None:
|
||||
nonlocal added_devices
|
||||
new_devices_set, current_devices = coordinator.async_add_devices(added_devices)
|
||||
added_devices = current_devices
|
||||
|
||||
async_add_entities(
|
||||
MieleFan(coordinator, device_id, definition.description)
|
||||
for device_id, device in coordinator.data.devices.items()
|
||||
for definition in FAN_TYPES
|
||||
if device.device_type in definition.types
|
||||
if device_id in new_devices_set and device.device_type in definition.types
|
||||
)
|
||||
|
||||
config_entry.async_on_unload(coordinator.async_add_listener(_async_add_new_devices))
|
||||
_async_add_new_devices()
|
||||
|
||||
|
||||
class MieleFan(MieleEntity, FanEntity):
|
||||
"""Representation of a Fan."""
|
||||
|
@ -85,14 +85,23 @@ async def async_setup_entry(
|
||||
) -> None:
|
||||
"""Set up the light platform."""
|
||||
coordinator = config_entry.runtime_data
|
||||
added_devices: set[str] = set()
|
||||
|
||||
def _async_add_new_devices() -> None:
|
||||
nonlocal added_devices
|
||||
new_devices_set, current_devices = coordinator.async_add_devices(added_devices)
|
||||
added_devices = current_devices
|
||||
|
||||
async_add_entities(
|
||||
MieleLight(coordinator, device_id, definition.description)
|
||||
for device_id, device in coordinator.data.devices.items()
|
||||
for definition in LIGHT_TYPES
|
||||
if device.device_type in definition.types
|
||||
if device_id in new_devices_set and device.device_type in definition.types
|
||||
)
|
||||
|
||||
config_entry.async_on_unload(coordinator.async_add_listener(_async_add_new_devices))
|
||||
_async_add_new_devices()
|
||||
|
||||
|
||||
class MieleLight(MieleEntity, LightEntity):
|
||||
"""Representation of a Light."""
|
||||
|
@ -426,9 +426,15 @@ async def async_setup_entry(
|
||||
) -> None:
|
||||
"""Set up the sensor platform."""
|
||||
coordinator = config_entry.runtime_data
|
||||
added_devices: set[str] = set()
|
||||
|
||||
def _async_add_new_devices() -> None:
|
||||
nonlocal added_devices
|
||||
entities: list = []
|
||||
entity_class: type[MieleSensor]
|
||||
new_devices_set, current_devices = coordinator.async_add_devices(added_devices)
|
||||
added_devices = current_devices
|
||||
|
||||
for device_id, device in coordinator.data.devices.items():
|
||||
for definition in SENSOR_TYPES:
|
||||
if device.device_type in definition.types:
|
||||
@ -442,7 +448,9 @@ async def async_setup_entry(
|
||||
case _:
|
||||
entity_class = MieleSensor
|
||||
if (
|
||||
definition.description.device_class == SensorDeviceClass.TEMPERATURE
|
||||
device_id in new_devices_set
|
||||
and definition.description.device_class
|
||||
== SensorDeviceClass.TEMPERATURE
|
||||
and definition.description.value_fn(device)
|
||||
== DISABLED_TEMPERATURE / 100
|
||||
):
|
||||
@ -451,9 +459,11 @@ async def async_setup_entry(
|
||||
entities.append(
|
||||
entity_class(coordinator, device_id, definition.description)
|
||||
)
|
||||
|
||||
async_add_entities(entities)
|
||||
|
||||
config_entry.async_on_unload(coordinator.async_add_listener(_async_add_new_devices))
|
||||
_async_add_new_devices()
|
||||
|
||||
|
||||
APPLIANCE_ICONS = {
|
||||
MieleAppliance.WASHING_MACHINE: "mdi:washing-machine",
|
||||
|
@ -116,12 +116,21 @@ async def async_setup_entry(
|
||||
) -> None:
|
||||
"""Set up the switch platform."""
|
||||
coordinator = config_entry.runtime_data
|
||||
added_devices: set[str] = set()
|
||||
|
||||
entities: list = []
|
||||
entity_class: type[MieleSwitch]
|
||||
def _async_add_new_devices() -> None:
|
||||
nonlocal added_devices
|
||||
new_devices_set, current_devices = coordinator.async_add_devices(added_devices)
|
||||
added_devices = current_devices
|
||||
|
||||
entities = []
|
||||
for device_id, device in coordinator.data.devices.items():
|
||||
for definition in SWITCH_TYPES:
|
||||
if device.device_type in definition.types:
|
||||
if (
|
||||
device_id in new_devices_set
|
||||
and device.device_type in definition.types
|
||||
):
|
||||
entity_class: type[MieleSwitch] = MieleSwitch
|
||||
match definition.description.key:
|
||||
case "poweronoff":
|
||||
entity_class = MielePowerSwitch
|
||||
@ -133,6 +142,9 @@ async def async_setup_entry(
|
||||
)
|
||||
async_add_entities(entities)
|
||||
|
||||
config_entry.async_on_unload(coordinator.async_add_listener(_async_add_new_devices))
|
||||
_async_add_new_devices()
|
||||
|
||||
|
||||
class MieleSwitch(MieleEntity, SwitchEntity):
|
||||
"""Representation of a Switch."""
|
||||
|
@ -141,7 +141,7 @@ async def setup_platform(
|
||||
with patch(f"homeassistant.components.{DOMAIN}.PLATFORMS", platforms):
|
||||
assert await hass.config_entries.async_setup(mock_config_entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
yield
|
||||
yield mock_config_entry
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
|
@ -356,6 +356,106 @@
|
||||
"batteryLevel": null
|
||||
}
|
||||
},
|
||||
"DummyAppliance_18": {
|
||||
"ident": {
|
||||
"type": {
|
||||
"key_localized": "Device type",
|
||||
"value_raw": 18,
|
||||
"value_localized": "Cooker Hood"
|
||||
},
|
||||
"deviceName": "",
|
||||
"protocolVersion": 2,
|
||||
"deviceIdentLabel": {
|
||||
"fabNumber": "<fabNumber3>",
|
||||
"fabIndex": "64",
|
||||
"techType": "Fläkt",
|
||||
"matNumber": "<matNumber3>",
|
||||
"swids": ["<swid1>", "<swid2>", "<swid3>", "<...>"]
|
||||
},
|
||||
"xkmIdentLabel": {
|
||||
"techType": "EK039W",
|
||||
"releaseVersion": "02.72"
|
||||
}
|
||||
},
|
||||
"state": {
|
||||
"ProgramID": {
|
||||
"value_raw": 1,
|
||||
"value_localized": "Off",
|
||||
"key_localized": "Program name"
|
||||
},
|
||||
"status": {
|
||||
"value_raw": 1,
|
||||
"value_localized": "Off",
|
||||
"key_localized": "status"
|
||||
},
|
||||
"programType": {
|
||||
"value_raw": 0,
|
||||
"value_localized": "Program",
|
||||
"key_localized": "Program type"
|
||||
},
|
||||
"programPhase": {
|
||||
"value_raw": 4608,
|
||||
"value_localized": "",
|
||||
"key_localized": "Program phase"
|
||||
},
|
||||
"remainingTime": [0, 0],
|
||||
"startTime": [0, 0],
|
||||
"targetTemperature": [
|
||||
{
|
||||
"value_raw": -32768,
|
||||
"value_localized": null,
|
||||
"unit": "Celsius"
|
||||
}
|
||||
],
|
||||
"temperature": [
|
||||
{
|
||||
"value_raw": -32768,
|
||||
"value_localized": null,
|
||||
"unit": "Celsius"
|
||||
},
|
||||
{
|
||||
"value_raw": -32768,
|
||||
"value_localized": null,
|
||||
"unit": "Celsius"
|
||||
},
|
||||
{
|
||||
"value_raw": -32768,
|
||||
"value_localized": null,
|
||||
"unit": "Celsius"
|
||||
}
|
||||
],
|
||||
"signalInfo": false,
|
||||
"signalFailure": false,
|
||||
"signalDoor": false,
|
||||
"remoteEnable": {
|
||||
"fullRemoteControl": true,
|
||||
"smartGrid": false,
|
||||
"mobileStart": false
|
||||
},
|
||||
"ambientLight": 2,
|
||||
"light": 1,
|
||||
"elapsedTime": {},
|
||||
"spinningSpeed": {
|
||||
"unit": "rpm",
|
||||
"value_raw": null,
|
||||
"value_localized": null,
|
||||
"key_localized": "Spin speed"
|
||||
},
|
||||
"dryingStep": {
|
||||
"value_raw": null,
|
||||
"value_localized": "",
|
||||
"key_localized": "Drying level"
|
||||
},
|
||||
"ventilationStep": {
|
||||
"value_raw": 0,
|
||||
"value_localized": "0",
|
||||
"key_localized": "Fan level"
|
||||
},
|
||||
"plateStep": [],
|
||||
"ecoFeedback": null,
|
||||
"batteryLevel": null
|
||||
}
|
||||
},
|
||||
"Dummy_Appliance_4": {
|
||||
"ident": {
|
||||
"type": {
|
||||
@ -402,10 +502,28 @@
|
||||
{ "value_raw": -32768, "value_localized": null, "unit": "Celsius" },
|
||||
{ "value_raw": -32768, "value_localized": null, "unit": "Celsius" }
|
||||
],
|
||||
"coreTargetTemperature": [
|
||||
{ "value_raw": 7500, "value_localized": "75.0", "unit": "Celsius" }
|
||||
],
|
||||
"coreTemperature": [
|
||||
{ "value_raw": 5200, "value_localized": "52.0", "unit": "Celsius" }
|
||||
],
|
||||
"temperature": [
|
||||
{ "value_raw": -32768, "value_localized": null, "unit": "Celsius" },
|
||||
{ "value_raw": -32768, "value_localized": null, "unit": "Celsius" },
|
||||
{ "value_raw": -32768, "value_localized": null, "unit": "Celsius" }
|
||||
{
|
||||
"value_raw": 17500,
|
||||
"value_localized": "175.0",
|
||||
"unit": "Celsius"
|
||||
},
|
||||
{
|
||||
"value_raw": -32768,
|
||||
"value_localized": null,
|
||||
"unit": "Celsius"
|
||||
},
|
||||
{
|
||||
"value_raw": -32768,
|
||||
"value_localized": null,
|
||||
"unit": "Celsius"
|
||||
}
|
||||
],
|
||||
"signalInfo": false,
|
||||
"signalFailure": false,
|
||||
|
@ -5,7 +5,13 @@
|
||||
"startTime": [],
|
||||
"ventilationStep": [],
|
||||
"programId": [],
|
||||
"targetTemperature": [],
|
||||
"targetTemperature": [
|
||||
{
|
||||
"zone": 1,
|
||||
"min": -28,
|
||||
"max": -14
|
||||
}
|
||||
],
|
||||
"deviceName": true,
|
||||
"powerOn": true,
|
||||
"powerOff": false,
|
||||
|
@ -36,6 +36,11 @@
|
||||
'startTime': list([
|
||||
]),
|
||||
'targetTemperature': list([
|
||||
dict({
|
||||
'max': -14,
|
||||
'min': -28,
|
||||
'zone': 1,
|
||||
}),
|
||||
]),
|
||||
'ventilationStep': list([
|
||||
]),
|
||||
@ -64,6 +69,11 @@
|
||||
'startTime': list([
|
||||
]),
|
||||
'targetTemperature': list([
|
||||
dict({
|
||||
'max': -14,
|
||||
'min': -28,
|
||||
'zone': 1,
|
||||
}),
|
||||
]),
|
||||
'ventilationStep': list([
|
||||
]),
|
||||
@ -92,6 +102,11 @@
|
||||
'startTime': list([
|
||||
]),
|
||||
'targetTemperature': list([
|
||||
dict({
|
||||
'max': -14,
|
||||
'min': -28,
|
||||
'zone': 1,
|
||||
}),
|
||||
]),
|
||||
'ventilationStep': list([
|
||||
]),
|
||||
@ -120,6 +135,11 @@
|
||||
'startTime': list([
|
||||
]),
|
||||
'targetTemperature': list([
|
||||
dict({
|
||||
'max': -14,
|
||||
'min': -28,
|
||||
'zone': 1,
|
||||
}),
|
||||
]),
|
||||
'ventilationStep': list([
|
||||
]),
|
||||
@ -689,6 +709,11 @@
|
||||
'startTime': list([
|
||||
]),
|
||||
'targetTemperature': list([
|
||||
dict({
|
||||
'max': -14,
|
||||
'min': -28,
|
||||
'zone': 1,
|
||||
}),
|
||||
]),
|
||||
'ventilationStep': list([
|
||||
]),
|
||||
|
@ -17,11 +17,10 @@ from tests.common import MockConfigEntry, snapshot_platform
|
||||
async def test_binary_sensor_states(
|
||||
hass: HomeAssistant,
|
||||
mock_miele_client: MagicMock,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
snapshot: SnapshotAssertion,
|
||||
entity_registry: er.EntityRegistry,
|
||||
setup_platform: None,
|
||||
setup_platform: MockConfigEntry,
|
||||
) -> None:
|
||||
"""Test binary sensor state."""
|
||||
|
||||
await snapshot_platform(hass, entity_registry, snapshot, mock_config_entry.entry_id)
|
||||
await snapshot_platform(hass, entity_registry, snapshot, setup_platform.entry_id)
|
||||
|
@ -24,21 +24,20 @@ ENTITY_ID = "button.washing_machine_start"
|
||||
async def test_button_states(
|
||||
hass: HomeAssistant,
|
||||
mock_miele_client: MagicMock,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
snapshot: SnapshotAssertion,
|
||||
entity_registry: er.EntityRegistry,
|
||||
setup_platform: None,
|
||||
setup_platform: MockConfigEntry,
|
||||
) -> None:
|
||||
"""Test button entity state."""
|
||||
|
||||
await snapshot_platform(hass, entity_registry, snapshot, mock_config_entry.entry_id)
|
||||
await snapshot_platform(hass, entity_registry, snapshot, setup_platform.entry_id)
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("entity_registry_enabled_by_default")
|
||||
async def test_button_press(
|
||||
hass: HomeAssistant,
|
||||
mock_miele_client: MagicMock,
|
||||
setup_platform: None,
|
||||
setup_platform: MockConfigEntry,
|
||||
) -> None:
|
||||
"""Test button press."""
|
||||
|
||||
@ -54,7 +53,7 @@ async def test_button_press(
|
||||
async def test_api_failure(
|
||||
hass: HomeAssistant,
|
||||
mock_miele_client: MagicMock,
|
||||
setup_platform: None,
|
||||
setup_platform: MockConfigEntry,
|
||||
) -> None:
|
||||
"""Test handling of exception from API."""
|
||||
mock_miele_client.send_action.side_effect = ClientResponseError("test", "Test")
|
||||
|
@ -33,20 +33,19 @@ SERVICE_SET_TEMPERATURE = "set_temperature"
|
||||
async def test_climate_states(
|
||||
hass: HomeAssistant,
|
||||
mock_miele_client: MagicMock,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
snapshot: SnapshotAssertion,
|
||||
entity_registry: er.EntityRegistry,
|
||||
setup_platform: None,
|
||||
setup_platform: MockConfigEntry,
|
||||
) -> None:
|
||||
"""Test climate entity state."""
|
||||
|
||||
await snapshot_platform(hass, entity_registry, snapshot, mock_config_entry.entry_id)
|
||||
await snapshot_platform(hass, entity_registry, snapshot, setup_platform.entry_id)
|
||||
|
||||
|
||||
async def test_set_target(
|
||||
hass: HomeAssistant,
|
||||
mock_miele_client: MagicMock,
|
||||
setup_platform: None,
|
||||
setup_platform: MockConfigEntry,
|
||||
) -> None:
|
||||
"""Test the climate can be turned on/off."""
|
||||
|
||||
@ -64,7 +63,7 @@ async def test_set_target(
|
||||
async def test_api_failure(
|
||||
hass: HomeAssistant,
|
||||
mock_miele_client: MagicMock,
|
||||
setup_platform: None,
|
||||
setup_platform: MockConfigEntry,
|
||||
) -> None:
|
||||
"""Test handling of exception from API."""
|
||||
mock_miele_client.set_target_temperature.side_effect = ClientError
|
||||
|
@ -25,14 +25,13 @@ ENTITY_ID = "fan.hood_fan"
|
||||
async def test_fan_states(
|
||||
hass: HomeAssistant,
|
||||
mock_miele_client: MagicMock,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
snapshot: SnapshotAssertion,
|
||||
entity_registry: er.EntityRegistry,
|
||||
setup_platform: None,
|
||||
setup_platform: MockConfigEntry,
|
||||
) -> None:
|
||||
"""Test fan entity state."""
|
||||
|
||||
await snapshot_platform(hass, entity_registry, snapshot, mock_config_entry.entry_id)
|
||||
await snapshot_platform(hass, entity_registry, snapshot, setup_platform.entry_id)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("load_device_file", ["fan_devices.json"])
|
||||
@ -46,7 +45,7 @@ async def test_fan_states(
|
||||
async def test_fan_control(
|
||||
hass: HomeAssistant,
|
||||
mock_miele_client: MagicMock,
|
||||
setup_platform: None,
|
||||
setup_platform: MockConfigEntry,
|
||||
service: str,
|
||||
expected_argument: dict[str, Any],
|
||||
) -> None:
|
||||
@ -74,7 +73,7 @@ async def test_fan_control(
|
||||
async def test_fan_set_speed(
|
||||
hass: HomeAssistant,
|
||||
mock_miele_client: MagicMock,
|
||||
setup_platform: None,
|
||||
setup_platform: MockConfigEntry,
|
||||
service: str,
|
||||
percentage: int,
|
||||
expected_argument: dict[str, Any],
|
||||
@ -102,7 +101,7 @@ async def test_fan_set_speed(
|
||||
async def test_api_failure(
|
||||
hass: HomeAssistant,
|
||||
mock_miele_client: MagicMock,
|
||||
setup_platform: None,
|
||||
setup_platform: MockConfigEntry,
|
||||
service: str,
|
||||
) -> None:
|
||||
"""Test handling of exception from API."""
|
||||
|
@ -1,10 +1,12 @@
|
||||
"""Tests for init module."""
|
||||
|
||||
from datetime import timedelta
|
||||
import http
|
||||
import time
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
from aiohttp import ClientConnectionError
|
||||
from freezegun.api import FrozenDateTimeFactory
|
||||
from pymiele import OAUTH2_TOKEN
|
||||
import pytest
|
||||
from syrupy import SnapshotAssertion
|
||||
@ -17,7 +19,11 @@ from homeassistant.setup import async_setup_component
|
||||
|
||||
from . import setup_integration
|
||||
|
||||
from tests.common import MockConfigEntry
|
||||
from tests.common import (
|
||||
MockConfigEntry,
|
||||
async_fire_time_changed,
|
||||
load_json_object_fixture,
|
||||
)
|
||||
from tests.test_util.aiohttp import AiohttpClientMocker
|
||||
from tests.typing import WebSocketGenerator
|
||||
|
||||
@ -157,3 +163,48 @@ async def test_device_remove_devices(
|
||||
old_device_entry.id, mock_config_entry.entry_id
|
||||
)
|
||||
assert response["success"]
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("entity_registry_enabled_by_default")
|
||||
async def test_setup_all_platforms(
|
||||
hass: HomeAssistant,
|
||||
mock_miele_client: MagicMock,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
device_registry: dr.DeviceRegistry,
|
||||
load_device_file: str,
|
||||
freezer: FrozenDateTimeFactory,
|
||||
) -> None:
|
||||
"""Test that all platforms can be set up."""
|
||||
|
||||
await setup_integration(hass, mock_config_entry)
|
||||
|
||||
assert hass.states.get("binary_sensor.freezer_door").state == "off"
|
||||
assert hass.states.get("binary_sensor.hood_problem").state == "off"
|
||||
|
||||
assert (
|
||||
hass.states.get("button.washing_machine_start").object_id
|
||||
== "washing_machine_start"
|
||||
)
|
||||
|
||||
assert hass.states.get("climate.freezer").state == "cool"
|
||||
assert hass.states.get("light.hood_light").state == "on"
|
||||
|
||||
assert hass.states.get("sensor.freezer_temperature").state == "-18.0"
|
||||
assert hass.states.get("sensor.washing_machine").state == "off"
|
||||
|
||||
assert hass.states.get("switch.washing_machine_power").state == "off"
|
||||
|
||||
# Add two devices and let the clock tick for 130 seconds
|
||||
freezer.tick(timedelta(seconds=130))
|
||||
mock_miele_client.get_devices.return_value = load_json_object_fixture(
|
||||
"5_devices.json", DOMAIN
|
||||
)
|
||||
|
||||
async_fire_time_changed(hass)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert len(device_registry.devices) == 6
|
||||
|
||||
# Check a sample sensor for each new device
|
||||
assert hass.states.get("sensor.dishwasher").state == "in_use"
|
||||
assert hass.states.get("sensor.oven_temperature").state == "175.0"
|
||||
|
@ -23,14 +23,13 @@ ENTITY_ID = "light.hood_light"
|
||||
async def test_light_states(
|
||||
hass: HomeAssistant,
|
||||
mock_miele_client: MagicMock,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
snapshot: SnapshotAssertion,
|
||||
entity_registry: er.EntityRegistry,
|
||||
setup_platform: None,
|
||||
setup_platform: MockConfigEntry,
|
||||
) -> None:
|
||||
"""Test light entity state."""
|
||||
|
||||
await snapshot_platform(hass, entity_registry, snapshot, mock_config_entry.entry_id)
|
||||
await snapshot_platform(hass, entity_registry, snapshot, setup_platform.entry_id)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
@ -43,7 +42,7 @@ async def test_light_states(
|
||||
async def test_light_toggle(
|
||||
hass: HomeAssistant,
|
||||
mock_miele_client: MagicMock,
|
||||
setup_platform: None,
|
||||
setup_platform: MockConfigEntry,
|
||||
service: str,
|
||||
light_state: int,
|
||||
) -> None:
|
||||
@ -67,7 +66,7 @@ async def test_light_toggle(
|
||||
async def test_api_failure(
|
||||
hass: HomeAssistant,
|
||||
mock_miele_client: MagicMock,
|
||||
setup_platform: None,
|
||||
setup_platform: MockConfigEntry,
|
||||
service: str,
|
||||
) -> None:
|
||||
"""Test handling of exception from API."""
|
||||
|
@ -17,11 +17,10 @@ from tests.common import MockConfigEntry, snapshot_platform
|
||||
async def test_sensor_states(
|
||||
hass: HomeAssistant,
|
||||
mock_miele_client: MagicMock,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
snapshot: SnapshotAssertion,
|
||||
entity_registry: er.EntityRegistry,
|
||||
setup_platform: None,
|
||||
setup_platform: MockConfigEntry,
|
||||
) -> None:
|
||||
"""Test sensor state."""
|
||||
|
||||
await snapshot_platform(hass, entity_registry, snapshot, mock_config_entry.entry_id)
|
||||
await snapshot_platform(hass, entity_registry, snapshot, setup_platform.entry_id)
|
||||
|
@ -23,14 +23,13 @@ ENTITY_ID = "switch.freezer_superfreezing"
|
||||
async def test_switch_states(
|
||||
hass: HomeAssistant,
|
||||
mock_miele_client: MagicMock,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
snapshot: SnapshotAssertion,
|
||||
entity_registry: er.EntityRegistry,
|
||||
setup_platform: None,
|
||||
setup_platform: MockConfigEntry,
|
||||
) -> None:
|
||||
"""Test switch entity state."""
|
||||
|
||||
await snapshot_platform(hass, entity_registry, snapshot, mock_config_entry.entry_id)
|
||||
await snapshot_platform(hass, entity_registry, snapshot, setup_platform.entry_id)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
@ -51,7 +50,7 @@ async def test_switch_states(
|
||||
async def test_switching(
|
||||
hass: HomeAssistant,
|
||||
mock_miele_client: MagicMock,
|
||||
setup_platform: None,
|
||||
setup_platform: MockConfigEntry,
|
||||
service: str,
|
||||
entity: str,
|
||||
) -> None:
|
||||
@ -81,7 +80,7 @@ async def test_switching(
|
||||
async def test_api_failure(
|
||||
hass: HomeAssistant,
|
||||
mock_miele_client: MagicMock,
|
||||
setup_platform: None,
|
||||
setup_platform: MockConfigEntry,
|
||||
service: str,
|
||||
entity: str,
|
||||
) -> None:
|
||||
|
Loading…
x
Reference in New Issue
Block a user