From 51f0fcc8dc525573274c4837416f0324263daf50 Mon Sep 17 00:00:00 2001 From: sususweet Date: Wed, 24 Sep 2025 19:57:11 +0800 Subject: [PATCH] feat: refactor code to add more attributes. --- .../midea_auto_cloud/binary_sensor.py | 22 ++- custom_components/midea_auto_cloud/climate.py | 21 +-- .../midea_auto_cloud/device_mapping/T0xE1.py | 1 + custom_components/midea_auto_cloud/fan.py | 68 ++++++--- .../midea_auto_cloud/midea_entities.py | 131 ---------------- .../midea_auto_cloud/midea_entity.py | 144 ++++++++++++++++-- custom_components/midea_auto_cloud/select.py | 32 +++- custom_components/midea_auto_cloud/sensor.py | 11 +- custom_components/midea_auto_cloud/switch.py | 12 +- .../midea_auto_cloud/water_heater.py | 80 +++++++--- 10 files changed, 299 insertions(+), 223 deletions(-) delete mode 100644 custom_components/midea_auto_cloud/midea_entities.py diff --git a/custom_components/midea_auto_cloud/binary_sensor.py b/custom_components/midea_auto_cloud/binary_sensor.py index 92f9c82..a6ef854 100644 --- a/custom_components/midea_auto_cloud/binary_sensor.py +++ b/custom_components/midea_auto_cloud/binary_sensor.py @@ -57,18 +57,17 @@ class MideaDeviceStatusSensorEntity(MideaEntity, BinarySensorEntity): device.sn, device.sn8, device.model, - entity_key + entity_key, + device=device, + manufacturer=manufacturer, + rationale=rationale, + config=config, ) self._device = device self._manufacturer = manufacturer self._rationale = rationale self._config = config - @property - def entity_id_suffix(self) -> str: - """Return the suffix for entity ID.""" - return "status" - @property def device_class(self): """Return the device class.""" @@ -102,7 +101,11 @@ class MideaBinarySensorEntity(MideaEntity, BinarySensorEntity): device.sn, device.sn8, device.model, - entity_key + entity_key, + device=device, + manufacturer=manufacturer, + rationale=rationale, + config=config, ) self._device = device self._manufacturer = manufacturer @@ -110,11 +113,6 @@ class MideaBinarySensorEntity(MideaEntity, BinarySensorEntity): self._entity_key = entity_key self._config = config - @property - def entity_id_suffix(self) -> str: - """Return the suffix for entity ID.""" - return f"binary_sensor_{self._entity_key}" - @property def is_on(self): """Return if the binary sensor is on.""" diff --git a/custom_components/midea_auto_cloud/climate.py b/custom_components/midea_auto_cloud/climate.py index 90be591..94a8fa2 100644 --- a/custom_components/midea_auto_cloud/climate.py +++ b/custom_components/midea_auto_cloud/climate.py @@ -15,7 +15,6 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback from .const import DOMAIN from .core.logger import MideaLogger from .midea_entity import MideaEntity -from .midea_entities import Rationale from . import load_device_config @@ -61,7 +60,11 @@ class MideaClimateEntity(MideaEntity, ClimateEntity): device.sn, device.sn8, device.model, - entity_key + entity_key, + device=device, + manufacturer=manufacturer, + rationale=rationale, + config=config, ) self._device = device self._manufacturer = manufacturer @@ -146,7 +149,7 @@ class MideaClimateEntity(MideaEntity, ClimateEntity): @property def fan_mode(self): - return self._dict_get_selected(self._key_fan_modes, Rationale.EQUALLY) + return self._dict_get_selected(self._key_fan_modes, "EQUALLY") @property def swing_modes(self): @@ -154,7 +157,7 @@ class MideaClimateEntity(MideaEntity, ClimateEntity): @property def swing_mode(self): - return self._dict_get_selected(self._key_swing_modes) + return self._dict_get_selected(self._key_swing_modes, "EQUALLY") @property def is_on(self) -> bool: @@ -162,7 +165,7 @@ class MideaClimateEntity(MideaEntity, ClimateEntity): @property def hvac_mode(self): - return self._dict_get_selected(self._key_hvac_modes) + return self._dict_get_selected(self._key_hvac_modes, "EQUALLY") @property def hvac_modes(self): @@ -233,7 +236,7 @@ class MideaClimateEntity(MideaEntity, ClimateEntity): return await self.async_set_attribute(key, value) - def _dict_get_selected(self, dict_config, rationale=Rationale.EQUALLY): + def _dict_get_selected(self, dict_config, rationale="EQUALLY"): """Get selected value from dictionary configuration.""" if dict_config is None: return None @@ -248,15 +251,15 @@ class MideaClimateEntity(MideaEntity, ClimateEntity): if device_value is None: match = False break - if rationale == Rationale.EQUALLY: + if rationale == "EQUALLY": if device_value != attr_value: match = False break - elif rationale == Rationale.LESS: + elif rationale == "LESS": if device_value >= attr_value: match = False break - elif rationale == Rationale.GREATER: + elif rationale == "GREATER": if device_value <= attr_value: match = False break diff --git a/custom_components/midea_auto_cloud/device_mapping/T0xE1.py b/custom_components/midea_auto_cloud/device_mapping/T0xE1.py index 999f6a5..964d836 100644 --- a/custom_components/midea_auto_cloud/device_mapping/T0xE1.py +++ b/custom_components/midea_auto_cloud/device_mapping/T0xE1.py @@ -62,6 +62,7 @@ DEVICE_MAPPING = { "work_status": { "options": { "power_off": {"work_status": "power_off" }, + "power_on": {"work_status": "power_on" }, } }, }, diff --git a/custom_components/midea_auto_cloud/fan.py b/custom_components/midea_auto_cloud/fan.py index 0d5c65c..d5f1287 100644 --- a/custom_components/midea_auto_cloud/fan.py +++ b/custom_components/midea_auto_cloud/fan.py @@ -1,7 +1,7 @@ from homeassistant.components.fan import FanEntity, FanEntityFeature from homeassistant.const import Platform from .const import DOMAIN -from .midea_entities import MideaEntity +from .midea_entity import MideaEntity from . import load_device_config @@ -24,13 +24,30 @@ async def async_setup_entry(hass, config_entry, async_add_entities): coordinator = coordinator_map.get(device_id) device = coordinator.device if coordinator else None for entity_key, ecfg in entities_cfg.items(): - devs.append(MideaFanEntity(device, manufacturer, rationale, entity_key, ecfg)) + devs.append(MideaFanEntity(coordinator, device, manufacturer, rationale, entity_key, ecfg)) async_add_entities(devs) class MideaFanEntity(MideaEntity, FanEntity): - def __init__(self, device, manufacturer, rationale, entity_key, config): - super().__init__(device, manufacturer, rationale, entity_key, config) + def __init__(self, coordinator, device, manufacturer, rationale, entity_key, config): + super().__init__( + coordinator, + device.device_id, + device.device_name, + f"T0x{device.device_type:02X}", + device.sn, + device.sn8, + device.model, + entity_key, + device=device, + manufacturer=manufacturer, + rationale=rationale, + config=config, + ) + self._device = device + self._manufacturer = manufacturer + self._rationale = rationale + self._config = config self._key_power = self._config.get("power") self._key_preset_modes = self._config.get("preset_modes") self._key_speeds = self._config.get("speeds") @@ -74,41 +91,48 @@ class MideaFanEntity(MideaEntity, FanEntity): def oscillating(self): return self._get_status_on_off(self._key_oscillate) - def turn_on( + async def async_turn_on( self, percentage: int | None = None, preset_mode: str | None = None, **kwargs, ): - if preset_mode is not None: - new_status = self._key_preset_modes.get(preset_mode) - else: - new_status = {} - if percentage is not None: + new_status = {} + if preset_mode is not None and self._key_preset_modes is not None: + new_status.update(self._key_preset_modes.get(preset_mode, {})) + if percentage is not None and self._key_speeds: index = round(percentage * self._attr_speed_count / 100) - 1 + index = max(0, min(index, len(self._key_speeds) - 1)) new_status.update(self._key_speeds[index]) - new_status[self._key_power] = self._rationale[1] - self._device.set_attributes(new_status) + if self._key_power is not None: + new_status[self._key_power] = True + if new_status: + await self.async_set_attributes(new_status) - def turn_off(self): - self._set_status_on_off(self._key_power, False) + async def async_turn_off(self): + await self._async_set_status_on_off(self._key_power, False) - def set_percentage(self, percentage: int): + async def async_set_percentage(self, percentage: int): + if not self._key_speeds: + return index = round(percentage * self._attr_speed_count / 100) - if 0 < index < len(self._key_speeds): + if 0 < index <= len(self._key_speeds): new_status = self._key_speeds[index - 1] - self._device.set_attributes(new_status) + await self.async_set_attributes(new_status) - def set_preset_mode(self, preset_mode: str): + async def async_set_preset_mode(self, preset_mode: str): + if not self._key_preset_modes: + return new_status = self._key_preset_modes.get(preset_mode) - self._device.set_attributes(new_status) + if new_status: + await self.async_set_attributes(new_status) - def oscillate(self, oscillating: bool): + async def async_oscillate(self, oscillating: bool): if self.oscillating != oscillating: - self._set_status_on_off(self._key_oscillate, oscillating) + await self._async_set_status_on_off(self._key_oscillate, oscillating) def update_state(self, status): try: self.schedule_update_ha_state() - except Exception as e: + except Exception: pass diff --git a/custom_components/midea_auto_cloud/midea_entities.py b/custom_components/midea_auto_cloud/midea_entities.py deleted file mode 100644 index e85536f..0000000 --- a/custom_components/midea_auto_cloud/midea_entities.py +++ /dev/null @@ -1,131 +0,0 @@ -from enum import IntEnum -from homeassistant.helpers.entity import Entity -from homeassistant.const import ( - STATE_ON, - STATE_OFF -) -from .const import DOMAIN -from .core.logger import MideaLogger - - -class Rationale(IntEnum): - EQUALLY = 0 - GREATER = 1 - LESS = 2 - - -class MideaEntity(Entity): - def __init__(self, device, manufacturer: str | None, rationale: list | None, entity_key: str, config: dict): - self._device = device - self._device.register_update(self.update_state) - self._entity_key = entity_key - self._config = config - self._device_name = self._device.device_name - self._rationale = rationale - if rationale_local := config.get("rationale"): - self._rationale = rationale_local - if self._rationale is None: - self._rationale = ["off", "on"] - self._attr_name = self._config.get("name") - self._attr_native_unit_of_measurement = self._config.get("unit_of_measurement") - self._attr_device_class = self._config.get("device_class") - self._attr_state_class = self._config.get("state_class") - self._attr_icon = self._config.get("icon") - self._attr_unique_id = f"{DOMAIN}.{self._device.device_id}_{self._entity_key}" - self._attr_device_info = { - "manufacturer": "Midea" if manufacturer is None else manufacturer, - "model": f"{self._device.model}", - "identifiers": {(DOMAIN, self._device.device_id)}, - "name": self._device_name - } - name = self._config.get("name") - if name is None: - name = self._entity_key.replace("_", " ").title() - self._attr_name = f"{self._device_name} {name}" - self.entity_id = self._attr_unique_id - - @property - def device(self): - return self._device - - @property - def should_poll(self): - return False - - @property - def available(self): - return self._device.connected - - def _get_status_on_off(self, status_key: str): - result = False - status = self._device.get_attribute(status_key) - if status is not None: - try: - result = bool(self._rationale.index(status)) - except ValueError: - MideaLogger.error(f"The value of attribute {status_key} ('{status}') " - f"is not in rationale {self._rationale}") - return result - - def _set_status_on_off(self, status_key: str, turn_on: bool): - self._device.set_attribute(status_key, self._rationale[int(turn_on)]) - - def _list_get_selected(self, key_of_list: list, rationale: Rationale = Rationale.EQUALLY): - for index in range(0, len(key_of_list)): - match = True - for attr, value in key_of_list[index].items(): - state_value = self._device.get_attribute(attr) - if state_value is None: - match = False - break - if rationale is Rationale.EQUALLY and state_value != value: - match = False - break - if rationale is Rationale.GREATER and state_value < value: - match = False - break - if rationale is Rationale.LESS and state_value > value: - match = False - break - if match: - return index - return None - - def _dict_get_selected(self, key_of_dict: dict, rationale: Rationale = Rationale.EQUALLY): - for mode, status in key_of_dict.items(): - match = True - for attr, value in status.items(): - state_value = self._device.get_attribute(attr) - if state_value is None: - match = False - break - if rationale is Rationale.EQUALLY and state_value != value: - match = False - break - if rationale is Rationale.GREATER and state_value < value: - match = False - break - if rationale is Rationale.LESS and state_value > value: - match = False - break - if match: - return mode - return None - - def update_state(self, status): - if self._entity_key in status or "connected" in status: - try: - self.schedule_update_ha_state() - except Exception as e: - pass - - -class MideaBinaryBaseEntity(MideaEntity): - - @property - def state(self): - return STATE_ON if self.is_on else STATE_OFF - - @property - def is_on(self): - return self._get_status_on_off(self._entity_key) \ No newline at end of file diff --git a/custom_components/midea_auto_cloud/midea_entity.py b/custom_components/midea_auto_cloud/midea_entity.py index f6d8d97..3314baa 100644 --- a/custom_components/midea_auto_cloud/midea_entity.py +++ b/custom_components/midea_auto_cloud/midea_entity.py @@ -29,7 +29,12 @@ class MideaEntity(CoordinatorEntity[MideaDataUpdateCoordinator], Entity): sn: str, sn8: str, model: str, - entity_key: str + entity_key: str, + *, + device: Any | None = None, + manufacturer: str | None = None, + rationale: list | None = None, + config: dict | None = None, ) -> None: """Initialize the entity.""" super().__init__(coordinator) @@ -40,18 +45,55 @@ class MideaEntity(CoordinatorEntity[MideaDataUpdateCoordinator], Entity): self._sn = sn self._sn8 = sn8 self._model = model + # Legacy/extended fields + self._device = device + self._config = config or {} + self._rationale = rationale + if (self._config.get("rationale")) is not None: + self._rationale = self._config.get("rationale") + if self._rationale is None: + self._rationale = ["off", "on"] + # Display and identification self._attr_has_entity_name = True - self._attr_unique_id = f"{sn8}_{self.entity_id_suffix}" - self.entity_id_base = f"midea_{sn8.lower()}" - - self._attr_device_info = DeviceInfo( - identifiers={(DOMAIN, sn8)}, - model=model, - serial_number=sn, - manufacturer="Midea", - name=device_name, - ) + # Prefer legacy unique_id scheme if device object is available (device_id based) + if self._device is not None: + self._attr_unique_id = f"{DOMAIN}.{self._device_id}_{self._entity_key}" + self.entity_id_base = f"midea_{self._device_id}" + manu = "Midea" if manufacturer is None else manufacturer + self._attr_device_info = DeviceInfo( + identifiers={(DOMAIN, str(self._device_id))}, + model=self._model, + serial_number=sn, + manufacturer=manu, + name=device_name, + ) + # Presentation attributes from config + self._attr_native_unit_of_measurement = self._config.get("unit_of_measurement") + self._attr_device_class = self._config.get("device_class") + self._attr_state_class = self._config.get("state_class") + self._attr_icon = self._config.get("icon") + name_cfg = self._config.get("name") + if name_cfg is None: + name_cfg = self._entity_key.replace("_", " ").title() + self._attr_name = f"{name_cfg}" + self.entity_id = self._attr_unique_id + # Register device updates for HA state refresh + try: + self._device.register_update(self.update_state) # type: ignore[attr-defined] + except Exception: + pass + else: + # Fallback to sn8-based unique id/device info + self._attr_unique_id = f"{sn8}_{self.entity_id_suffix}" + self.entity_id_base = f"midea_{sn8.lower()}" + self._attr_device_info = DeviceInfo( + identifiers={(DOMAIN, sn8)}, + model=model, + serial_number=sn, + manufacturer="Midea", + name=device_name, + ) # Debounced command publishing self._debounced_publish_command = Debouncer( @@ -89,6 +131,86 @@ class MideaEntity(CoordinatorEntity[MideaDataUpdateCoordinator], Entity): # This will be implemented by subclasses pass + # ===== Unified helpers migrated from legacy entity base ===== + def _get_status_on_off(self, attribute_key: str | None) -> bool: + """Return boolean value from device attributes for given key. + + Accepts common truthy representations: True/1/"on"/"true". + """ + if attribute_key is None: + return False + value = self.device_attributes.get(attribute_key) + if isinstance(value, bool): + return value + return value in (1, "1", "on", "ON", "true", "TRUE") + + async def _async_set_status_on_off(self, attribute_key: str | None, turn_on: bool) -> None: + """Set boolean attribute via coordinator, no-op if key is None.""" + if attribute_key is None: + return + await self.async_set_attribute(attribute_key, bool(turn_on)) + + def _list_get_selected(self, options: list[dict] | None, rationale: object = None) -> int | None: + """Select index from a list of dict conditions matched against attributes. + + The optional rationale supports equality/greater/less matching. It can be + a string name ("EQUALLY"/"GREATER"/"LESS") or an Enum with .name. + """ + if not options: + return None + + rationale_name = getattr(rationale, "name", None) or rationale or "EQUALLY" + for index in range(0, len(options)): + match = True + for attr, expected in options[index].items(): + current = self.device_attributes.get(attr) + if current is None: + match = False + break + if rationale_name == "EQUALLY" and current != expected: + match = False + break + if rationale_name == "GREATER" and current < expected: + match = False + break + if rationale_name == "LESS" and current > expected: + match = False + break + if match: + return index + return None + + def _dict_get_selected(self, mapping: dict | None, rationale: object = None): + """Return key from a dict whose value (a condition dict) matches attributes. + + The optional rationale supports equality/greater/less matching. It can be + a string name ("EQUALLY"/"GREATER"/"LESS") or an Enum with .name. + """ + if not mapping: + return None + rationale_name = getattr(rationale, "name", None) or rationale or "EQUALLY" + for key, conditions in mapping.items(): + if not isinstance(conditions, dict): + continue + match = True + for attr, expected in conditions.items(): + current = self.device_attributes.get(attr) + if current is None: + match = False + break + if rationale_name == "EQUALLY" and current != expected: + match = False + break + if rationale_name == "GREATER" and current <= expected: + match = False + break + if rationale_name == "LESS" and current >= expected: + match = False + break + if match: + return key + return None + async def publish_command_from_current_state(self) -> None: """Publish commands to the device from current state.""" self.coordinator.mute_state_update_for_a_while() diff --git a/custom_components/midea_auto_cloud/select.py b/custom_components/midea_auto_cloud/select.py index 5d436a5..560ac5a 100644 --- a/custom_components/midea_auto_cloud/select.py +++ b/custom_components/midea_auto_cloud/select.py @@ -1,7 +1,7 @@ from homeassistant.components.select import SelectEntity from homeassistant.const import Platform from .const import DOMAIN -from .midea_entities import MideaEntity +from .midea_entity import MideaEntity from . import load_device_config @@ -24,13 +24,30 @@ async def async_setup_entry(hass, config_entry, async_add_entities): coordinator = coordinator_map.get(device_id) device = coordinator.device if coordinator else None for entity_key, ecfg in entities_cfg.items(): - devs.append(MideaSelectEntity(device, manufacturer, rationale, entity_key, ecfg)) + devs.append(MideaSelectEntity(coordinator, device, manufacturer, rationale, entity_key, ecfg)) async_add_entities(devs) class MideaSelectEntity(MideaEntity, SelectEntity): - def __init__(self, device, manufacturer, rationale, entity_key, config): - super().__init__(device, manufacturer, rationale, entity_key, config) + def __init__(self, coordinator, device, manufacturer, rationale, entity_key, config): + super().__init__( + coordinator, + device.device_id, + device.device_name, + f"T0x{device.device_type:02X}", + device.sn, + device.sn8, + device.model, + entity_key, + device=device, + manufacturer=manufacturer, + rationale=rationale, + config=config, + ) + self._device = device + self._manufacturer = manufacturer + self._rationale = rationale + self._config = config self._key_options = self._config.get("options") @property @@ -41,13 +58,14 @@ class MideaSelectEntity(MideaEntity, SelectEntity): def current_option(self): return self._dict_get_selected(self._key_options) - def select_option(self, option: str): + async def async_select_option(self, option: str): new_status = self._key_options.get(option) - self._device.set_attributes(new_status) + if new_status: + await self.async_set_attributes(new_status) def update_state(self, status): try: self.schedule_update_ha_state() - except Exception as e: + except Exception: pass diff --git a/custom_components/midea_auto_cloud/sensor.py b/custom_components/midea_auto_cloud/sensor.py index 0d706fb..8cbf568 100644 --- a/custom_components/midea_auto_cloud/sensor.py +++ b/custom_components/midea_auto_cloud/sensor.py @@ -52,18 +52,17 @@ class MideaSensorEntity(MideaEntity, SensorEntity): device.sn, device.sn8, device.model, - entity_key + entity_key, + device=device, + manufacturer=manufacturer, + rationale=rationale, + config=config, ) self._device = device self._manufacturer = manufacturer self._rationale = rationale self._config = config - @property - def entity_id_suffix(self) -> str: - """Return the suffix for entity ID.""" - return f"sensor_{self._entity_key}" - @property def native_value(self): """Return the native value of the sensor.""" diff --git a/custom_components/midea_auto_cloud/switch.py b/custom_components/midea_auto_cloud/switch.py index 090db02..ba70b91 100644 --- a/custom_components/midea_auto_cloud/switch.py +++ b/custom_components/midea_auto_cloud/switch.py @@ -27,7 +27,7 @@ async def async_setup_entry( for device_id, info in device_list.items(): device_type = info.get("type") sn8 = info.get("sn8") - config = load_device_config(hass, device_type, sn8) or {} + config = await load_device_config(hass, device_type, sn8) or {} entities_cfg = (config.get("entities") or {}).get(Platform.SWITCH, {}) manufacturer = config.get("manufacturer") rationale = config.get("rationale") @@ -52,17 +52,17 @@ class MideaSwitchEntity(MideaEntity, SwitchEntity): device.sn, device.sn8, device.model, - entity_key + entity_key, + device=device, + manufacturer=manufacturer, + rationale=rationale, + config=config, ) self._device = device self._manufacturer = manufacturer self._rationale = rationale self._config = config - @property - def entity_id_suffix(self) -> str: - """Return the suffix for entity ID.""" - return f"switch_{self._entity_key}" @property def is_on(self) -> bool: diff --git a/custom_components/midea_auto_cloud/water_heater.py b/custom_components/midea_auto_cloud/water_heater.py index f79301a..925475a 100644 --- a/custom_components/midea_auto_cloud/water_heater.py +++ b/custom_components/midea_auto_cloud/water_heater.py @@ -4,7 +4,7 @@ from homeassistant.const import ( ATTR_TEMPERATURE ) from .const import DOMAIN -from .midea_entities import MideaEntity +from .midea_entity import MideaEntity from . import load_device_config @@ -27,13 +27,54 @@ async def async_setup_entry(hass, config_entry, async_add_entities): coordinator = coordinator_map.get(device_id) device = coordinator.device if coordinator else None for entity_key, ecfg in entities_cfg.items(): - devs.append(MideaWaterHeaterEntityEntity(device, manufacturer, rationale, entity_key, ecfg)) + devs.append(MideaWaterHeaterEntityEntity(coordinator, device, manufacturer, rationale, entity_key, ecfg)) async_add_entities(devs) class MideaWaterHeaterEntityEntity(MideaEntity, WaterHeaterEntity): - def __init__(self, device, manufacturer, rationale, entity_key, config): - super().__init__(device, manufacturer, rationale, entity_key, config) + def __init__(self, coordinator, device, manufacturer, rationale, entity_key, config): + super().__init__( + coordinator, + device.device_id, + device.device_name, + f"T0x{device.device_type:02X}", + device.sn, + device.sn8, + device.model, + entity_key, + device=device, + manufacturer=manufacturer, + rationale=rationale, + config=config, + ) + self._device = device + self._manufacturer = manufacturer + self._rationale = rationale + self._config = config + # Legacy compatibility: register update and restore display attributes + if self._device: + self._device.register_update(self.update_state) + if (rationale_local := self._config.get("rationale")) is not None: + self._rationale = rationale_local + if self._rationale is None: + self._rationale = ["off", "on"] + self._attr_native_unit_of_measurement = self._config.get("unit_of_measurement") + self._attr_device_class = self._config.get("device_class") + self._attr_state_class = self._config.get("state_class") + self._attr_icon = self._config.get("icon") + from .const import DOMAIN as _DOMAIN + self._attr_unique_id = f"{_DOMAIN}.{self._device.device_id}_{self._entity_key}" + self._attr_device_info = { + "manufacturer": "Midea" if self._manufacturer is None else self._manufacturer, + "model": f"{self._device.model}", + "identifiers": {( _DOMAIN, self._device.device_id)}, + "name": self._device.device_name + } + name = self._config.get("name") + if name is None: + name = self._entity_key.replace("_", " ").title() + self._attr_name = f"{self._device.device_name} {name}" + self.entity_id = self._attr_unique_id self._key_power = self._config.get("power") self._key_operation_list = self._config.get("operation_list") self._key_min_temp = self._config.get("min_temp") @@ -62,30 +103,30 @@ class MideaWaterHeaterEntityEntity(MideaEntity, WaterHeaterEntity): @property def current_temperature(self): - return self._device.get_attribute(self._key_current_temperature) + return self.device_attributes.get(self._key_current_temperature) @property def target_temperature(self): if isinstance(self._key_target_temperature, list): - temp_int = self._device.get_attribute(self._key_target_temperature[0]) - tem_dec = self._device.get_attribute(self._key_target_temperature[1]) + temp_int = self.device_attributes.get(self._key_target_temperature[0]) + tem_dec = self.device_attributes.get(self._key_target_temperature[1]) if temp_int is not None and tem_dec is not None: return temp_int + tem_dec return None else: - return self._device.get_attribute(self._key_target_temperature) + return self.device_attributes.get(self._key_target_temperature) @property def min_temp(self): if isinstance(self._key_min_temp, str): - return float(self._device.get_attribute(self._key_min_temp)) + return float(self.device_attributes.get(self._key_min_temp)) else: return float(self._key_min_temp) @property def max_temp(self): if isinstance(self._key_max_temp, str): - return float(self._device.get_attribute(self._key_max_temp)) + return float(self.device_attributes.get(self._key_max_temp)) else: return float(self._key_max_temp) @@ -101,13 +142,13 @@ class MideaWaterHeaterEntityEntity(MideaEntity, WaterHeaterEntity): def is_on(self) -> bool: return self._get_status_on_off(self._key_power) - def turn_on(self): - self._set_status_on_off(self._key_power, True) + async def async_turn_on(self): + await self._async_set_status_on_off(self._key_power, True) - def turn_off(self): - self._set_status_on_off(self._key_power, False) + async def async_turn_off(self): + await self._async_set_status_on_off(self._key_power, False) - def set_temperature(self, **kwargs): + async def async_set_temperature(self, **kwargs): if ATTR_TEMPERATURE not in kwargs: return temperature = kwargs.get(ATTR_TEMPERATURE) @@ -119,15 +160,16 @@ class MideaWaterHeaterEntityEntity(MideaEntity, WaterHeaterEntity): new_status[self._key_target_temperature[1]] = temp_dec else: new_status[self._key_target_temperature] = temperature - self._device.set_attributes(new_status) + await self.async_set_attributes(new_status) - def set_operation_mode(self, operation_mode: str) -> None: + async def async_set_operation_mode(self, operation_mode: str) -> None: new_status = self._key_operation_list.get(operation_mode) - self._device.set_attributes(new_status) + if new_status: + await self.async_set_attributes(new_status) def update_state(self, status): try: self.schedule_update_ha_state() - except Exception as e: + except Exception: pass