Discovery of Miele temperature sensors (#144585)

Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>
This commit is contained in:
Andrea Turri 2025-07-15 12:50:28 +02:00 committed by GitHub
parent ee4325a927
commit 7d06aec8da
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
14 changed files with 4015 additions and 80 deletions

View File

@ -16,6 +16,11 @@ class MieleEntity(CoordinatorEntity[MieleDataUpdateCoordinator]):
_attr_has_entity_name = True _attr_has_entity_name = True
@staticmethod
def get_unique_id(device_id: str, description: EntityDescription) -> str:
"""Generate a unique ID for the entity."""
return f"{device_id}-{description.key}"
def __init__( def __init__(
self, self,
coordinator: MieleDataUpdateCoordinator, coordinator: MieleDataUpdateCoordinator,
@ -26,7 +31,7 @@ class MieleEntity(CoordinatorEntity[MieleDataUpdateCoordinator]):
super().__init__(coordinator) super().__init__(coordinator)
self._device_id = device_id self._device_id = device_id
self.entity_description = description self.entity_description = description
self._attr_unique_id = f"{device_id}-{description.key}" self._attr_unique_id = MieleEntity.get_unique_id(device_id, description)
device = self.device device = self.device
appliance_type = DEVICE_TYPE_TAGS.get(MieleAppliance(device.device_type)) appliance_type = DEVICE_TYPE_TAGS.get(MieleAppliance(device.device_type))

View File

@ -7,7 +7,7 @@ from dataclasses import dataclass
import logging import logging
from typing import Final, cast from typing import Final, cast
from pymiele import MieleDevice from pymiele import MieleDevice, MieleTemperature
from homeassistant.components.sensor import ( from homeassistant.components.sensor import (
SensorDeviceClass, SensorDeviceClass,
@ -25,10 +25,13 @@ from homeassistant.const import (
UnitOfVolume, UnitOfVolume,
) )
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_registry as er
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
from homeassistant.helpers.typing import StateType from homeassistant.helpers.typing import StateType
from .const import ( from .const import (
DISABLED_TEMP_ENTITIES,
DOMAIN,
STATE_PROGRAM_ID, STATE_PROGRAM_ID,
STATE_PROGRAM_PHASE, STATE_PROGRAM_PHASE,
STATE_STATUS_TAGS, STATE_STATUS_TAGS,
@ -45,8 +48,6 @@ PARALLEL_UPDATES = 0
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
DISABLED_TEMPERATURE = -32768
DEFAULT_PLATE_COUNT = 4 DEFAULT_PLATE_COUNT = 4
PLATE_COUNT = { PLATE_COUNT = {
@ -75,12 +76,25 @@ def _convert_duration(value_list: list[int]) -> int | None:
return value_list[0] * 60 + value_list[1] if value_list else None return value_list[0] * 60 + value_list[1] if value_list else None
def _convert_temperature(
value_list: list[MieleTemperature], index: int
) -> float | None:
"""Convert temperature object to readable value."""
if index >= len(value_list):
return None
raw_value = cast(int, value_list[index].temperature) / 100.0
if raw_value in DISABLED_TEMP_ENTITIES:
return None
return raw_value
@dataclass(frozen=True, kw_only=True) @dataclass(frozen=True, kw_only=True)
class MieleSensorDescription(SensorEntityDescription): class MieleSensorDescription(SensorEntityDescription):
"""Class describing Miele sensor entities.""" """Class describing Miele sensor entities."""
value_fn: Callable[[MieleDevice], StateType] value_fn: Callable[[MieleDevice], StateType]
zone: int = 1 zone: int | None = None
unique_id_fn: Callable[[str, MieleSensorDescription], str] | None = None
@dataclass @dataclass
@ -404,32 +418,20 @@ SENSOR_TYPES: Final[tuple[MieleSensorDefinition, ...]] = (
), ),
description=MieleSensorDescription( description=MieleSensorDescription(
key="state_temperature_1", key="state_temperature_1",
zone=1,
device_class=SensorDeviceClass.TEMPERATURE, device_class=SensorDeviceClass.TEMPERATURE,
native_unit_of_measurement=UnitOfTemperature.CELSIUS, native_unit_of_measurement=UnitOfTemperature.CELSIUS,
state_class=SensorStateClass.MEASUREMENT, state_class=SensorStateClass.MEASUREMENT,
value_fn=lambda value: cast(int, value.state_temperatures[0].temperature) value_fn=lambda value: _convert_temperature(value.state_temperatures, 0),
/ 100.0,
), ),
), ),
MieleSensorDefinition( MieleSensorDefinition(
types=( types=(
MieleAppliance.TUMBLE_DRYER_SEMI_PROFESSIONAL,
MieleAppliance.OVEN,
MieleAppliance.OVEN_MICROWAVE,
MieleAppliance.DISH_WARMER,
MieleAppliance.STEAM_OVEN,
MieleAppliance.MICROWAVE,
MieleAppliance.FRIDGE,
MieleAppliance.FREEZER,
MieleAppliance.FRIDGE_FREEZER, MieleAppliance.FRIDGE_FREEZER,
MieleAppliance.STEAM_OVEN_COMBI,
MieleAppliance.WINE_CABINET, MieleAppliance.WINE_CABINET,
MieleAppliance.WINE_CONDITIONING_UNIT, MieleAppliance.WINE_CONDITIONING_UNIT,
MieleAppliance.WINE_STORAGE_CONDITIONING_UNIT, MieleAppliance.WINE_STORAGE_CONDITIONING_UNIT,
MieleAppliance.STEAM_OVEN_MICRO,
MieleAppliance.DIALOG_OVEN,
MieleAppliance.WINE_CABINET_FREEZER, MieleAppliance.WINE_CABINET_FREEZER,
MieleAppliance.STEAM_OVEN_MK2,
), ),
description=MieleSensorDescription( description=MieleSensorDescription(
key="state_temperature_2", key="state_temperature_2",
@ -438,7 +440,24 @@ SENSOR_TYPES: Final[tuple[MieleSensorDefinition, ...]] = (
translation_key="temperature_zone_2", translation_key="temperature_zone_2",
native_unit_of_measurement=UnitOfTemperature.CELSIUS, native_unit_of_measurement=UnitOfTemperature.CELSIUS,
state_class=SensorStateClass.MEASUREMENT, state_class=SensorStateClass.MEASUREMENT,
value_fn=lambda value: value.state_temperatures[1].temperature / 100.0, # type: ignore [operator] value_fn=lambda value: _convert_temperature(value.state_temperatures, 1),
),
),
MieleSensorDefinition(
types=(
MieleAppliance.WINE_CABINET,
MieleAppliance.WINE_CONDITIONING_UNIT,
MieleAppliance.WINE_STORAGE_CONDITIONING_UNIT,
MieleAppliance.WINE_CABINET_FREEZER,
),
description=MieleSensorDescription(
key="state_temperature_3",
zone=3,
device_class=SensorDeviceClass.TEMPERATURE,
translation_key="temperature_zone_3",
native_unit_of_measurement=UnitOfTemperature.CELSIUS,
state_class=SensorStateClass.MEASUREMENT,
value_fn=lambda value: _convert_temperature(value.state_temperatures, 2),
), ),
), ),
MieleSensorDefinition( MieleSensorDefinition(
@ -454,11 +473,8 @@ SENSOR_TYPES: Final[tuple[MieleSensorDefinition, ...]] = (
device_class=SensorDeviceClass.TEMPERATURE, device_class=SensorDeviceClass.TEMPERATURE,
native_unit_of_measurement=UnitOfTemperature.CELSIUS, native_unit_of_measurement=UnitOfTemperature.CELSIUS,
state_class=SensorStateClass.MEASUREMENT, state_class=SensorStateClass.MEASUREMENT,
value_fn=( value_fn=lambda value: _convert_temperature(
lambda value: cast( value.state_core_target_temperature, 0
int, value.state_core_target_temperature[0].temperature
)
/ 100.0
), ),
), ),
), ),
@ -479,9 +495,8 @@ SENSOR_TYPES: Final[tuple[MieleSensorDefinition, ...]] = (
device_class=SensorDeviceClass.TEMPERATURE, device_class=SensorDeviceClass.TEMPERATURE,
native_unit_of_measurement=UnitOfTemperature.CELSIUS, native_unit_of_measurement=UnitOfTemperature.CELSIUS,
state_class=SensorStateClass.MEASUREMENT, state_class=SensorStateClass.MEASUREMENT,
value_fn=( value_fn=lambda value: _convert_temperature(
lambda value: cast(int, value.state_target_temperature[0].temperature) value.state_target_temperature, 0
/ 100.0
), ),
), ),
), ),
@ -497,9 +512,8 @@ SENSOR_TYPES: Final[tuple[MieleSensorDefinition, ...]] = (
device_class=SensorDeviceClass.TEMPERATURE, device_class=SensorDeviceClass.TEMPERATURE,
native_unit_of_measurement=UnitOfTemperature.CELSIUS, native_unit_of_measurement=UnitOfTemperature.CELSIUS,
state_class=SensorStateClass.MEASUREMENT, state_class=SensorStateClass.MEASUREMENT,
value_fn=( value_fn=lambda value: _convert_temperature(
lambda value: cast(int, value.state_core_temperature[0].temperature) value.state_core_temperature, 0
/ 100.0
), ),
), ),
), ),
@ -518,6 +532,8 @@ SENSOR_TYPES: Final[tuple[MieleSensorDefinition, ...]] = (
device_class=SensorDeviceClass.ENUM, device_class=SensorDeviceClass.ENUM,
options=sorted(PlatePowerStep.keys()), options=sorted(PlatePowerStep.keys()),
value_fn=lambda value: None, value_fn=lambda value: None,
unique_id_fn=lambda device_id,
description: f"{device_id}-{description.key}-{description.zone}",
), ),
) )
for i in range(1, 7) for i in range(1, 7)
@ -559,10 +575,52 @@ async def async_setup_entry(
) -> None: ) -> None:
"""Set up the sensor platform.""" """Set up the sensor platform."""
coordinator = config_entry.runtime_data coordinator = config_entry.runtime_data
added_devices: set[str] = set() added_devices: set[str] = set() # device_id
added_entities: set[str] = set() # unique_id
def _async_add_new_devices() -> None: def _get_entity_class(definition: MieleSensorDefinition) -> type[MieleSensor]:
nonlocal added_devices """Get the entity class for the sensor."""
return {
"state_status": MieleStatusSensor,
"state_program_id": MieleProgramIdSensor,
"state_program_phase": MielePhaseSensor,
"state_plate_step": MielePlateSensor,
}.get(definition.description.key, MieleSensor)
def _is_entity_registered(unique_id: str) -> bool:
"""Check if the entity is already registered."""
entity_registry = er.async_get(hass)
return any(
entry.platform == DOMAIN and entry.unique_id == unique_id
for entry in entity_registry.entities.values()
)
def _is_sensor_enabled(
definition: MieleSensorDefinition,
device: MieleDevice,
unique_id: str,
) -> bool:
"""Check if the sensor is enabled."""
if (
definition.description.device_class == SensorDeviceClass.TEMPERATURE
and definition.description.value_fn(device) is None
and definition.description.zone != 1
):
# all appliances supporting temperature have at least zone 1, for other zones
# don't create entity if API signals that datapoint is disabled, unless the sensor
# already appeared in the past (= it provided a valid value)
return _is_entity_registered(unique_id)
if (
definition.description.key == "state_plate_step"
and definition.description.zone is not None
and definition.description.zone > _get_plate_count(device.tech_type)
):
# don't create plate entity if not expected by the appliance tech type
return False
return True
def _async_add_devices() -> None:
nonlocal added_devices, added_entities
entities: list = [] entities: list = []
entity_class: type[MieleSensor] entity_class: type[MieleSensor]
new_devices_set, current_devices = coordinator.async_add_devices(added_devices) new_devices_set, current_devices = coordinator.async_add_devices(added_devices)
@ -570,40 +628,35 @@ async def async_setup_entry(
for device_id, device in coordinator.data.devices.items(): for device_id, device in coordinator.data.devices.items():
for definition in SENSOR_TYPES: for definition in SENSOR_TYPES:
if ( # device is not supported, skip
device_id in new_devices_set if device.device_type not in definition.types:
and device.device_type in definition.types continue
):
match definition.description.key: entity_class = _get_entity_class(definition)
case "state_status": unique_id = (
entity_class = MieleStatusSensor definition.description.unique_id_fn(
case "state_program_id": device_id, definition.description
entity_class = MieleProgramIdSensor
case "state_program_phase":
entity_class = MielePhaseSensor
case "state_plate_step":
entity_class = MielePlateSensor
case _:
entity_class = MieleSensor
if (
definition.description.device_class
== SensorDeviceClass.TEMPERATURE
and definition.description.value_fn(device)
== DISABLED_TEMPERATURE / 100
) or (
definition.description.key == "state_plate_step"
and definition.description.zone
> _get_plate_count(device.tech_type)
):
# Don't create entity if API signals that datapoint is disabled
continue
entities.append(
entity_class(coordinator, device_id, definition.description)
) )
if definition.description.unique_id_fn is not None
else MieleEntity.get_unique_id(device_id, definition.description)
)
# entity was already added, skip
if device_id not in new_devices_set and unique_id in added_entities:
continue
# sensors is not enabled, skip
if not _is_sensor_enabled(definition, device, unique_id):
continue
added_entities.add(unique_id)
entities.append(
entity_class(coordinator, device_id, definition.description)
)
async_add_entities(entities) async_add_entities(entities)
config_entry.async_on_unload(coordinator.async_add_listener(_async_add_new_devices)) config_entry.async_on_unload(coordinator.async_add_listener(_async_add_devices))
_async_add_new_devices() _async_add_devices()
APPLIANCE_ICONS = { APPLIANCE_ICONS = {
@ -641,6 +694,17 @@ class MieleSensor(MieleEntity, SensorEntity):
entity_description: MieleSensorDescription entity_description: MieleSensorDescription
def __init__(
self,
coordinator: MieleDataUpdateCoordinator,
device_id: str,
description: MieleSensorDescription,
) -> None:
"""Initialize the sensor."""
super().__init__(coordinator, device_id, description)
if description.unique_id_fn is not None:
self._attr_unique_id = description.unique_id_fn(device_id, description)
@property @property
def native_value(self) -> StateType: def native_value(self) -> StateType:
"""Return the state of the sensor.""" """Return the state of the sensor."""
@ -652,16 +716,6 @@ class MielePlateSensor(MieleSensor):
entity_description: MieleSensorDescription entity_description: MieleSensorDescription
def __init__(
self,
coordinator: MieleDataUpdateCoordinator,
device_id: str,
description: MieleSensorDescription,
) -> None:
"""Initialize the plate sensor."""
super().__init__(coordinator, device_id, description)
self._attr_unique_id = f"{device_id}-{description.key}-{description.zone}"
@property @property
def native_value(self) -> StateType: def native_value(self) -> StateType:
"""Return the state of the plate sensor.""" """Return the state of the plate sensor."""
@ -672,7 +726,7 @@ class MielePlateSensor(MieleSensor):
cast( cast(
int, int,
self.device.state_plate_step[ self.device.state_plate_step[
self.entity_description.zone - 1 cast(int, self.entity_description.zone) - 1
].value_raw, ].value_raw,
) )
).name ).name

View File

@ -82,5 +82,20 @@
"colors": [], "colors": [],
"modes": [], "modes": [],
"runOnTime": [] "runOnTime": []
},
"DummyAppliance_12": {
"processAction": [],
"light": [2],
"ambientLight": [],
"startTime": [],
"ventilationStep": [],
"programId": [],
"targetTemperature": [],
"deviceName": true,
"powerOn": false,
"powerOff": true,
"colors": [],
"modes": [],
"runOnTime": []
} }
} }

