From 9fdf12cbd4570401a3cea3c0932fa47a57c6f80a Mon Sep 17 00:00:00 2001 From: Cyborg2017 Date: Wed, 24 Dec 2025 15:14:32 +0800 Subject: [PATCH 01/17] fix: align translations with M-Smart app --- custom_components/midea_auto_cloud/device_mapping/T0xFB.py | 1 + custom_components/midea_auto_cloud/translations/en.json | 2 +- custom_components/midea_auto_cloud/translations/zh-Hans.json | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/custom_components/midea_auto_cloud/device_mapping/T0xFB.py b/custom_components/midea_auto_cloud/device_mapping/T0xFB.py index de09936..8097184 100644 --- a/custom_components/midea_auto_cloud/device_mapping/T0xFB.py +++ b/custom_components/midea_auto_cloud/device_mapping/T0xFB.py @@ -16,6 +16,7 @@ DEVICE_MAPPING = { }, "screen_close": { "device_class": SwitchDeviceClass.SWITCH, + "rationale": ["on", "off"], } }, Platform.CLIMATE: { diff --git a/custom_components/midea_auto_cloud/translations/en.json b/custom_components/midea_auto_cloud/translations/en.json index 4154f35..f9f3e4a 100644 --- a/custom_components/midea_auto_cloud/translations/en.json +++ b/custom_components/midea_auto_cloud/translations/en.json @@ -2023,7 +2023,7 @@ "name": "Wind Change with Temperature" }, "screen_close": { - "name": "Screen Close" + "name": "Screen Display" }, "anion": { "name": "Anion" diff --git a/custom_components/midea_auto_cloud/translations/zh-Hans.json b/custom_components/midea_auto_cloud/translations/zh-Hans.json index d3ca10a..5521ea6 100644 --- a/custom_components/midea_auto_cloud/translations/zh-Hans.json +++ b/custom_components/midea_auto_cloud/translations/zh-Hans.json @@ -2123,7 +2123,7 @@ "name": "风随温变" }, "screen_close": { - "name": "屏幕关闭" + "name": "屏幕显示" }, "anion": { "name": "负离子" From ed4e3d34feadaa6661ae12f45ab9c6e0566dfc8b Mon Sep 17 00:00:00 2001 From: Cyborg2017 Date: Fri, 26 Dec 2025 20:58:41 +0800 Subject: [PATCH 02/17] feat: add device mapping for T0xFB(570667EC) * Device type: T0xFB, Sn8: 570667EC, model: HDU20WS. --- .../midea_auto_cloud/device_mapping/T0xFB.py | 61 ++++++++++++++++++- .../midea_auto_cloud/translations/en.json | 13 +++- .../translations/zh-Hans.json | 13 +++- 3 files changed, 84 insertions(+), 3 deletions(-) diff --git a/custom_components/midea_auto_cloud/device_mapping/T0xFB.py b/custom_components/midea_auto_cloud/device_mapping/T0xFB.py index 8097184..09462d8 100644 --- a/custom_components/midea_auto_cloud/device_mapping/T0xFB.py +++ b/custom_components/midea_auto_cloud/device_mapping/T0xFB.py @@ -1,5 +1,5 @@ from homeassistant.const import Platform, UnitOfTemperature, UnitOfVolume, UnitOfTime, PERCENTAGE, PRECISION_HALVES, \ - UnitOfEnergy, UnitOfPower + PRECISION_WHOLE, UnitOfEnergy, UnitOfPower from homeassistant.components.sensor import SensorStateClass, SensorDeviceClass from homeassistant.components.binary_sensor import BinarySensorDeviceClass from homeassistant.components.switch import SwitchDeviceClass @@ -50,5 +50,64 @@ DEVICE_MAPPING = { } } } + }, + "570667EC": { + "rationale": ["off", "on"], + "queries": [{}], + "centralized": [], + "entities": { + Platform.SWITCH: { + "auto_power_off": { + "device_class": SwitchDeviceClass.SWITCH, + }, + "humidification": { + "device_class": SwitchDeviceClass.SWITCH, + "rationale": ['off', 'no_change'], + }, + "lock": { + "device_class": SwitchDeviceClass.SWITCH, + "translation_key": "child_lock", + }, + "screen_close": { + "device_class": SwitchDeviceClass.SWITCH, + "rationale": ['on', 'off'], + }, + "voice": { + "device_class": SwitchDeviceClass.SWITCH, + "rationale": ['close_buzzer', 'open_buzzer'], + } + }, + Platform.CLIMATE: { + "electric_heater": { + "power": "power", + "hvac_modes": { + "off": {"power": "off"}, + "heat": {"power": "on"} + }, + "target_temperature": "temperature", + "current_temperature": "cur_temperature", + "min_temp": 5, + "max_temp": 35, + "temperature_unit": UnitOfTemperature.CELSIUS, + "precision": PRECISION_WHOLE, + } + }, + Platform.SELECT: { + "gear": { + "options": { + "left_warm": {"gear": 1}, + "right_warm": {"gear": 2}, + "full_on": {"gear": 3} + } + } + }, + Platform.SENSOR: { + "power_statistics": { + "device_class": SensorDeviceClass.POWER, + "unit_of_measurement": UnitOfPower.WATT, + "state_class": SensorStateClass.MEASUREMENT + } + } + } } } diff --git a/custom_components/midea_auto_cloud/translations/en.json b/custom_components/midea_auto_cloud/translations/en.json index f9f3e4a..67f288e 100644 --- a/custom_components/midea_auto_cloud/translations/en.json +++ b/custom_components/midea_auto_cloud/translations/en.json @@ -828,7 +828,12 @@ "name": "Sleep Sensor" }, "gear": { - "name": "Gear" + "name": "Gear", + "state": { + "left_warm": "Left Warm", + "right_warm": "Right Warm", + "full_on": "Full On" + } }, "ptc": { "name": "PTC" @@ -1998,6 +2003,12 @@ } }, "switch": { + "auto_power_off": { + "name": "Auto Power Off" + }, + "voice": { + "name": "Sound" + }, "laundry": { "name": "One Key Laundry" }, diff --git a/custom_components/midea_auto_cloud/translations/zh-Hans.json b/custom_components/midea_auto_cloud/translations/zh-Hans.json index 5521ea6..3554762 100644 --- a/custom_components/midea_auto_cloud/translations/zh-Hans.json +++ b/custom_components/midea_auto_cloud/translations/zh-Hans.json @@ -928,7 +928,12 @@ "name": "睡眠传感器" }, "gear": { - "name": "档位" + "name": "档位", + "state": { + "left_warm": "左暖", + "right_warm": "右暖", + "full_on": "全开" + } }, "ptc": { "name": "电辅热" @@ -2098,6 +2103,12 @@ } }, "switch": { + "auto_power_off": { + "name": "待机超时自动关机" + }, + "voice": { + "name": "声音" + }, "laundry": { "name": "一键晾衣" }, From 729389c9f14c0fe702a5f610735186aef6f3dbff Mon Sep 17 00:00:00 2001 From: Cyborg2017 Date: Fri, 26 Dec 2025 21:06:14 +0800 Subject: [PATCH 03/17] feat: add device mapping for T0xFC(571Z3081) * Device type: T0xFC, Sn8: 571Z3081, model: KJ1000G-T1000 Lite. --- .../midea_auto_cloud/device_mapping/T0xFC.py | 85 +++++++++++++++++++ .../midea_auto_cloud/translations/en.json | 8 ++ .../translations/zh-Hans.json | 8 ++ 3 files changed, 101 insertions(+) diff --git a/custom_components/midea_auto_cloud/device_mapping/T0xFC.py b/custom_components/midea_auto_cloud/device_mapping/T0xFC.py index 4c11e80..39e6ad1 100644 --- a/custom_components/midea_auto_cloud/device_mapping/T0xFC.py +++ b/custom_components/midea_auto_cloud/device_mapping/T0xFC.py @@ -99,5 +99,90 @@ DEVICE_MAPPING = { } } } + }, + "571Z3081": { + "rationale": ["off", "on"], + "queries": [{}], + "centralized": [], + "entities": { + Platform.SWITCH: { + "power": { + "device_class": SwitchDeviceClass.SWITCH, + }, + "buzzer": { + "device_class": SwitchDeviceClass.SWITCH, + "translation_key": "voice", + }, + "lock": { + "device_class": SwitchDeviceClass.SWITCH, + "translation_key": "child_lock", + }, + "waterions":{ + "device_class": SwitchDeviceClass.SWITCH, + } + }, + Platform.SELECT: { + "mode": { + "options": { + "manual": {"mode": "manual"}, + "sleep": {"mode": "sleep"}, + "auto": {"mode": "auto"}, + "air_dry": {"mode": "air_dry"} + } + }, + "bias_gear":{ + "options": { + "瑜伽静修场景": {"mode": "auto", "sub_mode": "denoise", "bias_gear": -20}, + "室内对话场景": {"mode": "auto", "sub_mode": "denoise", "bias_gear": -10} + } + }, + "bright": { + "options": { + "全亮": {"bright": 0}, + "半亮": {"bright": 6}, + "熄灭": {"bright": 7} + } + }, + "gear": { + "options": { + "low": {"wind_speed": 1}, + "medium": {"wind_speed": 2}, + "high": {"wind_speed": 3} + } + } + }, + Platform.SENSOR: { + "temperature_feedback": { + "device_class": SensorDeviceClass.TEMPERATURE, + "unit_of_measurement": UnitOfTemperature.CELSIUS, + "state_class": SensorStateClass.MEASUREMENT + }, + "humidify_feedback": { + "device_class": SensorDeviceClass.HUMIDITY, + "unit_of_measurement": "%", + "state_class": SensorStateClass.MEASUREMENT + }, + "hcho":{ + "device_class": SensorDeviceClass.VOLATILE_ORGANIC_COMPOUNDS, + "unit_of_measurement": CONCENTRATION_MICROGRAMS_PER_CUBIC_METER, + "state_class": SensorStateClass.MEASUREMENT + }, + "pm1":{ + "device_class": SensorDeviceClass.PM1, + "unit_of_measurement": CONCENTRATION_MICROGRAMS_PER_CUBIC_METER, + "state_class": SensorStateClass.MEASUREMENT + }, + "pm25":{ + "device_class": SensorDeviceClass.PM25, + "unit_of_measurement": CONCENTRATION_MICROGRAMS_PER_CUBIC_METER, + "state_class": SensorStateClass.MEASUREMENT + }, + "pm10":{ + "device_class": SensorDeviceClass.PM10, + "unit_of_measurement": CONCENTRATION_MICROGRAMS_PER_CUBIC_METER, + "state_class": SensorStateClass.MEASUREMENT + } + } + } } } diff --git a/custom_components/midea_auto_cloud/translations/en.json b/custom_components/midea_auto_cloud/translations/en.json index 67f288e..e529227 100644 --- a/custom_components/midea_auto_cloud/translations/en.json +++ b/custom_components/midea_auto_cloud/translations/en.json @@ -570,9 +570,14 @@ "mode": { "name": "Mode", "state": { + "air_dry": "Air Dry Mode", + "auto": "Auto Mode", + "manual": "Manual Mode", "normal": "normal", "factory_test": "factory test", + "fast": "Fast Mode", "service": "service", + "sleep": "Sleep Mode", "normal_continus": "normal continus" } }, @@ -830,6 +835,9 @@ "gear": { "name": "Gear", "state": { + "low": "Low", + "medium": "Medium", + "high": "High", "left_warm": "Left Warm", "right_warm": "Right Warm", "full_on": "Full On" diff --git a/custom_components/midea_auto_cloud/translations/zh-Hans.json b/custom_components/midea_auto_cloud/translations/zh-Hans.json index 3554762..c80a335 100644 --- a/custom_components/midea_auto_cloud/translations/zh-Hans.json +++ b/custom_components/midea_auto_cloud/translations/zh-Hans.json @@ -670,9 +670,14 @@ "mode": { "name": "运行模式", "state": { + "air_dry": "风芯模式", + "auto": "智能托管", + "manual": "手动模式", "normal": "正常", "factory_test": "工厂测试", + "fast": "速净模式", "service": "服务", + "sleep": "睡眠模式", "normal_continus": "正常连续" } }, @@ -930,6 +935,9 @@ "gear": { "name": "档位", "state": { + "low": "低", + "medium": "中", + "high": "高", "left_warm": "左暖", "right_warm": "右暖", "full_on": "全开" From 40df4d1a83d49bcc99df1912cf24423763e1916f Mon Sep 17 00:00:00 2001 From: Cyborg2017 Date: Fri, 26 Dec 2025 21:12:26 +0800 Subject: [PATCH 04/17] feat: add device mapping for T0xFD(202Z310H) * Device type: T0xFD, Sn8: 202Z310H, model: SZK-1Y80. --- .../midea_auto_cloud/device_mapping/T0xFD.py | 82 +++++++++++++++++++ .../midea_auto_cloud/translations/en.json | 8 ++ .../translations/zh-Hans.json | 10 ++- 3 files changed, 99 insertions(+), 1 deletion(-) diff --git a/custom_components/midea_auto_cloud/device_mapping/T0xFD.py b/custom_components/midea_auto_cloud/device_mapping/T0xFD.py index 143a7e0..cc67e47 100644 --- a/custom_components/midea_auto_cloud/device_mapping/T0xFD.py +++ b/custom_components/midea_auto_cloud/device_mapping/T0xFD.py @@ -156,5 +156,87 @@ DEVICE_MAPPING = { } } } + }, + "202Z310H": { + "rationale": ["off", "on"], + "queries": [{}], + "centralized": [], + "entities": { + Platform.SWITCH: { + "buzzer": { + "device_class": SwitchDeviceClass.SWITCH, + "translation_key": "voice", + }, + "airDry_on_off": { + "device_class": SwitchDeviceClass.SWITCH, + "translation_key": "airdry_on_off", + }, + "power": { + "device_class": SwitchDeviceClass.SWITCH, + }, + "power_on_timer": { + "device_class": SwitchDeviceClass.SWITCH, + }, + "power_off_timer": { + "device_class": SwitchDeviceClass.SWITCH, + } + }, + Platform.BINARY_SENSOR: { + "add_water_flag": { + "device_class": BinarySensorDeviceClass.PROBLEM, + } + }, + Platform.SELECT: { + "humidity_mode": { + "options": { + "manual": {"humidity_mode": "manual"}, + "auto": {"humidity_mode": "auto"}, + "sleep": {"humidity_mode": "sleep"} + } + }, + "wind_speed": { + "options": { + "low": {"wind_speed": "low"}, + "middle": {"wind_speed": "middle"}, + "high": {"wind_speed": "high"} + } + } + }, + Platform.SENSOR: { + "running_percent": { + "device_class": SensorDeviceClass.POWER_FACTOR, + "unit_of_measurement": PERCENTAGE, + "state_class": SensorStateClass.MEASUREMENT + }, + "error_code": { + "device_class": SensorDeviceClass.ENUM + }, + "cur_temperature": { + "device_class": SensorDeviceClass.TEMPERATURE, + "unit_of_measurement": UnitOfTemperature.CELSIUS, + "state_class": SensorStateClass.MEASUREMENT + }, + "air_dry_left_time": { + "device_class": SensorDeviceClass.DURATION, + "unit_of_measurement": UnitOfTime.MINUTES, + "state_class": SensorStateClass.MEASUREMENT + }, + "time_on": { + "device_class": SensorDeviceClass.DURATION, + "unit_of_measurement": UnitOfTime.MINUTES, + "state_class": SensorStateClass.MEASUREMENT + }, + "time_off": { + "device_class": SensorDeviceClass.DURATION, + "unit_of_measurement": UnitOfTime.MINUTES, + "state_class": SensorStateClass.MEASUREMENT + }, + "tank_status": { + "device_class": SensorDeviceClass.BATTERY, + "unit_of_measurement": PERCENTAGE, + "state_class": SensorStateClass.MEASUREMENT + } + } + } } } \ No newline at end of file diff --git a/custom_components/midea_auto_cloud/translations/en.json b/custom_components/midea_auto_cloud/translations/en.json index e529227..93a4cb7 100644 --- a/custom_components/midea_auto_cloud/translations/en.json +++ b/custom_components/midea_auto_cloud/translations/en.json @@ -544,6 +544,7 @@ "humidity_mode": { "name": "Humidity Mode", "state": { + "auto": "auto", "manual": "manual", "moist_skin": "moist skin", "sleep": "sleep" @@ -752,6 +753,7 @@ "state": { "low": "low", "medium": "medium", + "middle": "middle", "high": "high", "auto": "auto", "invalid": "invalid" @@ -2014,6 +2016,12 @@ "auto_power_off": { "name": "Auto Power Off" }, + "power_on_timer": { + "name": "Power On Timer" + }, + "power_off_timer": { + "name": "Power Off Timer" + }, "voice": { "name": "Sound" }, diff --git a/custom_components/midea_auto_cloud/translations/zh-Hans.json b/custom_components/midea_auto_cloud/translations/zh-Hans.json index c80a335..5d69e2c 100644 --- a/custom_components/midea_auto_cloud/translations/zh-Hans.json +++ b/custom_components/midea_auto_cloud/translations/zh-Hans.json @@ -644,6 +644,7 @@ "humidity_mode": { "name": "湿度模式", "state": { + "auto": "AI湿随温变", "manual": "手动", "moist_skin": "润肤", "sleep": "睡眠" @@ -852,6 +853,7 @@ "state": { "low": "低速", "medium": "中速", + "middle": "中速", "high": "高速", "auto": "自动", "invalid": "无效" @@ -2114,6 +2116,12 @@ "auto_power_off": { "name": "待机超时自动关机" }, + "power_on_timer": { + "name": "定时开机" + }, + "power_off_timer": { + "name": "定时关机" + }, "voice": { "name": "声音" }, @@ -2340,7 +2348,7 @@ "name": "启停" }, "airdry_on_off": { - "name": "风干开关" + "name": "湿帘风干" }, "airswitch": { "name": "烘干存储开关" From 0c4b6b5e0d4ef5d2fdaafe5da623a94ddc09db1c Mon Sep 17 00:00:00 2001 From: Cyborg2017 Date: Fri, 26 Dec 2025 22:49:59 +0800 Subject: [PATCH 05/17] feat: add device mapping for T0xFA(5600119Z) * Device type: T0xFA, Sn8: 5600119Z, model: AAF10MR. --- .../midea_auto_cloud/device_mapping/T0xFA.py | 40 +++++++++++++++++++ .../midea_auto_cloud/translations/en.json | 3 ++ .../translations/zh-Hans.json | 3 ++ 3 files changed, 46 insertions(+) diff --git a/custom_components/midea_auto_cloud/device_mapping/T0xFA.py b/custom_components/midea_auto_cloud/device_mapping/T0xFA.py index 1d9c925..2df5ac5 100644 --- a/custom_components/midea_auto_cloud/device_mapping/T0xFA.py +++ b/custom_components/midea_auto_cloud/device_mapping/T0xFA.py @@ -205,5 +205,45 @@ DEVICE_MAPPING = { } } } + }, + "5600119Z": { + "rationale": ["off", "on"], + "queries": [{}], + "centralized": [], + "entities": { + Platform.SWITCH: { + "display_on_off": { + "device_class": SwitchDeviceClass.SWITCH, + "rationale": ["on", "off"], + "translation_key": "screen_close", + }, + "humidify": { + "device_class": SwitchDeviceClass.SWITCH, + "rationale": ["off", "1"], + }, + "waterions": { + "device_class": SwitchDeviceClass.SWITCH, + "translation_key": "anion", + } + }, + Platform.FAN: { + "fan": { + "power": "power", + "speeds": list({"gear": value + 1} for value in range(0, 3)), + "oscillate": "swing", + "preset_modes": { + "normal": {"mode": "normal"}, + "sleep": {"mode": "sleep"}, + "baby": {"mode": "baby"} + } + } + }, + Platform.SENSOR: { + "water_feedback": { + "device_class": SensorDeviceClass.ENUM, + "state_class": SensorStateClass.MEASUREMENT + } + } + } } } diff --git a/custom_components/midea_auto_cloud/translations/en.json b/custom_components/midea_auto_cloud/translations/en.json index 93a4cb7..559a767 100644 --- a/custom_components/midea_auto_cloud/translations/en.json +++ b/custom_components/midea_auto_cloud/translations/en.json @@ -2733,6 +2733,9 @@ "function_zone_power": { "name": "Function Zone Power" }, + "humidify": { + "name": "Cool Wind" + }, "humidify_power": { "name": "Humidify Power" }, diff --git a/custom_components/midea_auto_cloud/translations/zh-Hans.json b/custom_components/midea_auto_cloud/translations/zh-Hans.json index 5d69e2c..1f79e36 100644 --- a/custom_components/midea_auto_cloud/translations/zh-Hans.json +++ b/custom_components/midea_auto_cloud/translations/zh-Hans.json @@ -2833,6 +2833,9 @@ "function_zone_power": { "name": "功能区电源" }, + "humidify": { + "name": "清凉风" + }, "humidify_power": { "name": "加湿电源" }, From 7426455d7551c27f360c2859066de8cc07db135a Mon Sep 17 00:00:00 2001 From: Cyborg2017 Date: Sun, 28 Dec 2025 11:27:53 +0800 Subject: [PATCH 06/17] feat: update translations for T0xD9 --- .../translations/zh-Hans.json | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/custom_components/midea_auto_cloud/translations/zh-Hans.json b/custom_components/midea_auto_cloud/translations/zh-Hans.json index 1f79e36..6b5f3da 100644 --- a/custom_components/midea_auto_cloud/translations/zh-Hans.json +++ b/custom_components/midea_auto_cloud/translations/zh-Hans.json @@ -500,7 +500,7 @@ "ssp": "SSP", "sport_clothes": "运动服", "single_dehytration": "单脱水", - "rinsing_dehydration": "漂洗脱水", + "rinsing_dehydration": "漂+脱", "big": "大件", "baby_clothes": "婴儿服", "down_jacket": "羽绒服", @@ -510,7 +510,7 @@ "shirt": "衬衫", "fiber": "化纤", "enzyme": "酶洗", - "underwear": "内衣", + "underwear": "文胸", "outdoor": "户外", "air_wash": "空气洗", "single_drying": "单烘干", @@ -531,7 +531,7 @@ "new_water_cotton": "新水洗棉", "water_eco": "水洗节能", "wash_drying_60": "洗烘60", - "self_wash_5": "自洁5", + "self_wash_5": "筒自洁", "fast_wash_min": "快洗分钟", "mixed_wash_min": "混合洗分钟", "dehydration_min": "脱水分钟", @@ -564,18 +564,23 @@ "water_cold_wash": "水洗冷水", "water_prevent_allergy": "水洗防过敏", "water_remove_mite_wash": "水洗除螨", - "water_ssp": "水洗SSP", + "water_ssp": "深度洁筒", "standard": "标准", "green_wool": "绿色羊毛", - "cook_wash": "烹饪洗", + "cook_wash": "高温煮洗", "fresh_remove_wrinkle": "清新去皱", "steam_sterilize_wash": "蒸汽杀菌洗", "sterilize_wash": "杀菌洗", "white_clothes_clean": "白衣清洁", - "clean_stains": "去渍", + "clean_stains": "特渍洗", "prevent_cross_color": "防串色", "quick_dry_clothes": "快干衣物", - "yoga_clothes": "瑜伽服" + "yoga_clothes": "瑜伽服", + "baby_clothes_dry": "婴童服烘", + "hot_wind_dry": "热风暖衣", + "small_wash_dry": "小件智洗烘", + "socks": "袜子", + "underpants": "内裤" } }, "db_running_status": { From c86152226c9892062f720298f153a8e944361cff Mon Sep 17 00:00:00 2001 From: Cyborg2017 Date: Sun, 28 Dec 2025 11:29:19 +0800 Subject: [PATCH 07/17] fix: Remove non-existent running programs for T0xD9 --- .../midea_auto_cloud/device_mapping/T0xD9.py | 99 +++---------------- 1 file changed, 16 insertions(+), 83 deletions(-) diff --git a/custom_components/midea_auto_cloud/device_mapping/T0xD9.py b/custom_components/midea_auto_cloud/device_mapping/T0xD9.py index 07f4d6b..cb84bcf 100644 --- a/custom_components/midea_auto_cloud/device_mapping/T0xD9.py +++ b/custom_components/midea_auto_cloud/device_mapping/T0xD9.py @@ -69,91 +69,24 @@ DEVICE_MAPPING = { }, "db_program": { "options": { - "cotton": {"db_program": "cotton"}, - "eco": {"db_program": "eco"}, - "fast_wash": {"db_program": "fast_wash"}, - "mixed_wash": {"db_program": "mixed_wash"}, - "wool": {"db_program": "wool"}, - "ssp": {"db_program": "ssp"}, - "sport_clothes": {"db_program": "sport_clothes"}, - "single_dehytration": {"db_program": "single_dehytration"}, - "rinsing_dehydration": {"db_program": "rinsing_dehydration"}, - "big": {"db_program": "big"}, "baby_clothes": {"db_program": "baby_clothes"}, - "down_jacket": {"db_program": "down_jacket"}, - "color": {"db_program": "color"}, - "intelligent": {"db_program": "intelligent"}, - "quick_wash": {"db_program": "quick_wash"}, - "shirt": {"db_program": "shirt"}, - "fiber": {"db_program": "fiber"}, - "enzyme": {"db_program": "enzyme"}, - "underwear": {"db_program": "underwear"}, - "outdoor": {"db_program": "outdoor"}, - "air_wash": {"db_program": "air_wash"}, - "single_drying": {"db_program": "single_drying"}, - "steep": {"db_program": "steep"}, - "kids": {"db_program": "kids"}, - "water_baby_clothes": {"db_program": "water_baby_clothes"}, - "fast_wash_30": {"db_program": "fast_wash_30"}, - "water_shirt": {"db_program": "water_shirt"}, - "water_mixed_wash": {"db_program": "water_mixed_wash"}, - "water_fiber": {"db_program": "water_fiber"}, - "water_kids": {"db_program": "water_kids"}, - "water_underwear": {"db_program": "water_underwear"}, - "specialist": {"db_program": "specialist"}, - "love": {"db_program": "love"}, - "water_intelligent": {"db_program": "water_intelligent"}, - "water_steep": {"db_program": "water_steep"}, - "water_fast_wash_30": {"db_program": "water_fast_wash_30"}, - "new_water_cotton": {"db_program": "new_water_cotton"}, - "water_eco": {"db_program": "water_eco"}, - "wash_drying_60": {"db_program": "wash_drying_60"}, - "self_wash_5": {"db_program": "self_wash_5"}, - "fast_wash_min": {"db_program": "fast_wash_min"}, - "mixed_wash_min": {"db_program": "mixed_wash_min"}, - "dehydration_min": {"db_program": "dehydration_min"}, - "self_wash_min": {"db_program": "self_wash_min"}, - "baby_clothes_min": {"db_program": "baby_clothes_min"}, - "silk_wash": {"db_program": "silk_wash"}, - "prevent_allergy": {"db_program": "prevent_allergy"}, - "cold_wash": {"db_program": "cold_wash"}, - "soft_wash": {"db_program": "soft_wash"}, - "remove_mite_wash": {"db_program": "remove_mite_wash"}, - "water_intense_wash": {"db_program": "water_intense_wash"}, - "fast_dry": {"db_program": "fast_dry"}, - "water_outdoor": {"db_program": "water_outdoor"}, - "spring_autumn_wash": {"db_program": "spring_autumn_wash"}, - "summer_wash": {"db_program": "summer_wash"}, - "winter_wash": {"db_program": "winter_wash"}, - "jean": {"db_program": "jean"}, - "new_clothes_wash": {"db_program": "new_clothes_wash"}, - "silk": {"db_program": "silk"}, - "insight_wash": {"db_program": "insight_wash"}, - "fitness_clothes": {"db_program": "fitness_clothes"}, - "mink": {"db_program": "mink"}, - "fresh_air": {"db_program": "fresh_air"}, - "bucket_dry": {"db_program": "bucket_dry"}, - "jacket": {"db_program": "jacket"}, - "bath_towel": {"db_program": "bath_towel"}, - "night_fresh_wash": {"db_program": "night_fresh_wash"}, - "degerm": {"db_program": "degerm"}, - "heart_wash": {"db_program": "heart_wash"}, - "water_cold_wash": {"db_program": "water_cold_wash"}, - "water_prevent_allergy": {"db_program": "water_prevent_allergy"}, - "water_remove_mite_wash": {"db_program": "water_remove_mite_wash"}, - "water_ssp": {"db_program": "water_ssp"}, - "standard": {"db_program": "standard"}, - "green_wool": {"db_program": "green_wool"}, - "cook_wash": {"db_program": "cook_wash"}, - "fresh_remove_wrinkle": {"db_program": "fresh_remove_wrinkle"}, - "steam_sterilize_wash": {"db_program": "steam_sterilize_wash"}, - "sterilize_wash": {"db_program": "sterilize_wash"}, - "white_clothes_clean": {"db_program": "white_clothes_clean"}, + "baby_clothes_dry": {"db_program": "151"}, "clean_stains": {"db_program": "clean_stains"}, - "prevent_cross_color": {"db_program": "prevent_cross_color"}, - "quick_dry_clothes": {"db_program": "quick_dry_clothes"}, - "yoga_clothes": {"db_program": "yoga_clothes"} - } + "cold_wash": {"db_program": "cold_wash"}, + "cook_wash": {"db_program": "cook_wash"}, + "fast_wash": {"db_program": "137"}, + "hot_wind_dry": {"db_program": "153"}, + "rinsing_dehydration": {"db_program": "rinsing_dehydration"}, + "self_wash_5": {"db_program": "self_wash_5"}, + "single_dehytration": {"db_program": "single_dehytration"}, + "single_drying": {"db_program": "single_drying"}, + "small_wash_dry": {"db_program": "138"}, + "socks": {"db_program": "148"}, + "standard": {"db_program": "standard"}, + "underpants": {"db_program": "156"}, + "underwear": {"db_program": "underwear"}, + "water_ssp": {"db_program": "water_ssp"} + } } }, Platform.SENSOR: { From e532f9deab0ae7a057b71e972e86637c585b9c51 Mon Sep 17 00:00:00 2001 From: Cyborg2017 Date: Sun, 28 Dec 2025 11:30:45 +0800 Subject: [PATCH 08/17] fix: Remove non-existent entities for T0xD9 --- .../midea_auto_cloud/device_mapping/T0xD9.py | 24 ------------------- 1 file changed, 24 deletions(-) diff --git a/custom_components/midea_auto_cloud/device_mapping/T0xD9.py b/custom_components/midea_auto_cloud/device_mapping/T0xD9.py index cb84bcf..d98bbb5 100644 --- a/custom_components/midea_auto_cloud/device_mapping/T0xD9.py +++ b/custom_components/midea_auto_cloud/device_mapping/T0xD9.py @@ -24,30 +24,6 @@ DEVICE_MAPPING = { }, }, Platform.SWITCH: { - "db_clean_notification": { - "device_class": SwitchDeviceClass.SWITCH, - "rationale": [0, 1], - }, - "db_baby_lock": { - "device_class": SwitchDeviceClass.SWITCH, - "rationale": [0, 1], - }, - "db_light": { - "device_class": SwitchDeviceClass.SWITCH, - "rationale": [0, 1], - }, - "db_steam_wash": { - "device_class": SwitchDeviceClass.SWITCH, - "rationale": [0, 1], - }, - "db_fast_clean_wash": { - "device_class": SwitchDeviceClass.SWITCH, - "rationale": [0, 1], - }, - "db_wash_dry_link": { - "device_class": SwitchDeviceClass.SWITCH, - "rationale": [0, 1], - } }, Platform.SELECT: { "db_location_selection": { From ca1953ba460a8e2237108825312ed8d4f5bdb9be Mon Sep 17 00:00:00 2001 From: Cyborg2017 Date: Sun, 28 Dec 2025 11:31:51 +0800 Subject: [PATCH 09/17] fix: Add correct power switch and control status entities for T0xD9 * Note: `power` is the washing machine's power switch, `db_running_status` only displays the running status of the current drum, `db_control_status` is the switch to start or pause the current drum. --- .../midea_auto_cloud/device_mapping/T0xD9.py | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/custom_components/midea_auto_cloud/device_mapping/T0xD9.py b/custom_components/midea_auto_cloud/device_mapping/T0xD9.py index d98bbb5..1996109 100644 --- a/custom_components/midea_auto_cloud/device_mapping/T0xD9.py +++ b/custom_components/midea_auto_cloud/device_mapping/T0xD9.py @@ -24,6 +24,14 @@ DEVICE_MAPPING = { }, }, Platform.SWITCH: { + "db_power": { + "device_class": SwitchDeviceClass.SWITCH, + }, + "db_control_status": { + "device_class": SwitchDeviceClass.SWITCH, + "rationale": ["pause", "start"], + "translation_key": "control_status", + } }, Platform.SELECT: { "db_location_selection": { @@ -32,17 +40,6 @@ DEVICE_MAPPING = { "right": {"db_location_selection": "right"} } }, - "db_running_status": { - "options": { - "off": {"db_power": "off", "db_running_status": "off"}, - "standby": {"db_power": "on", "db_running_status": "standby"}, - "start": {"db_power": "on", "db_running_status": "start"}, - "pause": {"db_power": "on", "db_running_status": "pause"}, - "end": {"db_power": "on", "db_running_status": "end"}, - "fault": {"db_power": "on", "db_running_status": "fault"}, - "delay": {"db_power": "on", "db_running_status": "delay"} - } - }, "db_program": { "options": { "baby_clothes": {"db_program": "baby_clothes"}, From 92fb232a0cfbb32552d9ad2af2ae9464141adc12 Mon Sep 17 00:00:00 2001 From: Cyborg2017 Date: Sun, 28 Dec 2025 11:39:14 +0800 Subject: [PATCH 10/17] feat: Sync the attribute status of the selected drum with M-Smart app --- .../midea_auto_cloud/core/device.py | 60 +++++++++++++------ 1 file changed, 43 insertions(+), 17 deletions(-) diff --git a/custom_components/midea_auto_cloud/core/device.py b/custom_components/midea_auto_cloud/core/device.py index 54f6a70..d156ec3 100644 --- a/custom_components/midea_auto_cloud/core/device.py +++ b/custom_components/midea_auto_cloud/core/device.py @@ -170,9 +170,17 @@ class MiedaDevice(threading.Thread): if self._device_type == 0xD9 and attribute == "db_location_selection": # 更新属性 self._attributes[attribute] = value + + # 更新db_location(用于查询) + if value == "left": + self._attributes["db_location"] = 1 + elif value == "right": + self._attributes["db_location"] = 2 + # 立即刷新状态以显示新筒的状态 await self.refresh_status() - return + + # return # 发送到云端,所以注释teturn # 针对T0xD9复式洗衣机,根据选择的筒添加db_location参数 if self._device_type == 0xD9 and attribute != "db_location_selection": @@ -209,16 +217,23 @@ class MiedaDevice(threading.Thread): await cloud.send_device_control(self._device_id, control=nested_status, status=self._attributes) async def set_attributes(self, attributes): - # 针对T0xD9复式洗衣机,当切换筒选择时,立即刷新状态以显示新筒的状态 + # 针对T0xD9复式洗衣机,当切换筒选择时 if self._device_type == 0xD9 and "db_location_selection" in attributes: - # 更新属性 - for attribute, value in attributes.items(): - if attribute in self._attributes.keys(): - self._attributes[attribute] = value + location_selection = attributes["db_location_selection"] + + # 更新本地属性 + self._attributes["db_location_selection"] = location_selection + + # 更新db_location(用于查询) + if location_selection == "left": + self._attributes["db_location"] = 1 + elif location_selection == "right": + self._attributes["db_location"] = 2 + # 立即刷新状态以显示新筒的状态 await self.refresh_status() - return - + # return # 发送到云端,所以注释teturn + new_status = {} for attr in self._centralized: new_status[attr] = self._attributes.get(attr) @@ -227,15 +242,26 @@ class MiedaDevice(threading.Thread): if attribute in self._attributes.keys(): has_new = True new_status[attribute] = value - - # 针对T0xD9复式洗衣机,根据选择的筒添加db_location参数 - if self._device_type == 0xD9 and "db_location_selection" not in attributes: - location_selection = self._attributes.get("db_location_selection", "left") - if location_selection == "left": - new_status["db_location"] = 1 - elif location_selection == "right": - new_status["db_location"] = 2 - + + # 针对T0xD9复式洗衣机,确保发送到云端的控制命令包含筒位置信息 + if self._device_type == 0xD9: + # 如果attributes中有db_location_selection,确保new_status也有 + if "db_location_selection" in attributes: + location_selection = attributes["db_location_selection"] + new_status["db_location_selection"] = location_selection + # 添加对应的db_location + if location_selection == "left": + new_status["db_location"] = 1 + elif location_selection == "right": + new_status["db_location"] = 2 + # 如果没有db_location_selection,但当前有选择,添加db_location + elif "db_location_selection" not in attributes and self._attributes.get("db_location_selection"): + location_selection = self._attributes.get("db_location_selection", "left") + if location_selection == "left": + new_status["db_location"] = 1 + elif location_selection == "right": + new_status["db_location"] = 2 + # Convert dot-notation attributes to nested structure for transmission nested_status = self._convert_to_nested_structure(new_status) From 97724a8dbaa23de57d6193f5f78d4b123fbe99de Mon Sep 17 00:00:00 2001 From: Cyborg2017 Date: Sun, 28 Dec 2025 11:42:48 +0800 Subject: [PATCH 11/17] feat: Allow both drums to share the `db_control_status` switch * Note: Ensures the shared control status (`db_control_status`) reflects the operational state of the currently active silo. - If the selected silo is not running (`db_running_status`), the control status is set to 'pause'. - This synchronization allows multiple silos to safely share a single control switch during switching operations. --- .../midea_auto_cloud/core/device.py | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/custom_components/midea_auto_cloud/core/device.py b/custom_components/midea_auto_cloud/core/device.py index d156ec3..9e10c81 100644 --- a/custom_components/midea_auto_cloud/core/device.py +++ b/custom_components/midea_auto_cloud/core/device.py @@ -83,6 +83,14 @@ class MiedaDevice(threading.Thread): self._lua_runtime = MideaCodec(lua_file, device_type=self._attributes.get("device_type"), sn=sn, subtype=subtype) if lua_file is not None else None self._cloud = cloud + def _determine_control_status_based_on_running(self, running_status): + # 根据运行状态确定控制状态, 只有当运行状态是"start"时,控制状态才为"start" + if running_status == "start": + return "start" + # 其他所有情况(包括standby、pause、off、error等),控制状态应为pause + else: + return "pause" + @property def device_name(self): return self._device_name @@ -180,6 +188,15 @@ class MiedaDevice(threading.Thread): # 立即刷新状态以显示新筒的状态 await self.refresh_status() + # 获取当前运行状态 + running_status = self._attributes.get("db_running_status") + if running_status is not None: + # 根据运行状态确定控制状态 + control_status = self._determine_control_status_based_on_running(running_status) + # 更新本地属性 + self._attributes["db_control_status"] = control_status + # 添加到要发送的状态中(如果需要发送到云端) + new_status["db_control_status"] = control_status # return # 发送到云端,所以注释teturn # 针对T0xD9复式洗衣机,根据选择的筒添加db_location参数 @@ -232,6 +249,14 @@ class MiedaDevice(threading.Thread): # 立即刷新状态以显示新筒的状态 await self.refresh_status() + + # 获取当前运行状态 + running_status = self._attributes.get("db_running_status") + if running_status is not None: + # 根据运行状态确定控制状态 + control_status = self._determine_control_status_based_on_running(running_status) + # 更新本地属性 + self._attributes["db_control_status"] = control_status # return # 发送到云端,所以注释teturn new_status = {} From 085f7b3cde0d529572cb84029524b6944aa87bc7 Mon Sep 17 00:00:00 2001 From: Cyborg2017 Date: Mon, 29 Dec 2025 21:38:39 +0800 Subject: [PATCH 12/17] feat: Add preset mode specific speed configurations - Each preset mode (e.g normal/sleep/baby) now supports independent speed settings - Automatically sets fixed speed when switching to single-speed modes - Maintains backward compatibility with existing configuration format - Dynamic switching of speed configuration based on selected preset mode The implementation allows for more intuitive control where different operating modes can have different speed adjustment capabilities. --- .../midea_auto_cloud/device_mapping/T0xFA.py | 15 +++- custom_components/midea_auto_cloud/fan.py | 78 ++++++++++++++++--- 2 files changed, 78 insertions(+), 15 deletions(-) diff --git a/custom_components/midea_auto_cloud/device_mapping/T0xFA.py b/custom_components/midea_auto_cloud/device_mapping/T0xFA.py index 2df5ac5..b897ebb 100644 --- a/custom_components/midea_auto_cloud/device_mapping/T0xFA.py +++ b/custom_components/midea_auto_cloud/device_mapping/T0xFA.py @@ -232,9 +232,18 @@ DEVICE_MAPPING = { "speeds": list({"gear": value + 1} for value in range(0, 3)), "oscillate": "swing", "preset_modes": { - "normal": {"mode": "normal"}, - "sleep": {"mode": "sleep"}, - "baby": {"mode": "baby"} + "normal": { + "mode": "normal", + "speeds": list({"gear": value + 1} for value in range(0, 3)) + }, + "sleep": { + "mode": "sleep", + "speeds": list({"gear": value + 1} for value in range(0, 2)) + }, + "baby": { + "mode": "baby", + "speeds": list({"gear": value + 1} for value in range(0, 1)) + } } } }, diff --git a/custom_components/midea_auto_cloud/fan.py b/custom_components/midea_auto_cloud/fan.py index 8cc0b43..0faa218 100644 --- a/custom_components/midea_auto_cloud/fan.py +++ b/custom_components/midea_auto_cloud/fan.py @@ -69,6 +69,8 @@ class MideaFanEntity(MideaEntity, FanEntity): self._key_oscillate = self._config.get("oscillate") self._key_directions = self._config.get("directions") self._attr_speed_count = len(self._key_speeds) if self._key_speeds else 0 + self._current_preset_mode = None + self._current_speeds = self._key_speeds @property def supported_features(self): @@ -77,7 +79,7 @@ class MideaFanEntity(MideaEntity, FanEntity): features |= FanEntityFeature.TURN_OFF if self._key_preset_modes is not None and len(self._key_preset_modes) > 0: features |= FanEntityFeature.PRESET_MODE - if self._key_speeds is not None and len(self._key_speeds) > 0: + if self._current_speeds is not None and len(self._current_speeds) > 0: features |= FanEntityFeature.SET_SPEED if self._key_oscillate is not None: features |= FanEntityFeature.OSCILLATE @@ -99,11 +101,28 @@ class MideaFanEntity(MideaEntity, FanEntity): def preset_mode(self): if self._key_preset_modes is None: return None - return self._dict_get_selected(self._key_preset_modes) + + current_mode = self._dict_get_selected(self._key_preset_modes) + + if current_mode: + mode_config = self._key_preset_modes.get(current_mode, {}) + + # 切换到该模式的档位配置 + if "speeds" in mode_config: + self._current_speeds = mode_config["speeds"] + self._attr_speed_count = len(self._current_speeds) + else: + # 使用全局配置 + self._current_speeds = self._key_speeds + self._attr_speed_count = len(self._current_speeds) if self._current_speeds else 0 + + self._current_preset_mode = current_mode + + return current_mode @property def percentage(self): - index = self._list_get_selected(self._key_speeds) + index = self._list_get_selected(self._current_speeds) if index is None: return None return round((index + 1) * 100 / self._attr_speed_count) @@ -124,11 +143,28 @@ class MideaFanEntity(MideaEntity, FanEntity): ): 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: + mode_config = self._key_preset_modes.get(preset_mode, {}) + new_status.update({"mode": mode_config.get("mode")}) + + # 切换到该模式的档位配置 + if "speeds" in mode_config: + self._current_speeds = mode_config["speeds"] + self._attr_speed_count = len(self._current_speeds) + else: + self._current_speeds = self._key_speeds + self._attr_speed_count = len(self._current_speeds) if self._current_speeds else 0 + + self._current_preset_mode = preset_mode + + # 如果只有一个档位,自动设置 + if "speeds" in mode_config and len(mode_config["speeds"]) == 1: + new_status.update(mode_config["speeds"][0]) + + # 使用当前模式的速度配置 + if percentage is not None and self._current_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]) + index = max(0, min(index, len(self._current_speeds) - 1)) + new_status.update(self._current_speeds[index]) await self._async_set_status_on_off(self._key_power, True) if new_status: await self.async_set_attributes(new_status) @@ -137,18 +173,36 @@ class MideaFanEntity(MideaEntity, FanEntity): await self._async_set_status_on_off(self._key_power, False) async def async_set_percentage(self, percentage: int): - if not self._key_speeds: + if not self._current_speeds: return index = round(percentage * self._attr_speed_count / 100) - if 0 < index <= len(self._key_speeds): - new_status = self._key_speeds[index - 1] + if 0 < index <= len(self._current_speeds): + new_status = self._current_speeds[index - 1] await self.async_set_attributes(new_status) 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) - if new_status: + + mode_config = self._key_preset_modes.get(preset_mode, {}) + if mode_config: + # 切换到该模式的档位配置 + if "speeds" in mode_config: + self._current_speeds = mode_config["speeds"] + self._attr_speed_count = len(self._current_speeds) + else: + self._current_speeds = self._key_speeds + self._attr_speed_count = len(self._current_speeds) if self._current_speeds else 0 + + self._current_preset_mode = preset_mode + + # 设置模式 + new_status = {"mode": mode_config.get("mode")} + + # 如果只有一个档位,自动设置 + if "speeds" in mode_config and len(mode_config["speeds"]) == 1: + new_status.update(mode_config["speeds"][0]) + await self.async_set_attributes(new_status) async def async_oscillate(self, oscillating: bool): From 75c4d6c80d0bc3e59f3e705b948cbb854012fda4 Mon Sep 17 00:00:00 2001 From: Cyborg2017 Date: Mon, 29 Dec 2025 21:58:41 +0800 Subject: [PATCH 13/17] feat: update translations for fan preset modes --- .../midea_auto_cloud/translations/zh-Hans.json | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/custom_components/midea_auto_cloud/translations/zh-Hans.json b/custom_components/midea_auto_cloud/translations/zh-Hans.json index 6b5f3da..9d03dbc 100644 --- a/custom_components/midea_auto_cloud/translations/zh-Hans.json +++ b/custom_components/midea_auto_cloud/translations/zh-Hans.json @@ -2114,7 +2114,19 @@ }, "fan": { "fan": { - "name": "风扇" + "name": "风扇", + "state_attributes": { + "preset_mode": { + "state": { + "baby": "宝宝风", + "normal": "正常风", + "sleep": "睡眠风", + "self_selection": "自选风", + "sleeping_wind": "睡眠风", + "purified_wind": "净化风" + } + } + } } }, "switch": { From e3b785c0708fe3a6a2475cd2c4ec67805b9a097d Mon Sep 17 00:00:00 2001 From: Cyborg2017 Date: Mon, 29 Dec 2025 23:35:44 +0800 Subject: [PATCH 14/17] fix: Complete fan control with proper "off" state MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Changes: 1. Fix speed selector "off" state: - `percentage` property returns 0 when fan is off - `async_set_percentage()` calls `async_turn_off()` for 0% - `async_turn_on()` handles percentage=0 as turn off 2. Add auto-power on: - `async_set_percentage()` powers on fan if off when selecting speed - `async_set_preset_mode()` powers on fan if off when switching modes 3. Enhance user experience: - 0% in speed slider → Turns fan off - Any speed selection when off → Auto powers on + sets speed - Mode switch when off → Auto powers on + sets mode - Works with range-based speed configs --- custom_components/midea_auto_cloud/fan.py | 56 ++++++++++++++++++++--- 1 file changed, 50 insertions(+), 6 deletions(-) diff --git a/custom_components/midea_auto_cloud/fan.py b/custom_components/midea_auto_cloud/fan.py index 0faa218..f3f0495 100644 --- a/custom_components/midea_auto_cloud/fan.py +++ b/custom_components/midea_auto_cloud/fan.py @@ -122,9 +122,18 @@ class MideaFanEntity(MideaEntity, FanEntity): @property def percentage(self): + # 如果风扇关闭,返回0%(这样UI会显示"关闭") + if not self.is_on: + return 0 + index = self._list_get_selected(self._current_speeds) if index is None: - return None + return 0 + + # 计算百分比:档位1对应最小百分比,最大档位对应100% + if self._attr_speed_count <= 1: + return 100 # 只有一个档位时,开启就是100% + return round((index + 1) * 100 / self._attr_speed_count) @property @@ -162,9 +171,21 @@ class MideaFanEntity(MideaEntity, FanEntity): # 使用当前模式的速度配置 if percentage is not None and self._current_speeds: - index = round(percentage * self._attr_speed_count / 100) - 1 - index = max(0, min(index, len(self._current_speeds) - 1)) + # 如果百分比为0,直接关闭(但async_turn_on不应该传入0) + if percentage == 0: + await self.async_turn_off() + return + + # 计算档位索引(至少为1档) + if self._attr_speed_count <= 1: + index = 0 + else: + index = round(percentage * self._attr_speed_count / 100) - 1 + index = max(0, min(index, len(self._current_speeds) - 1)) + new_status.update(self._current_speeds[index]) + + # 打开风扇 await self._async_set_status_on_off(self._key_power, True) if new_status: await self.async_set_attributes(new_status) @@ -175,9 +196,27 @@ class MideaFanEntity(MideaEntity, FanEntity): async def async_set_percentage(self, percentage: int): if not self._current_speeds: return - index = round(percentage * self._attr_speed_count / 100) - if 0 < index <= len(self._current_speeds): - new_status = self._current_speeds[index - 1] + + # 处理关闭情况(0% 表示关闭) + if percentage == 0: + await self.async_turn_off() + return + + # 如果风扇当前是关闭状态,先打开风扇 + if not self.is_on: + await self._async_set_status_on_off(self._key_power, True) + + # 将百分比转换为档位索引(从1开始,因为0%已处理) + if self._attr_speed_count <= 1: + index = 0 + else: + # 百分比1-100对应档位1到最大档位 + index = round((percentage / 100) * self._attr_speed_count) + index = max(1, min(index, self._attr_speed_count)) # 确保至少为1档 + + # 获取对应档位的配置 + if 1 <= index <= len(self._current_speeds): + new_status = self._current_speeds[index - 1] # 索引从0开始,所以减1 await self.async_set_attributes(new_status) async def async_set_preset_mode(self, preset_mode: str): @@ -186,6 +225,11 @@ class MideaFanEntity(MideaEntity, FanEntity): mode_config = self._key_preset_modes.get(preset_mode, {}) if mode_config: + + # 如果风扇当前是关闭状态,先打开风扇 + if not self.is_on: + await self._async_set_status_on_off(self._key_power, True) + # 切换到该模式的档位配置 if "speeds" in mode_config: self._current_speeds = mode_config["speeds"] From 2e389c50cc10e551b7dd486d9955fc9fd3e06c38 Mon Sep 17 00:00:00 2001 From: Cyborg2017 Date: Wed, 31 Dec 2025 00:19:19 +0800 Subject: [PATCH 15/17] feat: add device mapping for T0x26(M0100040) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Device type: T0x26, Sn8: M0100040, model: MY-S6X28-Y9W/Y9AW. - Optimize wind direction selector with unified angle control (60°-120°) - Add automatic swing mode for dynamic air distribution - Implement human-sensing night light switch with occupancy detection - Introduce dedicated temperature selectors for heating and bath modes (30-42°C) - Add lighting brightness controller with percentage-based adjustment (10-100%) - Update and improve Chinese translation strings for better localization --- .../midea_auto_cloud/device_mapping/T0x26.py | 88 ++++++++++++++++++- .../translations/zh-Hans.json | 40 ++++++++- 2 files changed, 125 insertions(+), 3 deletions(-) diff --git a/custom_components/midea_auto_cloud/device_mapping/T0x26.py b/custom_components/midea_auto_cloud/device_mapping/T0x26.py index ae23d35..d85bd9b 100644 --- a/custom_components/midea_auto_cloud/device_mapping/T0x26.py +++ b/custom_components/midea_auto_cloud/device_mapping/T0x26.py @@ -1,4 +1,4 @@ -from homeassistant.const import Platform, UnitOfTemperature, PRECISION_HALVES, UnitOfTime +from homeassistant.const import Platform, UnitOfTemperature, PERCENTAGE, PRECISION_HALVES, UnitOfTime from homeassistant.components.sensor import SensorStateClass, SensorDeviceClass from homeassistant.components.binary_sensor import BinarySensorDeviceClass from homeassistant.components.switch import SwitchDeviceClass @@ -141,5 +141,91 @@ DEVICE_MAPPING = { } } } + }, + "M0100040": { + "rationale": ["off", "on"], + "queries": [{}], + "centralized": [], + "entities": { + Platform.NUMBER: { + "bath_temperature": { + "min": 30, + "max": 42, + "step": 1, + "unit_of_measurement": UnitOfTemperature.CELSIUS + }, + "heating_temperature": { + "min": 30, + "max": 42, + "step": 1, + "unit_of_measurement": UnitOfTemperature.CELSIUS + }, + "main_light_brightness": { + "min": 10, + "max": 100, + "step": 1, + "unit_of_measurement": PERCENTAGE + } + }, + Platform.SWITCH: { + "radar_induction_enable": { + "device_class": SwitchDeviceClass.SWITCH, + }, + "wifi_led_enable": { + "device_class": SwitchDeviceClass.SWITCH, + } + }, + Platform.SELECT: { + "wind_direction": { + "options": { + "60": {"heating_direction": "60", "bath_direction": "60", "blowing_direction": "60", "drying_direction": "60"}, + "70": {"heating_direction": "70", "bath_direction": "70", "blowing_direction": "70", "drying_direction": "70"}, + "80": {"heating_direction": "80", "bath_direction": "80", "blowing_direction": "80", "drying_direction": "80"}, + "90": {"heating_direction": "90", "bath_direction": "90", "blowing_direction": "90", "drying_direction": "90"}, + "100": {"heating_direction": "100", "bath_direction": "100", "blowing_direction": "100", "drying_direction": "100"}, + "110": {"heating_direction": "110", "bath_direction": "110", "blowing_direction": "110", "drying_direction": "110"}, + "120": {"heating_direction": "120", "bath_direction": "120", "blowing_direction": "120", "drying_direction": "120"}, + "swing": {"heating_direction": "253", "bath_direction": "253", "blowing_direction": "253", "drying_direction": "253"} + } + }, + "light_mode": { + "options": { + "close_all": {"light_mode": "close_all"}, + "night_light": {"light_mode": "night_light"}, + "main_light": {"light_mode": "main_light"} + } + }, + "mode": { + "options": { + "close_all": {"mode": "close_all"}, + "heating": {"mode": "heating"}, + "bath": {"mode": "bath"}, + "blowing": {"mode": "blowing"}, + "ventilation": {"mode": "ventilation"}, + "drying": {"mode": "drying"} + } + }, + }, + Platform.SENSOR: { + "night_light_brightness": { + "unit_of_measurement": PERCENTAGE, + "state_class": SensorStateClass.MEASUREMENT + }, + "main_light_brightness": { + "unit_of_measurement": PERCENTAGE, + "state_class": SensorStateClass.MEASUREMENT + }, + "current_temperature": { + "device_class": SensorDeviceClass.TEMPERATURE, + "unit_of_measurement": UnitOfTemperature.CELSIUS, + "state_class": SensorStateClass.MEASUREMENT + }, + "delay_time": { + "device_class": SensorDeviceClass.DURATION, + "unit_of_measurement": UnitOfTime.MINUTES, + "state_class": SensorStateClass.MEASUREMENT + } + } + } } } diff --git a/custom_components/midea_auto_cloud/translations/zh-Hans.json b/custom_components/midea_auto_cloud/translations/zh-Hans.json index 9d03dbc..6808305 100644 --- a/custom_components/midea_auto_cloud/translations/zh-Hans.json +++ b/custom_components/midea_auto_cloud/translations/zh-Hans.json @@ -684,7 +684,13 @@ "fast": "速净模式", "service": "服务", "sleep": "睡眠模式", - "normal_continus": "正常连续" + "normal_continus": "正常连续", + "close_all": "关闭", + "heating": "取暖", + "bath": "安心沐浴", + "blowing": "吹风", + "ventilation": "换气", + "drying": "干燥" } }, "mode_state": { @@ -978,7 +984,12 @@ "name": "加热方向" }, "light_mode": { - "name": "灯光模式" + "name": "灯光模式", + "state": { + "close_all": "关闭", + "night_light": "夜灯", + "main_light": "照明" + } }, "bath_direction": { "name": "浴室方向" @@ -986,6 +997,19 @@ "drying_direction": { "name": "烘干方向" }, + "wind_direction": { + "name": "吹风方向", + "state": { + "60": "60°", + "70": "70°", + "80": "80°", + "90": "90°", + "100": "100°", + "110": "110°", + "120": "120°", + "swing": "自动摆风" + } + }, "air_set_hour": { "name": "烘干存储设置时间" }, @@ -2030,6 +2054,15 @@ } }, "number": { + "bath_temperature": { + "name": "沐浴温度" + }, + "heating_temperature": { + "name": "取暖温度" + }, + "main_light_brightness": { + "name": "照明亮度" + }, "light_brightness": { "name": "照明亮度" }, @@ -2130,6 +2163,9 @@ } }, "switch": { + "radar_induction_enable": { + "name": "人感夜灯" + }, "auto_power_off": { "name": "待机超时自动关机" }, From a738b2e4a0d3173312cf2fb30a0ae1a820aa430b Mon Sep 17 00:00:00 2001 From: Cyborg2017 Date: Fri, 2 Jan 2026 21:52:27 +0800 Subject: [PATCH 16/17] feat: add device mapping for T0xAC(23096653) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Device type: T0xAC, Sn8: 23096653, model: KFR-72T2/B3N8-XGQ(1)Ⅲ. - Remove non-existent swing function and humidity sensor - Fix disinfection key (fengguan_remove_odor) - Add standalone power switch - Correct aux heat key (ptc) - Add energy sensor with kWh conversion --- .../midea_auto_cloud/device_mapping/T0xAC.py | 90 +++++++++++++++++++ .../midea_auto_cloud/translations/en.json | 3 + .../translations/zh-Hans.json | 9 +- 3 files changed, 101 insertions(+), 1 deletion(-) diff --git a/custom_components/midea_auto_cloud/device_mapping/T0xAC.py b/custom_components/midea_auto_cloud/device_mapping/T0xAC.py index 7f995f6..0cf3868 100644 --- a/custom_components/midea_auto_cloud/device_mapping/T0xAC.py +++ b/custom_components/midea_auto_cloud/device_mapping/T0xAC.py @@ -754,5 +754,95 @@ DEVICE_MAPPING = { }, }, } + }, + "23096653": { + "rationale": ["off", "on"], + "queries": [{}, {"query_type":"run_status"}, {"query_type":"indoor_humidity"}, {"query_type":"indoor_temperature"}], + "calculate": { + "get": [ + { + "lvalue": "[total_elec_value]", + "rvalue": "float([total_elec]) / 1000" + }, + ], + }, + "centralized": [], + "entities": { + Platform.CLIMATE: { + "thermostat": { + "power": "power", + "hvac_modes": { + "off": {"power": "off"}, + "heat": {"power": "on", "mode": "heat"}, + "cool": {"power": "on", "mode": "cool"}, + "auto": {"power": "on", "mode": "auto"}, + "dry": {"power": "on", "mode": "dry"}, + "fan_only": {"power": "on", "mode": "fan"} + }, + "preset_modes": { + "none": { + "eco": "off", + "cool_power_saving": 0, + "strong_wind": "off" + }, + "eco": {"eco": "on", "cool_power_saving": 1}, + "boost": {"strong_wind": "on"} + }, + "fan_modes": { + "silent": {"wind_speed": 20}, + "low": {"wind_speed": 40}, + "medium": {"wind_speed": 60}, + "high": {"wind_speed": 80}, + "full": {"wind_speed": 100}, + "auto": {"wind_speed": 102} + }, + "target_temperature": ["temperature", "small_temperature"], + "current_temperature": "indoor_temperature", + "pre_mode": "mode", + "aux_heat": "ptc", + "min_temp": 17, + "max_temp": 30, + "temperature_unit": UnitOfTemperature.CELSIUS, + "precision": PRECISION_HALVES, + } + }, + Platform.SWITCH: { + "fengguan_remove_odor": { + "device_class": SwitchDeviceClass.SWITCH, + "rationale": ["on", "off"], + "translation_key": "disinfect", + }, + "power": { + "device_class": SwitchDeviceClass.SWITCH, + }, + "ptc": { + "device_class": SwitchDeviceClass.SWITCH, + "translation_key": "aux_heat", + } + }, + Platform.SELECT: { + "follow_body_sense": { + "options": { + "on": {"follow_body_sense": "on", "follow_body_sense_enable": 1}, + "off": {"follow_body_sense": "off", "follow_body_sense_enable": 1}, + } + } + }, + Platform.SENSOR: { + "mode": { + "device_class": SensorDeviceClass.ENUM, + }, + "indoor_temperature": { + "device_class": SensorDeviceClass.TEMPERATURE, + "unit_of_measurement": UnitOfTemperature.CELSIUS, + "state_class": SensorStateClass.MEASUREMENT + }, + "total_elec_value": { + "device_class": SensorDeviceClass.ENERGY, + "unit_of_measurement": "kWh", + "state_class": SensorStateClass.TOTAL_INCREASING + } + } + } } } diff --git a/custom_components/midea_auto_cloud/translations/en.json b/custom_components/midea_auto_cloud/translations/en.json index 559a767..35dc546 100644 --- a/custom_components/midea_auto_cloud/translations/en.json +++ b/custom_components/midea_auto_cloud/translations/en.json @@ -1917,6 +1917,9 @@ }, "tw1_out_water_temp": { "name": "Outlet Water Temperature" + }, + "total_elec_value": { + "name": "Total Electricity" } }, "light": { diff --git a/custom_components/midea_auto_cloud/translations/zh-Hans.json b/custom_components/midea_auto_cloud/translations/zh-Hans.json index 6808305..f7b0411 100644 --- a/custom_components/midea_auto_cloud/translations/zh-Hans.json +++ b/custom_components/midea_auto_cloud/translations/zh-Hans.json @@ -423,7 +423,11 @@ "name": "左右摆风角度" }, "follow_body_sense": { - "name": "随身感" + "name": "随身感", + "state": { + "on": "开", + "off": "关" + } }, "bright": { "name": "亮度" @@ -2046,6 +2050,9 @@ }, "tw1_out_water_temp": { "name": "出水温度" + }, + "total_elec_value": { + "name": "总耗电量" } }, "light": { From e3a6ad1681fc3c4e18a679e9ae225d1297f01785 Mon Sep 17 00:00:00 2001 From: Cyborg2017 Date: Sat, 3 Jan 2026 16:12:22 +0800 Subject: [PATCH 17/17] =?UTF-8?q?feat:=20add=20device=20mapping=20for=20T0?= =?UTF-8?q?xAC(23096633)=20*=20Device=20type:=20T0xAC,=20Sn8:=2023096633,?= =?UTF-8?q?=20model:=20KFR-75T2/B3N8-XF(1)=E2=85=A2.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Remove non-existent swing function - Add standalone power switch - Correct aux heat key (ptc) - Add energy sensor with kWh conversion - Add support for intake_wind / exhaust_wind Co-authored-by: Dali Yang --- .../midea_auto_cloud/device_mapping/T0xAC.py | 107 ++++++++++++++++++ .../midea_auto_cloud/translations/en.json | 19 ++++ .../translations/zh-Hans.json | 19 ++++ 3 files changed, 145 insertions(+) diff --git a/custom_components/midea_auto_cloud/device_mapping/T0xAC.py b/custom_components/midea_auto_cloud/device_mapping/T0xAC.py index 0cf3868..9f79efb 100644 --- a/custom_components/midea_auto_cloud/device_mapping/T0xAC.py +++ b/custom_components/midea_auto_cloud/device_mapping/T0xAC.py @@ -844,5 +844,112 @@ DEVICE_MAPPING = { } } } + }, + "23096633": { + "rationale": ["off", "on"], + "queries": [{}, {"query_type":"run_status"}, {"query_type":"indoor_humidity"}, {"query_type":"indoor_temperature"}], + "calculate": { + "get": [ + { + "lvalue": "[total_elec_value]", + "rvalue": "float([total_elec]) / 1000" + }, + ], + }, + "centralized": [], + "entities": { + Platform.CLIMATE: { + "thermostat": { + "power": "power", + "hvac_modes": { + "off": {"power": "off"}, + "heat": {"power": "on", "mode": "heat"}, + "cool": {"power": "on", "mode": "cool"}, + "auto": {"power": "on", "mode": "auto"}, + "dry": {"power": "on", "mode": "dry"}, + "fan_only": {"power": "on", "mode": "fan"} + }, + "preset_modes": { + "none": { + "eco": "off", + "cool_power_saving": 0, + "strong_wind": "off" + }, + "eco": {"eco": "on", "cool_power_saving": 1}, + "boost": {"strong_wind": "on"} + }, + "fan_modes": { + "silent": {"wind_speed": 20}, + "low": {"wind_speed": 40}, + "medium": {"wind_speed": 60}, + "high": {"wind_speed": 80}, + "full": {"wind_speed": 100}, + "auto": {"wind_speed": 102} + }, + "target_temperature": ["temperature", "small_temperature"], + "current_temperature": "indoor_temperature", + "pre_mode": "mode", + "aux_heat": "ptc", + "min_temp": 17, + "max_temp": 30, + "temperature_unit": UnitOfTemperature.CELSIUS, + "precision": PRECISION_HALVES, + } + }, + Platform.SWITCH: { + "power": { + "device_class": SwitchDeviceClass.SWITCH, + }, + "ptc": { + "device_class": SwitchDeviceClass.SWITCH, + "translation_key": "aux_heat", + } + }, + Platform.SELECT: { + "new_wind_model_intake_enable": { + "options": { + "off": {"new_wind_model_intake_switch": "off"}, + "low": {"new_wind_model_intake_switch": "on", "new_wind_model_intake_wind": "40"}, + "medium": {"new_wind_model_intake_switch": "on", "new_wind_model_intake_wind": "60"}, + "high": {"new_wind_model_intake_switch": "on", "new_wind_model_intake_wind": "80"}, + "full": {"new_wind_model_intake_switch": "on", "new_wind_model_intake_wind": "100"} + } + }, + "new_wind_model_exhaust_enable": { + "options": { + "off": {"new_wind_model_exhaust_switch": "off"}, + "silent": {"new_wind_model_exhaust_switch": "on", "new_wind_model_exhaust_wind": "20"}, + "high": {"new_wind_model_exhaust_switch": "on", "new_wind_model_exhaust_wind": "80"}, + "full": {"new_wind_model_exhaust_switch": "on", "new_wind_model_exhaust_wind": "100"} + } + }, + "follow_body_sense": { + "options": { + "on": {"follow_body_sense": "on", "follow_body_sense_enable": 1}, + "off": {"follow_body_sense": "off", "follow_body_sense_enable": 1}, + } + } + }, + Platform.SENSOR: { + "mode": { + "device_class": SensorDeviceClass.ENUM, + }, + "indoor_temperature": { + "device_class": SensorDeviceClass.TEMPERATURE, + "unit_of_measurement": UnitOfTemperature.CELSIUS, + "state_class": SensorStateClass.MEASUREMENT + }, + "indoor_humidity": { + "device_class": SensorDeviceClass.HUMIDITY, + "unit_of_measurement": "%", + "state_class": SensorStateClass.MEASUREMENT + }, + "total_elec_value": { + "device_class": SensorDeviceClass.ENERGY, + "unit_of_measurement": "kWh", + "state_class": SensorStateClass.TOTAL_INCREASING + } + } + } } } diff --git a/custom_components/midea_auto_cloud/translations/en.json b/custom_components/midea_auto_cloud/translations/en.json index 35dc546..3ee8c0f 100644 --- a/custom_components/midea_auto_cloud/translations/en.json +++ b/custom_components/midea_auto_cloud/translations/en.json @@ -408,6 +408,25 @@ } }, "select": { + "new_wind_model_intake_enable": { + "name": "Intake Wind", + "state": { + "off": "Off", + "low": "Low Speed", + "medium": "Medium Speed", + "high": "High Speed", + "full": "Turbo" + } + }, + "new_wind_model_exhaust_enable": { + "name": "Exhaust Wind", + "state": { + "off": "Off", + "silent": "Silent", + "high": "High Speed", + "full": "Turbo" + } + }, "updown": { "name": "Running Status" }, diff --git a/custom_components/midea_auto_cloud/translations/zh-Hans.json b/custom_components/midea_auto_cloud/translations/zh-Hans.json index f7b0411..c5ad9e9 100644 --- a/custom_components/midea_auto_cloud/translations/zh-Hans.json +++ b/custom_components/midea_auto_cloud/translations/zh-Hans.json @@ -408,6 +408,25 @@ } }, "select": { + "new_wind_model_intake_enable": { + "name": "新风", + "state": { + "off": "关闭", + "low": "低速", + "medium": "中速", + "high": "高速", + "full": "强劲" + } + }, + "new_wind_model_exhaust_enable": { + "name": "排风", + "state": { + "off": "关闭", + "silent": "静音", + "high": "高速", + "full": "强劲" + } + }, "updown": { "name": "运行状态", "state": {