Skip to content

Add miele devices dynamically #144216

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 16 commits into
base: dev
Choose a base branch
from
22 changes: 16 additions & 6 deletions homeassistant/components/miele/binary_sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -263,13 +263,23 @@ async def async_setup_entry(
) -> None:
"""Set up the binary sensor platform."""
coordinator = config_entry.runtime_data
added_devices: set[str] = set()

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
)
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_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):
Expand Down
21 changes: 15 additions & 6 deletions homeassistant/components/miele/button.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,13 +111,22 @@ 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_id in new_devices_set and device.device_type in definition.types
)

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
)
config_entry.async_on_unload(coordinator.async_add_listener(_async_add_new_devices))
_async_add_new_devices()


class MieleButton(MieleEntity, ButtonEntity):
Expand Down
32 changes: 23 additions & 9 deletions homeassistant/components/miele/climate.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,16 +131,30 @@ async def async_setup_entry(
) -> None:
"""Set up the climate platform."""
coordinator = config_entry.runtime_data

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)
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_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):
Expand Down
14 changes: 14 additions & 0 deletions homeassistant/components/miele/coordinator.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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,
Expand All @@ -56,12 +62,20 @@ async def _async_update_data(self) -> 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 = {
Expand Down
1 change: 1 addition & 0 deletions homeassistant/components/miele/entity.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ def __init__(
@property
def device(self) -> MieleDevice:
"""Return the device object."""
# print(">>> entity.device: ", self.coordinator.data.devices)
return self.coordinator.data.devices[self._device_id]

@property
Expand Down
21 changes: 15 additions & 6 deletions homeassistant/components/miele/fan.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,13 +65,22 @@ 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_id in new_devices_set and device.device_type in definition.types
)

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
)
config_entry.async_on_unload(coordinator.async_add_listener(_async_add_new_devices))
_async_add_new_devices()


class MieleFan(MieleEntity, FanEntity):
Expand Down
23 changes: 16 additions & 7 deletions homeassistant/components/miele/light.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,13 +85,22 @@ async def async_setup_entry(
) -> None:
"""Set up the light platform."""
coordinator = config_entry.runtime_data

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
)
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_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):
Expand Down
64 changes: 37 additions & 27 deletions homeassistant/components/miele/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -427,33 +427,43 @@ async def async_setup_entry(
) -> None:
"""Set up the sensor platform."""
coordinator = config_entry.runtime_data

entities: list = []
entity_class: type[MieleSensor]
for device_id, device in coordinator.data.devices.items():
for definition in SENSOR_TYPES:
if device.device_type in definition.types:
match definition.description.key:
case "state_status":
entity_class = MieleStatusSensor
case "state_program_id":
entity_class = MieleProgramIdSensor
case "state_program_phase":
entity_class = MielePhaseSensor
case _:
entity_class = MieleSensor
if (
definition.description.device_class == SensorDeviceClass.TEMPERATURE
and definition.description.value_fn(device)
== DISABLED_TEMPERATURE / 100
):
# Don't create entity if API signals that datapoint is disabled
continue
entities.append(
entity_class(coordinator, device_id, definition.description)
)

async_add_entities(entities)
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:
match definition.description.key:
case "state_status":
entity_class = MieleStatusSensor
case "state_program_id":
entity_class = MieleProgramIdSensor
case "state_program_phase":
entity_class = MielePhaseSensor
case _:
entity_class = MieleSensor
if (
device_id in new_devices_set
and definition.description.device_class
== SensorDeviceClass.TEMPERATURE
and definition.description.value_fn(device)
== DISABLED_TEMPERATURE / 100
):
# Don't create entity if API signals that datapoint is disabled
continue
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 = {
Expand Down
44 changes: 28 additions & 16 deletions homeassistant/components/miele/switch.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,22 +116,34 @@ async def async_setup_entry(
) -> None:
"""Set up the switch platform."""
coordinator = config_entry.runtime_data

entities: list = []
entity_class: type[MieleSwitch]
for device_id, device in coordinator.data.devices.items():
for definition in SWITCH_TYPES:
if device.device_type in definition.types:
match definition.description.key:
case "poweronoff":
entity_class = MielePowerSwitch
case "supercooling" | "superfreezing":
entity_class = MieleSuperSwitch

entities.append(
entity_class(coordinator, device_id, definition.description)
)
async_add_entities(entities)
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

entities = []
for device_id, device in coordinator.data.devices.items():
for definition in SWITCH_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
case "supercooling" | "superfreezing":
entity_class = MieleSuperSwitch

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()


class MieleSwitch(MieleEntity, SwitchEntity):
Expand Down
2 changes: 1 addition & 1 deletion tests/components/miele/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Loading