View File

@ -466,5 +466,129 @@
"ecoFeedback": null, "ecoFeedback": null,
"batteryLevel": null "batteryLevel": null
} }
},
"DummyAppliance_12": {
"ident": {
"type": {
"key_localized": "Device type",
"value_raw": 12,
"value_localized": "Oven"
},
"deviceName": "",
"protocolVersion": 4,
"deviceIdentLabel": {
"fabNumber": "**REDACTED**",
"fabIndex": "16",
"techType": "H7660BP",
"matNumber": "11120960",
"swids": []
},
"xkmIdentLabel": {
"techType": "EK057",
"releaseVersion": "08.32"
}
},
"state": {
"ProgramID": {
"value_raw": 356,
"value_localized": "Defrost",
"key_localized": "Program name"
},
"status": {
"value_raw": 5,
"value_localized": "In use",
"key_localized": "status"
},
"programType": {
"value_raw": 1,
"value_localized": "Program",
"key_localized": "Program type"
},
"programPhase": {
"value_raw": 3073,
"value_localized": "Heating-up phase",
"key_localized": "Program phase"
},
"remainingTime": [0, 5],
"startTime": [0, 0],
"targetTemperature": [
{
"value_raw": 2500,
"value_localized": 25.0,
"unit": "Celsius"
},
{
"value_raw": -32768,
"value_localized": null,
"unit": "Celsius"
},
{
"value_raw": -32768,
"value_localized": null,
"unit": "Celsius"
}
],
"coreTargetTemperature": [
{
"value_raw": -32768,
"value_localized": null,
"unit": "Celsius"
}
],
"temperature": [
{
"value_raw": 1954,
"value_localized": 19.54,
"unit": "Celsius"
},
{
"value_raw": -32768,
"value_localized": null,
"unit": "Celsius"
},
{
"value_raw": -32768,
"value_localized": null,
"unit": "Celsius"
}
],
"coreTemperature": [
{
"value_raw": 2200,
"value_localized": 22.0,
"unit": "Celsius"
}
],
"signalInfo": false,
"signalFailure": false,
"signalDoor": false,
"remoteEnable": {
"fullRemoteControl": true,
"smartGrid": false,
"mobileStart": true
},
"ambientLight": null,
"light": 1,
"elapsedTime": [0, 0],
"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": null,
"value_localized": "",
"key_localized": "Fan level"
},
"plateStep": [],
"ecoFeedback": null,
"batteryLevel": null
}
} }
} }

