diff --git a/README.md b/README.md index 0e30aa6..2d528c2 100644 --- a/README.md +++ b/README.md @@ -33,6 +33,7 @@ Get devices from MSmartHome/Midea Meiju homes through the network and control th - T0xB7 Gas Stove - T0xB8 Smart Robot Vacuum - T0xBF Microwave Steam Oven +- T0xC3 Heat Pump - T0xCA French Door Refrigerator - T0xCC Central Air Conditioning (Ducted) Wi-Fi Controller - T0xCD Air Energy Water Heater diff --git a/README_hans.md b/README_hans.md index 05c6c5b..4210fad 100644 --- a/README_hans.md +++ b/README_hans.md @@ -33,6 +33,7 @@ - T0xB7 燃气灶 - T0xB8 智能扫地机器人 - T0xBF 微波炉 +- T0xC3 热泵 - T0xCA 对开门冰箱 - T0xCC 中央空调(风管机)Wi-Fi线控器 - T0xCD 空气能热水器 diff --git a/custom_components/midea_auto_cloud/core/cloud.py b/custom_components/midea_auto_cloud/core/cloud.py index b7a1aad..c5dae23 100644 --- a/custom_components/midea_auto_cloud/core/cloud.py +++ b/custom_components/midea_auto_cloud/core/cloud.py @@ -29,8 +29,8 @@ clouds = { "app_key": "ac21b9f9cbfe4ca5a88562ef25e2b768", "iot_key": bytes.fromhex(format(7882822598523843940, 'x')).decode(), "hmac_key": bytes.fromhex(format(117390035944627627450677220413733956185864939010425, 'x')).decode(), - # "api_url": "https://mp-eu-prod.appsmb.com/mas/v5/app/proxy?alias=", - "api_url": "https://mp-prod.appsmb.com/mas/v5/app/proxy?alias=", + "api_url": "https://mp-eu-prod.appsmb.com/mas/v5/app/proxy?alias=", + # "api_url": "https://mp-prod.appsmb.com/mas/v5/app/proxy?alias=", }, } @@ -642,7 +642,7 @@ class MSmartHomeCloud(MideaCloud): self._api_url = api_url async def login(self) -> bool: - await self._re_route() + # await self._re_route() if login_id := await self._get_login_id(): self._login_id = login_id iot_data = self._make_general_data() @@ -734,6 +734,93 @@ class MSmartHomeCloud(MideaCloud): await fp.write(stream) return fnm + async def download_plugin( + self, path: str, + appliance_code: str, + smart_product_id: str, + device_type: int, + sn: str, + sn8: str, + model_number: str | None, + manufacturer_code: str = "0000", + ): + # 构建 applianceList,根据传入的参数动态生成 + appliance_info = { + "appModel": sn8, + "appEnterprise": manufacturer_code, + "appType": f"0x{device_type:02X}", + "applianceCode": str(appliance_code) if isinstance(appliance_code, int) else appliance_code, + "smartProductId": str(smart_product_id) if isinstance(smart_product_id, int) else smart_product_id, + "modelNumber": model_number or "0", + "versionCode": 0 + } + appliance_list = [appliance_info] + data = { + "applianceList": json.dumps(appliance_list), + "iotAppId": self.APP_ID, + "match": "1", + "clientType": "1", + "clientVersion": 201 + } + fnm = None + if response := await self._api_request( + endpoint="/v1/plugin/update/getPluginV3", + data=data + ): + # response 是 {"list": [...]} + plugin_list = response.get("list", []) + if not plugin_list: + MideaLogger.warning(f"No plugin found for device type 0x{device_type:02X}, sn: {sn}") + return None + + # 找到匹配的设备(优先匹配 applianceCode,其次匹配 appType) + matched_plugin = None + # 首先尝试精确匹配 applianceCode + for plugin in plugin_list: + if plugin.get("applianceCode") == sn and plugin.get("appType") == f"0x{device_type:02X}": + matched_plugin = plugin + break + + # 如果没有精确匹配,使用第一个匹配 appType 的 + if not matched_plugin: + for plugin in plugin_list: + if plugin.get("appType") == f"0x{device_type:02X}": + matched_plugin = plugin + break + + if not matched_plugin: + MideaLogger.warning(f"No matching plugin found for device type 0x{device_type:02X}, sn: {sn}") + return None + + # 下载 zip 文件 + zip_url = matched_plugin.get("url") + zip_title = matched_plugin.get("title", f"plugin_0x{device_type:02X}.zip") + + if not zip_url: + MideaLogger.warning(f"No download URL found for plugin: {zip_title}") + return None + + try: + # 确保目录存在 + os.makedirs(path, exist_ok=True) + + res = await self._session.get(zip_url) + if res.status == 200: + zip_data = await res.read() + if zip_data: + fnm = f"{path}/{zip_title}" + async with aiofiles.open(fnm, "wb") as fp: + await fp.write(zip_data) + MideaLogger.info(f"Downloaded plugin file: {fnm}") + else: + MideaLogger.warning(f"Downloaded zip file is empty: {zip_url}") + else: + MideaLogger.warning(f"Failed to download plugin, status: {res.status}, url: {zip_url}") + except Exception as e: + MideaLogger.error(f"Error downloading plugin: {e}") + traceback.print_exc() + return fnm + async def send_cloud(self, appliance_code: int, data: bytearray): appliance_code = str(appliance_code) params = { diff --git a/custom_components/midea_auto_cloud/device_mapping/T0xC3.py b/custom_components/midea_auto_cloud/device_mapping/T0xC3.py new file mode 100644 index 0000000..bd360c7 --- /dev/null +++ b/custom_components/midea_auto_cloud/device_mapping/T0xC3.py @@ -0,0 +1,75 @@ +from homeassistant.const import Platform, UnitOfTemperature, PRECISION_HALVES, CONCENTRATION_MICROGRAMS_PER_CUBIC_METER, \ + CONCENTRATION_PARTS_PER_MILLION +from homeassistant.components.sensor import SensorStateClass, SensorDeviceClass +from homeassistant.components.switch import SwitchDeviceClass + +DEVICE_MAPPING = { + "default": { + "rationale": ["off", "on"], + "queries": [{}], + "centralized": [], + "entities": { + Platform.CLIMATE: { + "Zone1": { + "power": "zone1_power_state", + "hvac_modes": { + "off": {"zone1_power_state": "off"}, + "heat": {"zone1_power_state": "on"}, + }, + "target_temperature": "room_temp_set", + "current_temperature": "T4", + "min_temp": "room_min_set_temp", + "max_temp": "room_max_set_temp", + "temperature_unit": UnitOfTemperature.CELSIUS, + "precision": PRECISION_HALVES, + }, + "DHW": { + "power": "dhw_power_state", + "hvac_modes": { + "off": {"dhw_power_state": "off"}, + "heat": {"dhw_power_state": "on"}, + }, + "target_temperature": "dhw_temp_set", + "current_temperature": "T4", + "min_temp": "dhw_min_set_temp", + "max_temp": "dhw_max_set_temp", + "temperature_unit": UnitOfTemperature.CELSIUS, + "precision": PRECISION_HALVES, + } + }, + Platform.SWITCH: { + "fastdhw_state": { + "device_class": SwitchDeviceClass.SWITCH, + "translation_key": "fastdhw_state", + }, + "forcetbh_state": { + "device_class": SwitchDeviceClass.SWITCH, + "translation_key": "forcetbh_state", + }, + }, + Platform.SENSOR: { + "run_mode_set": { + "device_class": SensorDeviceClass.ENUM, + "translation_key": "mode", + }, + "room_temp_set": { + "device_class": SensorDeviceClass.TEMPERATURE, + "unit_of_measurement": UnitOfTemperature.CELSIUS, + "state_class": SensorStateClass.MEASUREMENT, + "translation_key": "room_temperature", + }, + "t4": { + "device_class": SensorDeviceClass.TEMPERATURE, + "unit_of_measurement": UnitOfTemperature.CELSIUS, + "state_class": SensorStateClass.MEASUREMENT, + "translation_key": "outside_temperature", + }, + "tank_actual_temp":{ + "device_class": SensorDeviceClass.TEMPERATURE, + "unit_of_measurement": UnitOfTemperature.CELSIUS, + "state_class": SensorStateClass.MEASUREMENT, + } + } + } + } +} diff --git a/custom_components/midea_auto_cloud/midea_entity.py b/custom_components/midea_auto_cloud/midea_entity.py index ac768a7..a3c6531 100644 --- a/custom_components/midea_auto_cloud/midea_entity.py +++ b/custom_components/midea_auto_cloud/midea_entity.py @@ -125,7 +125,7 @@ class MideaEntity(CoordinatorEntity[MideaDataUpdateCoordinator], Entity): @property def device_attributes(self) -> dict: """Return device attributes.""" - return self.coordinator.data.attributes + return self.coordinator.data.attributes if self.coordinator.data else {} @property def available(self) -> bool: diff --git a/custom_components/midea_auto_cloud/translations/en.json b/custom_components/midea_auto_cloud/translations/en.json index 32a1bc7..727cdc8 100644 --- a/custom_components/midea_auto_cloud/translations/en.json +++ b/custom_components/midea_auto_cloud/translations/en.json @@ -335,6 +335,12 @@ } } }, + "Zone1": { + "name": "区域1" + }, + "DHW": { + "name": "DHW" + }, "colmo_turing_central_ac_climate": { "name": "Thermostat", "state_attributes": { @@ -2567,6 +2573,12 @@ }, "water_model_go_out": { "name": "Away Mode" + }, + "fastdhw_state": { + "name": "Fast Hot Water" + }, + "forcetbh_state": { + "name": "Force Standby" } } } diff --git a/custom_components/midea_auto_cloud/translations/zh-Hans.json b/custom_components/midea_auto_cloud/translations/zh-Hans.json index 8136cf5..409ac92 100644 --- a/custom_components/midea_auto_cloud/translations/zh-Hans.json +++ b/custom_components/midea_auto_cloud/translations/zh-Hans.json @@ -335,6 +335,12 @@ } } }, + "Zone1": { + "name": "区域1" + }, + "DHW": { + "name": "DHW" + }, "colmo_turing_central_ac_climate": { "name": "温控器", "state_attributes": { @@ -2571,6 +2577,12 @@ }, "water_model_go_out": { "name": "外出模式" + }, + "fastdhw_state": { + "name": "快速生活热水" + }, + "forcetbh_state": { + "name": "强制待机" } } }