diff --git a/custom_components/miele/__init__.py b/custom_components/miele/__init__.py index 89f192dd..35a48db7 100644 --- a/custom_components/miele/__init__.py +++ b/custom_components/miele/__init__.py @@ -61,6 +61,7 @@ TEST_DATA_23, TEST_DATA_24, TEST_DATA_27, + TEST_DATA_27_OFF, TEST_DATA_74, ) from .services import async_setup_services @@ -207,7 +208,8 @@ async def _callback_update_data(data) -> None: # data["1223021"] = TEST_DATA_21 # data["1223023"] = TEST_DATA_23 # data["1223024"] = TEST_DATA_24 - # data["1223027"] = TEST_DATA_27 + # data["122A027"] = TEST_DATA_27 + # data["122B027"] = TEST_DATA_27_OFF # data["1223074"] = TEST_DATA_74 flat_result: dict = {} try: @@ -289,7 +291,8 @@ async def async_fetch(): # result["1223021"] = TEST_DATA_21 # result["1223023"] = TEST_DATA_23 # result["1223024"] = TEST_DATA_24 - # result["1223027"] = TEST_DATA_27 + # result["122A027"] = TEST_DATA_27 + # result["122B027"] = TEST_DATA_27_OFF # result["1223074"] = TEST_DATA_74 try: diff --git a/custom_components/miele/devcap.py b/custom_components/miele/devcap.py index 2c8f09dd..00243410 100644 --- a/custom_components/miele/devcap.py +++ b/custom_components/miele/devcap.py @@ -1,6 +1,7 @@ """Device capabilities.""" +# pylint: disable=too-many-lines -# API Version 1.0.5 +# API Version 1.0.7 DEV_TYPES = { 1: "Washing Machine", @@ -1043,13 +1044,99 @@ {"value_raw": 15, "value_localized": 8, "key_localized": "Power level"}, {"value_raw": 220, "value_localized": 10, "key_localized": "Power level"}, {"value_raw": 12, "value_localized": 10, "key_localized": "Power level"}, - {"value_raw": 118, "value_localized": 10, "key_localized": "Power level"}, ], "ecoFeedback": None, "batteryLevel": None, }, } +TEST_DATA_27_OFF = { + "ident": { + "type": { + "key_localized": "Device type", + "value_raw": 27, + "value_localized": "Induction hob", + }, + "deviceName": "", + "protocolVersion": 203, + "deviceIdentLabel": { + "fabNumber": "**REDACTED**", + "fabIndex": "00", + "techType": "KM7474", + "matNumber": "", + "swids": ["000"], + }, + "xkmIdentLabel": { + "techType": "EK039W", + "releaseVersion": "02.72", + }, + }, + "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": "Program", + "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": None, "unit": "Celsius"}, + {"value_raw": -32768, "value_localized": None, "unit": "Celsius"}, + {"value_raw": -32768, "value_localized": None, "unit": "Celsius"}, + ], + "temperature": [ + {"value_raw": -32768, "value_localized": None, "unit": "Celsius"}, + {"value_raw": -32768, "value_localized": None, "unit": "Celsius"}, + {"value_raw": -32768, "value_localized": None, "unit": "Celsius"}, + ], + "signalInfo": False, + "signalFailure": False, + "signalDoor": False, + "remoteEnable": { + "fullRemoteControl": True, + "smartGrid": False, + "mobileStart": False, + }, + "ambientLight": None, + "light": None, + "elapsedTime": [], + "spinningSpeed": { + "unit": "rpm", + "value_raw": None, + "value_localized": "", + "key_localized": "Spin speed", + }, + "dryingStep": { + "value_raw": None, + "value_localized": "", + "key_localized": "Drying level", + }, + "ventilationStep": { + "value_raw": None, + "value_localized": "", + "key_localized": "Fan level", + }, + "plateStep": [], + "ecoFeedback": None, + "batteryLevel": None, + }, +} + TEST_DATA_74 = { "ident": { "type": { diff --git a/custom_components/miele/number.py b/custom_components/miele/number.py index 622cb706..128a4ef0 100644 --- a/custom_components/miele/number.py +++ b/custom_components/miele/number.py @@ -4,7 +4,7 @@ from collections.abc import Callable from dataclasses import dataclass import logging -from typing import Any, Final +from typing import Any from homeassistant.components.number import ( NumberEntity, @@ -12,6 +12,7 @@ NumberMode, ) from homeassistant.core import HomeAssistant +from homeassistant.helpers import issue_registry as ir from homeassistant.helpers.entity import DeviceInfo from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.typing import ConfigType @@ -21,10 +22,19 @@ ) from . import get_coordinator -from .const import API, DOMAIN, HOB_INDUCT_EXTR, HOB_INDUCTION, MANUFACTURER +from .const import ( + API, + DOMAIN, + HOB_HIGHLIGHT, + HOB_INDUCT_EXTR, + HOB_INDUCTION, + MANUFACTURER, +) _LOGGER = logging.getLogger(__name__) +HOB_TYPES = (HOB_INDUCT_EXTR, HOB_HIGHLIGHT, HOB_INDUCTION) + PLATE_MAP = { 0: 0, 110: 0.5, @@ -49,6 +59,15 @@ 18: 9.5, 117: 10, 118: 10, + 217: 110, +} + +DEFAULT_PLATE_COUNT = 6 + +PLATE_COUNT = { + "KM7474": 4, + "KM7897": 6, + "KMDA7634": 5, } @@ -77,175 +96,6 @@ class MieleNumberDefinition: description: MieleNumberDescription = None -NUMBER_TYPES: Final[tuple[MieleNumberDefinition, ...]] = ( - MieleNumberDefinition( - types=[ - HOB_INDUCT_EXTR, - ], - description=MieleNumberDescription( - key="plate", - data_tag="state|plateStep|0|value_raw", - icon="mdi:stove", - translation_key="plate_1", - zone=0, - native_min_value=0.0, - native_max_value=10.0, - native_step=0.5, - ), - ), - MieleNumberDefinition( - types=[ - HOB_INDUCT_EXTR, - ], - description=MieleNumberDescription( - key="plate", - data_tag="state|plateStep|1|value_raw", - icon="mdi:stove", - translation_key="plate_2", - zone=1, - native_min_value=0.0, - native_max_value=10.0, - native_step=0.5, - ), - ), - MieleNumberDefinition( - types=[ - HOB_INDUCT_EXTR, - ], - description=MieleNumberDescription( - key="plate", - data_tag="state|plateStep|2|value_raw", - icon="mdi:stove", - translation_key="plate_3", - zone=2, - native_min_value=0.0, - native_max_value=10.0, - native_step=0.5, - ), - ), - MieleNumberDefinition( - types=[ - HOB_INDUCT_EXTR, - ], - description=MieleNumberDescription( - key="plate", - data_tag="state|plateStep|3|value_raw", - icon="mdi:stove", - translation_key="plate_4", - zone=3, - native_min_value=0.0, - native_max_value=10.0, - native_step=0.5, - ), - ), - MieleNumberDefinition( - types=[ - HOB_INDUCT_EXTR, - ], - description=MieleNumberDescription( - key="plate", - data_tag="state|plateStep|4|value_raw", - icon="mdi:stove", - translation_key="plate_5", - zone=4, - native_min_value=0.0, - native_max_value=10.0, - native_step=0.5, - ), - ), - MieleNumberDefinition( - types=[ - HOB_INDUCTION, - ], - description=MieleNumberDescription( - key="plate", - data_tag="state|plateStep|0|value_raw", - icon="mdi:stove", - translation_key="plate_1", - zone=0, - native_min_value=0.0, - native_max_value=10.0, - native_step=0.5, - ), - ), - MieleNumberDefinition( - types=[ - HOB_INDUCTION, - ], - description=MieleNumberDescription( - key="plate", - data_tag="state|plateStep|1|value_raw", - icon="mdi:stove", - translation_key="plate_2", - zone=1, - native_min_value=0.0, - native_max_value=10.0, - native_step=0.5, - ), - ), - MieleNumberDefinition( - types=[ - HOB_INDUCTION, - ], - description=MieleNumberDescription( - key="plate", - data_tag="state|plateStep|2|value_raw", - icon="mdi:stove", - translation_key="plate_3", - zone=2, - native_min_value=0.0, - native_max_value=10.0, - native_step=0.5, - ), - ), - MieleNumberDefinition( - types=[ - HOB_INDUCTION, - ], - description=MieleNumberDescription( - key="plate", - data_tag="state|plateStep|3|value_raw", - icon="mdi:stove", - translation_key="plate_4", - zone=3, - native_min_value=0.0, - native_max_value=10.0, - native_step=0.5, - ), - ), - MieleNumberDefinition( - types=[ - HOB_INDUCTION, - ], - description=MieleNumberDescription( - key="plate", - data_tag="state|plateStep|4|value_raw", - icon="mdi:stove", - translation_key="plate_5", - zone=4, - native_min_value=0.0, - native_max_value=10.0, - native_step=0.5, - ), - ), - MieleNumberDefinition( - types=[ - HOB_INDUCTION, - ], - description=MieleNumberDescription( - key="plate", - data_tag="state|plateStep|5|value_raw", - icon="mdi:stove", - translation_key="plate_6", - zone=5, - native_min_value=0.0, - native_max_value=10.0, - native_step=0.5, - ), - ), -) - - async def async_setup_entry( hass: HomeAssistant, config_entry: ConfigType, @@ -256,19 +106,42 @@ async def async_setup_entry( entities = [] for idx, ent in enumerate(coordinator.data): - for definition in NUMBER_TYPES: - if coordinator.data[ent]["ident|type|value_raw"] in definition.types and ( - coordinator.data[ent].get(definition.description.data_tag) is not None - ): + if ( + coordinator.data[ent]["ident|type|value_raw"] in HOB_TYPES + and coordinator.data[ent]["ident|deviceIdentLabel|techType"] + not in PLATE_COUNT + ): + ir.async_create_issue( + hass, + DOMAIN, + "hob_not_supported", + is_fixable=False, + severity=ir.IssueSeverity.WARNING, + translation_key="hob_not_supported", + translation_placeholders={ + "tech_type": coordinator.data[ent][ + "ident|deviceIdentLabel|techType" + ], + "issue_url": "https://github.com/astrandb/miele/issues", + }, + ) + + if coordinator.data[ent]["ident|type|value_raw"] in HOB_TYPES: + tech_type = coordinator.data[ent]["ident|deviceIdentLabel|techType"] + plates = PLATE_COUNT.get(tech_type, DEFAULT_PLATE_COUNT) + for plate_no in range(plates): + description = MieleNumberDescription( + key="plate", + data_tag=f"state|plateStep|{plate_no}|value_raw", + icon="mdi:stove", + translation_key=f"plate_{plate_no+1}", + zone=plate_no, + native_min_value=0.0, + native_max_value=10.0, + native_step=0.5, + ) entities.append( - MieleNumber( - coordinator, - idx, - ent, - definition.description, - hass, - config_entry, - ) + MieleNumber(coordinator, idx, ent, description, hass, config_entry) ) async_add_entities(entities) @@ -298,10 +171,9 @@ def __init__( self._ed = description _LOGGER.debug("Init number %s", ent) appl_type = self.coordinator.data[self._ent][self._ed.type_key] + tech_type = self.coordinator.data[self._ent]["ident|deviceIdentLabel|techType"] if appl_type == "": - appl_type = self.coordinator.data[self._ent][ - "ident|deviceIdentLabel|techType" - ] + appl_type = tech_type self._attr_has_entity_name = True self._attr_unique_id = f"{self._ed.key}-{self._ed.zone}{self._ent}" self._attr_mode = NumberMode.SLIDER @@ -317,7 +189,7 @@ def __init__( def native_value(self): """Return native value.""" if self.coordinator.data[self._ent].get(self._ed.data_tag) is None: - return + return 0 return PLATE_MAP[self.coordinator.data[self._ent][self._ed.data_tag]] @property @@ -327,6 +199,9 @@ def available(self): if not self.coordinator.last_update_success: return False + if self.coordinator.data[self._ent].get(self._ed.data_tag) is None: + return False + return self.coordinator.data[self._ent]["state|status|value_raw"] != 255 async def async_set_native_value(self, value: float) -> None: diff --git a/custom_components/miele/translations/en.json b/custom_components/miele/translations/en.json index 2375749d..01312a73 100644 --- a/custom_components/miele/translations/en.json +++ b/custom_components/miele/translations/en.json @@ -481,6 +481,12 @@ } } }, + "issues": { + "hob_not_supported": { + "description": "The appliance type {tech_type} is not fully supported by the Miele integration. Therefore some entities might be missing or malfunctioning. \n\nPlease report this issue to [the maintainer on Github]({issue_url})", + "title": "The appliance {tech_type} is not fully supported" + } + }, "selector": { "process_action_options": { "options": {