View File

@ -0,0 +1,109 @@
{
"DummyAppliance_Fridge_Freezer": {
"ident": {
"type": {
"key_localized": "Device type",
"value_raw": 21,
"value_localized": "Fridge freezer"
},
"deviceName": "",
"protocolVersion": 203,
"deviceIdentLabel": {
"fabNumber": "**REDACTED**",
"fabIndex": "00",
"techType": "KFN 7734 C",
"matNumber": "12336150",
"swids": []
},
"xkmIdentLabel": {
"techType": "EK037LHBM",
"releaseVersion": "32.33"
}
},
"state": {
"ProgramID": {
"value_raw": 0,
"value_localized": "",
"key_localized": "Program name"
},
"status": {
"value_raw": 5,
"value_localized": "In use",
"key_localized": "status"
},
"programType": {
"value_raw": 0,
"value_localized": "",
"key_localized": "Program type"
},
"programPhase": {
"value_raw": 0,
"value_localized": "",
"key_localized": "Program phase"
},
"remainingTime": [0, 0],
"startTime": [0, 0],
"targetTemperature": [
{
"value_raw": 400,
"value_localized": 4.0,
"unit": "Celsius"
},
{
"value_raw": -1800,
"value_localized": -18.0,
"unit": "Celsius"
}
],
"coreTargetTemperature": [],
"temperature": [
{
"value_raw": 400,
"value_localized": 4.0,
"unit": "Celsius"
},
{
"value_raw": -1800,
"value_localized": -18.0,
"unit": "Celsius"
},
{
"value_raw": -32768,
"value_localized": null,
"unit": "Celsius"
}
],
"coreTemperature": [],
"signalInfo": false,
"signalFailure": false,
"signalDoor": false,
"remoteEnable": {
"fullRemoteControl": true,
"smartGrid": false,
"mobileStart": false
},
"ambientLight": null,
"light": null,
"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": null,
"value_localized": "",
"key_localized": "Fan level"
},
"plateStep": [],
"ecoFeedback": null,
"batteryLevel": null
}
}
}

View File

@ -0,0 +1,142 @@
{
"DummyOven": {
"ident": {
"type": {
"key_localized": "Device type",
"value_raw": 12,
"value_localized": "Oven"
},
"deviceName": "",
"protocolVersion": 4,
"deviceIdentLabel": {
"fabNumber": "**REDACTED**",
"fabIndex": "16",
"techType": "H7660BP",
"matNumber": "11120960",
"swids": [
"6166",
"25211",
"25210",
"4860",
"25245",
"6153",
"6050",
"25300",
"25307",
"25247",
"20570",
"25223",
"5640",
"20366",
"20462"
]
},
"xkmIdentLabel": {
"techType": "EK057",
"releaseVersion": "08.32"
}
},
"state": {
"ProgramID": {
"value_raw": 0,
"value_localized": "",
"key_localized": "Program name"
},
"status": {
"value_raw": 1,
"value_localized": "Off",
"key_localized": "status"
},
"programType": {
"value_raw": 0,
"value_localized": "",
"key_localized": "Program type"
},
"programPhase": {
"value_raw": 0,
"value_localized": "",
"key_localized": "Program phase"
},
"remainingTime": [0, 0],
"startTime": [0, 0],
"targetTemperature": [
{
"value_raw": -32768,
"value_localized": null,
"unit": "Celsius"
},
{
"value_raw": -32768,
"value_localized": null,
"unit": "Celsius"
},
{
"value_raw": -32768,
"value_localized": null,
"unit": "Celsius"
}
],
"coreTargetTemperature": [
{
"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"
}
],
"coreTemperature": [
{
"value_raw": -32768,
"value_localized": null,
"unit": "Celsius"
}
],
"signalInfo": false,
"signalFailure": false,
"signalDoor": false,
"remoteEnable": {
"fullRemoteControl": true,
"smartGrid": false,
"mobileStart": false
},
"ambientLight": null,
"light": null,
"elapsedTime": [0, 0],
"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": null,
"value_localized": "",
"key_localized": "Fan level"
},
"plateStep": [],
"ecoFeedback": null,
"batteryLevel": null
}
}
}

View File

@ -532,6 +532,297 @@
'state': 'off', 'state': 'off',
}) })
# --- # ---
# name: test_binary_sensor_states[platforms0][binary_sensor.oven_door-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'binary_sensor',
'entity_category': None,
'entity_id': 'binary_sensor.oven_door',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': <BinarySensorDeviceClass.DOOR: 'door'>,
'original_icon': None,
'original_name': 'Door',
'platform': 'miele',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': 'DummyAppliance_12-state_signal_door',
'unit_of_measurement': None,
})
# ---
# name: test_binary_sensor_states[platforms0][binary_sensor.oven_door-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'door',
'friendly_name': 'Oven Door',
}),
'context': <ANY>,
'entity_id': 'binary_sensor.oven_door',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'off',
})
# ---
# name: test_binary_sensor_states[platforms0][binary_sensor.oven_mobile_start-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'binary_sensor',
'entity_category': <EntityCategory.DIAGNOSTIC: 'diagnostic'>,
'entity_id': 'binary_sensor.oven_mobile_start',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': None,
'original_icon': None,
'original_name': 'Mobile start',
'platform': 'miele',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'mobile_start',
'unique_id': 'DummyAppliance_12-state_mobile_start',
'unit_of_measurement': None,
})
# ---
# name: test_binary_sensor_states[platforms0][binary_sensor.oven_mobile_start-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'friendly_name': 'Oven Mobile start',
}),
'context': <ANY>,
'entity_id': 'binary_sensor.oven_mobile_start',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'on',
})
# ---
# name: test_binary_sensor_states[platforms0][binary_sensor.oven_notification_active-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'binary_sensor',
'entity_category': <EntityCategory.DIAGNOSTIC: 'diagnostic'>,
'entity_id': 'binary_sensor.oven_notification_active',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': <BinarySensorDeviceClass.PROBLEM: 'problem'>,
'original_icon': None,
'original_name': 'Notification active',
'platform': 'miele',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'notification_active',
'unique_id': 'DummyAppliance_12-state_signal_info',
'unit_of_measurement': None,
})
# ---
# name: test_binary_sensor_states[platforms0][binary_sensor.oven_notification_active-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'problem',
'friendly_name': 'Oven Notification active',
}),
'context': <ANY>,
'entity_id': 'binary_sensor.oven_notification_active',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'off',
})
# ---
# name: test_binary_sensor_states[platforms0][binary_sensor.oven_problem-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'binary_sensor',
'entity_category': <EntityCategory.DIAGNOSTIC: 'diagnostic'>,
'entity_id': 'binary_sensor.oven_problem',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': <BinarySensorDeviceClass.PROBLEM: 'problem'>,
'original_icon': None,
'original_name': 'Problem',
'platform': 'miele',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': 'DummyAppliance_12-state_signal_failure',
'unit_of_measurement': None,
})
# ---
# name: test_binary_sensor_states[platforms0][binary_sensor.oven_problem-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'problem',
'friendly_name': 'Oven Problem',
}),
'context': <ANY>,
'entity_id': 'binary_sensor.oven_problem',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'off',
})
# ---
# name: test_binary_sensor_states[platforms0][binary_sensor.oven_remote_control-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'binary_sensor',
'entity_category': <EntityCategory.DIAGNOSTIC: 'diagnostic'>,
'entity_id': 'binary_sensor.oven_remote_control',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': None,
'original_icon': None,
'original_name': 'Remote control',
'platform': 'miele',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'remote_control',
'unique_id': 'DummyAppliance_12-state_full_remote_control',
'unit_of_measurement': None,
})
# ---
# name: test_binary_sensor_states[platforms0][binary_sensor.oven_remote_control-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'friendly_name': 'Oven Remote control',
}),
'context': <ANY>,
'entity_id': 'binary_sensor.oven_remote_control',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'on',
})
# ---
# name: test_binary_sensor_states[platforms0][binary_sensor.oven_smart_grid-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'binary_sensor',
'entity_category': <EntityCategory.DIAGNOSTIC: 'diagnostic'>,
'entity_id': 'binary_sensor.oven_smart_grid',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': None,
'original_icon': None,
'original_name': 'Smart grid',
'platform': 'miele',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'smart_grid',
'unique_id': 'DummyAppliance_12-state_smart_grid',
'unit_of_measurement': None,
})
# ---
# name: test_binary_sensor_states[platforms0][binary_sensor.oven_smart_grid-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'friendly_name': 'Oven Smart grid',
}),
'context': <ANY>,
'entity_id': 'binary_sensor.oven_smart_grid',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'off',
})
# ---
# name: test_binary_sensor_states[platforms0][binary_sensor.refrigerator_door-entry] # name: test_binary_sensor_states[platforms0][binary_sensor.refrigerator_door-entry]
EntityRegistryEntrySnapshot({ EntityRegistryEntrySnapshot({
'aliases': set({ 'aliases': set({
@ -1647,6 +1938,297 @@
'state': 'off', 'state': 'off',
}) })
# --- # ---
# name: test_binary_sensor_states_api_push[platforms0][binary_sensor.oven_door-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'binary_sensor',
'entity_category': None,
'entity_id': 'binary_sensor.oven_door',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': <BinarySensorDeviceClass.DOOR: 'door'>,
'original_icon': None,
'original_name': 'Door',
'platform': 'miele',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': 'DummyAppliance_12-state_signal_door',
'unit_of_measurement': None,
})
# ---
# name: test_binary_sensor_states_api_push[platforms0][binary_sensor.oven_door-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'door',
'friendly_name': 'Oven Door',
}),
'context': <ANY>,
'entity_id': 'binary_sensor.oven_door',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'off',
})
# ---
# name: test_binary_sensor_states_api_push[platforms0][binary_sensor.oven_mobile_start-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'binary_sensor',
'entity_category': <EntityCategory.DIAGNOSTIC: 'diagnostic'>,
'entity_id': 'binary_sensor.oven_mobile_start',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': None,
'original_icon': None,
'original_name': 'Mobile start',
'platform': 'miele',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'mobile_start',
'unique_id': 'DummyAppliance_12-state_mobile_start',
'unit_of_measurement': None,
})
# ---
# name: test_binary_sensor_states_api_push[platforms0][binary_sensor.oven_mobile_start-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'friendly_name': 'Oven Mobile start',
}),
'context': <ANY>,
'entity_id': 'binary_sensor.oven_mobile_start',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'on',
})
# ---
# name: test_binary_sensor_states_api_push[platforms0][binary_sensor.oven_notification_active-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'binary_sensor',
'entity_category': <EntityCategory.DIAGNOSTIC: 'diagnostic'>,
'entity_id': 'binary_sensor.oven_notification_active',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': <BinarySensorDeviceClass.PROBLEM: 'problem'>,
'original_icon': None,
'original_name': 'Notification active',
'platform': 'miele',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'notification_active',
'unique_id': 'DummyAppliance_12-state_signal_info',
'unit_of_measurement': None,
})
# ---
# name: test_binary_sensor_states_api_push[platforms0][binary_sensor.oven_notification_active-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'problem',
'friendly_name': 'Oven Notification active',
}),
'context': <ANY>,
'entity_id': 'binary_sensor.oven_notification_active',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'off',
})
# ---
# name: test_binary_sensor_states_api_push[platforms0][binary_sensor.oven_problem-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'binary_sensor',
'entity_category': <EntityCategory.DIAGNOSTIC: 'diagnostic'>,
'entity_id': 'binary_sensor.oven_problem',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': <BinarySensorDeviceClass.PROBLEM: 'problem'>,
'original_icon': None,
'original_name': 'Problem',
'platform': 'miele',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': 'DummyAppliance_12-state_signal_failure',
'unit_of_measurement': None,
})
# ---
# name: test_binary_sensor_states_api_push[platforms0][binary_sensor.oven_problem-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'problem',
'friendly_name': 'Oven Problem',
}),
'context': <ANY>,
'entity_id': 'binary_sensor.oven_problem',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'off',
})
# ---
# name: test_binary_sensor_states_api_push[platforms0][binary_sensor.oven_remote_control-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'binary_sensor',
'entity_category': <EntityCategory.DIAGNOSTIC: 'diagnostic'>,
'entity_id': 'binary_sensor.oven_remote_control',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': None,
'original_icon': None,
'original_name': 'Remote control',
'platform': 'miele',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'remote_control',
'unique_id': 'DummyAppliance_12-state_full_remote_control',
'unit_of_measurement': None,
})
# ---
# name: test_binary_sensor_states_api_push[platforms0][binary_sensor.oven_remote_control-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'friendly_name': 'Oven Remote control',
}),
'context': <ANY>,
'entity_id': 'binary_sensor.oven_remote_control',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'on',
})
# ---
# name: test_binary_sensor_states_api_push[platforms0][binary_sensor.oven_smart_grid-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'binary_sensor',
'entity_category': <EntityCategory.DIAGNOSTIC: 'diagnostic'>,
'entity_id': 'binary_sensor.oven_smart_grid',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': None,
'original_icon': None,
'original_name': 'Smart grid',
'platform': 'miele',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'smart_grid',
'unique_id': 'DummyAppliance_12-state_smart_grid',
'unit_of_measurement': None,
})
# ---
# name: test_binary_sensor_states_api_push[platforms0][binary_sensor.oven_smart_grid-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'friendly_name': 'Oven Smart grid',
}),
'context': <ANY>,
'entity_id': 'binary_sensor.oven_smart_grid',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'off',
})
# ---
# name: test_binary_sensor_states_api_push[platforms0][binary_sensor.refrigerator_door-entry] # name: test_binary_sensor_states_api_push[platforms0][binary_sensor.refrigerator_door-entry]
EntityRegistryEntrySnapshot({ EntityRegistryEntrySnapshot({
'aliases': set({ 'aliases': set({

View File

@ -47,6 +47,102 @@
'state': 'unknown', 'state': 'unknown',
}) })
# --- # ---
# name: test_button_states[platforms0][button.oven_start-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'button',
'entity_category': None,
'entity_id': 'button.oven_start',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': None,
'original_icon': None,
'original_name': 'Start',
'platform': 'miele',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'start',
'unique_id': 'DummyAppliance_12-start',
'unit_of_measurement': None,
})
# ---
# name: test_button_states[platforms0][button.oven_start-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'friendly_name': 'Oven Start',
}),
'context': <ANY>,
'entity_id': 'button.oven_start',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'unknown',
})
# ---
# name: test_button_states[platforms0][button.oven_stop-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'button',
'entity_category': None,
'entity_id': 'button.oven_stop',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': None,
'original_icon': None,
'original_name': 'Stop',
'platform': 'miele',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'stop',
'unique_id': 'DummyAppliance_12-stop',
'unit_of_measurement': None,
})
# ---
# name: test_button_states[platforms0][button.oven_stop-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'friendly_name': 'Oven Stop',
}),
'context': <ANY>,
'entity_id': 'button.oven_stop',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'unknown',
})
# ---
# name: test_button_states[platforms0][button.washing_machine_pause-entry] # name: test_button_states[platforms0][button.washing_machine_pause-entry]
EntityRegistryEntrySnapshot({ EntityRegistryEntrySnapshot({
'aliases': set({ 'aliases': set({
@ -239,6 +335,102 @@
'state': 'unavailable', 'state': 'unavailable',
}) })
# --- # ---
# name: test_button_states_api_push[platforms0][button.oven_start-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'button',
'entity_category': None,
'entity_id': 'button.oven_start',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': None,
'original_icon': None,
'original_name': 'Start',
'platform': 'miele',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'start',
'unique_id': 'DummyAppliance_12-start',
'unit_of_measurement': None,
})
# ---
# name: test_button_states_api_push[platforms0][button.oven_start-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'friendly_name': 'Oven Start',
}),
'context': <ANY>,
'entity_id': 'button.oven_start',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'unavailable',
})
# ---
# name: test_button_states_api_push[platforms0][button.oven_stop-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'button',
'entity_category': None,
'entity_id': 'button.oven_stop',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': None,
'original_icon': None,
'original_name': 'Stop',
'platform': 'miele',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'stop',
'unique_id': 'DummyAppliance_12-stop',
'unit_of_measurement': None,
})
# ---
# name: test_button_states_api_push[platforms0][button.oven_stop-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'friendly_name': 'Oven Stop',
}),
'context': <ANY>,
'entity_id': 'button.oven_stop',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'unavailable',
})
# ---
# name: test_button_states_api_push[platforms0][button.washing_machine_pause-entry] # name: test_button_states_api_push[platforms0][button.washing_machine_pause-entry]
EntityRegistryEntrySnapshot({ EntityRegistryEntrySnapshot({
'aliases': set({ 'aliases': set({

View File

@ -144,6 +144,39 @@
'ventilationStep': list([ 'ventilationStep': list([
]), ]),
}), }),
'**REDACTED_e7bc6793e305bf53': dict({
'ambientLight': list([
]),
'colors': list([
]),
'deviceName': True,
'light': list([
]),
'modes': list([
]),
'powerOff': False,
'powerOn': True,
'processAction': list([
1,
2,
3,
]),
'programId': list([
]),
'runOnTime': list([
]),
'startTime': list([
]),
'targetTemperature': list([
dict({
'max': 28,
'min': -28,
'zone': 1,
}),
]),
'ventilationStep': list([
]),
}),
}), }),
'devices': dict({ 'devices': dict({
'**REDACTED_019aa577ad1c330d': dict({ '**REDACTED_019aa577ad1c330d': dict({
@ -661,6 +694,141 @@
}), }),
}), }),
}), }),
'**REDACTED_e7bc6793e305bf53': dict({
'ident': dict({
'deviceIdentLabel': dict({
'fabIndex': '16',
'fabNumber': '**REDACTED**',
'matNumber': '11120960',
'swids': list([
]),
'techType': 'H7660BP',
}),
'deviceName': '',
'protocolVersion': 4,
'type': dict({
'key_localized': 'Device type',
'value_localized': 'Oven',
'value_raw': 12,
}),
'xkmIdentLabel': dict({
'releaseVersion': '08.32',
'techType': 'EK057',
}),
}),
'state': dict({
'ProgramID': dict({
'key_localized': 'Program name',
'value_localized': 'Defrost',
'value_raw': 356,
}),
'ambientLight': None,
'batteryLevel': None,
'coreTargetTemperature': list([
dict({
'unit': 'Celsius',
'value_localized': None,
'value_raw': -32768,
}),
]),
'coreTemperature': list([
dict({
'unit': 'Celsius',
'value_localized': 22.0,
'value_raw': 2200,
}),
]),
'dryingStep': dict({
'key_localized': 'Drying level',
'value_localized': '',
'value_raw': None,
}),
'ecoFeedback': None,
'elapsedTime': list([
0,
0,
]),
'light': 1,
'plateStep': list([
]),
'programPhase': dict({
'key_localized': 'Program phase',
'value_localized': 'Heating-up phase',
'value_raw': 3073,
}),
'programType': dict({
'key_localized': 'Program type',
'value_localized': 'Program',
'value_raw': 1,
}),
'remainingTime': list([
0,
5,
]),
'remoteEnable': dict({
'fullRemoteControl': True,
'mobileStart': True,
'smartGrid': False,
}),
'signalDoor': False,
'signalFailure': False,
'signalInfo': False,
'spinningSpeed': dict({
'key_localized': 'Spin speed',
'unit': 'rpm',
'value_localized': None,
'value_raw': None,
}),
'startTime': list([
0,
0,
]),
'status': dict({
'key_localized': 'status',
'value_localized': 'In use',
'value_raw': 5,
}),
'targetTemperature': list([
dict({
'unit': 'Celsius',
'value_localized': 25.0,
'value_raw': 2500,
}),
dict({
'unit': 'Celsius',
'value_localized': None,
'value_raw': -32768,
}),
dict({
'unit': 'Celsius',
'value_localized': None,
'value_raw': -32768,
}),
]),
'temperature': list([
dict({
'unit': 'Celsius',
'value_localized': 19.54,
'value_raw': 1954,
}),
dict({
'unit': 'Celsius',
'value_localized': None,
'value_raw': -32768,
}),
dict({
'unit': 'Celsius',
'value_localized': None,
'value_raw': -32768,
}),
]),
'ventilationStep': dict({
'key_localized': 'Fan level',
'value_localized': '',
'value_raw': None,
}),
}),
}),
}), }),
'missing_code_warnings': list([ 'missing_code_warnings': list([
'None', 'None',

View File

@ -113,6 +113,63 @@
'state': 'on', 'state': 'on',
}) })
# --- # ---
# name: test_light_states[platforms0][light.oven_light-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': dict({
'supported_color_modes': list([
<ColorMode.ONOFF: 'onoff'>,
]),
}),
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'light',
'entity_category': None,
'entity_id': 'light.oven_light',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': None,
'original_icon': None,
'original_name': 'Light',
'platform': 'miele',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'light',
'unique_id': 'DummyAppliance_12-light',
'unit_of_measurement': None,
})
# ---
# name: test_light_states[platforms0][light.oven_light-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'color_mode': <ColorMode.ONOFF: 'onoff'>,
'friendly_name': 'Oven Light',
'supported_color_modes': list([
<ColorMode.ONOFF: 'onoff'>,
]),
'supported_features': <LightEntityFeature: 0>,
}),
'context': <ANY>,
'entity_id': 'light.oven_light',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'on',
})
# ---
# name: test_light_states_api_push[platforms0][light.hood_ambient_light-entry] # name: test_light_states_api_push[platforms0][light.hood_ambient_light-entry]
EntityRegistryEntrySnapshot({ EntityRegistryEntrySnapshot({
'aliases': set({ 'aliases': set({
@ -227,3 +284,60 @@
'state': 'on', 'state': 'on',
}) })
# --- # ---
# name: test_light_states_api_push[platforms0][light.oven_light-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': dict({
'supported_color_modes': list([
<ColorMode.ONOFF: 'onoff'>,
]),
}),
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'light',
'entity_category': None,
'entity_id': 'light.oven_light',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': None,
'original_icon': None,
'original_name': 'Light',
'platform': 'miele',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'light',
'unique_id': 'DummyAppliance_12-light',
'unit_of_measurement': None,
})
# ---
# name: test_light_states_api_push[platforms0][light.oven_light-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'color_mode': <ColorMode.ONOFF: 'onoff'>,
'friendly_name': 'Oven Light',
'supported_color_modes': list([
<ColorMode.ONOFF: 'onoff'>,
]),
'supported_features': <LightEntityFeature: 0>,
}),
'context': <ANY>,
'entity_id': 'light.oven_light',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'on',
})
# ---

File diff suppressed because it is too large Load Diff

View File

@ -95,6 +95,54 @@
'state': 'off', 'state': 'off',
}) })
# --- # ---
# name: test_switch_states[platforms0][switch.oven_power-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'switch',
'entity_category': None,
'entity_id': 'switch.oven_power',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': None,
'original_icon': None,
'original_name': 'Power',
'platform': 'miele',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'power',
'unique_id': 'DummyAppliance_12-poweronoff',
'unit_of_measurement': None,
})
# ---
# name: test_switch_states[platforms0][switch.oven_power-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'friendly_name': 'Oven Power',
}),
'context': <ANY>,
'entity_id': 'switch.oven_power',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'off',
})
# ---
# name: test_switch_states[platforms0][switch.refrigerator_supercooling-entry] # name: test_switch_states[platforms0][switch.refrigerator_supercooling-entry]
EntityRegistryEntrySnapshot({ EntityRegistryEntrySnapshot({
'aliases': set({ 'aliases': set({
@ -287,6 +335,54 @@
'state': 'off', 'state': 'off',
}) })
# --- # ---
# name: test_switch_states_api_push[platforms0][switch.oven_power-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'switch',
'entity_category': None,
'entity_id': 'switch.oven_power',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': None,
'original_icon': None,
'original_name': 'Power',
'platform': 'miele',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'power',
'unique_id': 'DummyAppliance_12-poweronoff',
'unit_of_measurement': None,
})
# ---
# name: test_switch_states_api_push[platforms0][switch.oven_power-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'friendly_name': 'Oven Power',
}),
'context': <ANY>,
'entity_id': 'switch.oven_power',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'on',
})
# ---
# name: test_switch_states_api_push[platforms0][switch.refrigerator_supercooling-entry] # name: test_switch_states_api_push[platforms0][switch.refrigerator_supercooling-entry]
EntityRegistryEntrySnapshot({ EntityRegistryEntrySnapshot({
'aliases': set({ 'aliases': set({

View File

@ -109,7 +109,7 @@ async def test_devices_multiple_created_count(
"""Test that multiple devices are created.""" """Test that multiple devices are created."""
await setup_integration(hass, mock_config_entry) await setup_integration(hass, mock_config_entry)
assert len(device_registry.devices) == 4 assert len(device_registry.devices) == 5
async def test_device_info( async def test_device_info(
@ -200,11 +200,13 @@ async def test_setup_all_platforms(
) )
freezer.tick(timedelta(seconds=130)) freezer.tick(timedelta(seconds=130))
prev_devices = len(device_registry.devices)
async_fire_time_changed(hass) async_fire_time_changed(hass)
await hass.async_block_till_done() await hass.async_block_till_done()
assert len(device_registry.devices) == 6 assert len(device_registry.devices) == prev_devices + 2
# Check a sample sensor for each new device # Check a sample sensor for each new device
assert hass.states.get("sensor.dishwasher").state == "in_use" assert hass.states.get("sensor.dishwasher").state == "in_use"
assert hass.states.get("sensor.oven_temperature").state == "175.0" assert hass.states.get("sensor.oven_temperature_2").state == "175.0"

View File

@ -1,15 +1,24 @@
"""Tests for miele sensor module.""" """Tests for miele sensor module."""
from datetime import timedelta
from unittest.mock import MagicMock from unittest.mock import MagicMock
from freezegun.api import FrozenDateTimeFactory
from pymiele import MieleDevices
import pytest import pytest
from syrupy.assertion import SnapshotAssertion from syrupy.assertion import SnapshotAssertion
from homeassistant.components.miele.const import DOMAIN
from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_registry as er from homeassistant.helpers import entity_registry as er
from tests.common import MockConfigEntry, snapshot_platform from tests.common import (
MockConfigEntry,
async_fire_time_changed,
async_load_json_object_fixture,
snapshot_platform,
)
@pytest.mark.parametrize("platforms", [(SENSOR_DOMAIN,)]) @pytest.mark.parametrize("platforms", [(SENSOR_DOMAIN,)])
@ -56,6 +65,184 @@ async def test_hob_sensor_states(
await snapshot_platform(hass, entity_registry, snapshot, setup_platform.entry_id) 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("load_device_file", ["vacuum_device.json"])
@pytest.mark.parametrize("platforms", [(SENSOR_DOMAIN,)]) @pytest.mark.parametrize("platforms", [(SENSOR_DOMAIN,)])
@pytest.mark.usefixtures("entity_registry_enabled_by_default") @pytest.mark.usefixtures("entity_registry_enabled_by_default")