From 5d7e9a6695eaa67b8319703fe1d10070fe493d75 Mon Sep 17 00:00:00 2001
From: Pete <github@kthxbye.us>
Date: Sat, 3 Sep 2022 22:55:34 +0200
Subject: [PATCH] Fix setting and reading percentage for MIOT based fans
 (#77626)

---
 homeassistant/components/xiaomi_miio/const.py |  9 +++++
 homeassistant/components/xiaomi_miio/fan.py   | 36 ++++++++++++++-----
 2 files changed, 36 insertions(+), 9 deletions(-)

diff --git a/homeassistant/components/xiaomi_miio/const.py b/homeassistant/components/xiaomi_miio/const.py
index c0711a02a36..11922956c25 100644
--- a/homeassistant/components/xiaomi_miio/const.py
+++ b/homeassistant/components/xiaomi_miio/const.py
@@ -112,6 +112,15 @@ MODELS_FAN_MIOT = [
     MODEL_FAN_ZA5,
 ]
 
+# number of speed levels each fan has
+SPEEDS_FAN_MIOT = {
+    MODEL_FAN_1C: 3,
+    MODEL_FAN_P10: 4,
+    MODEL_FAN_P11: 4,
+    MODEL_FAN_P9: 4,
+    MODEL_FAN_ZA5: 4,
+}
+
 MODELS_PURIFIER_MIOT = [
     MODEL_AIRPURIFIER_3,
     MODEL_AIRPURIFIER_3C,
diff --git a/homeassistant/components/xiaomi_miio/fan.py b/homeassistant/components/xiaomi_miio/fan.py
index 39988976564..901211d1d2d 100644
--- a/homeassistant/components/xiaomi_miio/fan.py
+++ b/homeassistant/components/xiaomi_miio/fan.py
@@ -85,6 +85,7 @@ from .const import (
     MODELS_PURIFIER_MIOT,
     SERVICE_RESET_FILTER,
     SERVICE_SET_EXTRA_FEATURES,
+    SPEEDS_FAN_MIOT,
 )
 from .device import XiaomiCoordinatedMiioEntity
 
@@ -234,9 +235,13 @@ async def async_setup_entry(
     elif model in MODELS_FAN_MIIO:
         entity = XiaomiFan(device, config_entry, unique_id, coordinator)
     elif model == MODEL_FAN_ZA5:
-        entity = XiaomiFanZA5(device, config_entry, unique_id, coordinator)
+        speed_count = SPEEDS_FAN_MIOT[model]
+        entity = XiaomiFanZA5(device, config_entry, unique_id, coordinator, speed_count)
     elif model in MODELS_FAN_MIOT:
-        entity = XiaomiFanMiot(device, config_entry, unique_id, coordinator)
+        speed_count = SPEEDS_FAN_MIOT[model]
+        entity = XiaomiFanMiot(
+            device, config_entry, unique_id, coordinator, speed_count
+        )
     else:
         return
 
@@ -1044,6 +1049,11 @@ class XiaomiFanP5(XiaomiGenericFan):
 class XiaomiFanMiot(XiaomiGenericFan):
     """Representation of a Xiaomi Fan Miot."""
 
+    def __init__(self, device, entry, unique_id, coordinator, speed_count):
+        """Initialize MIOT fan with speed count."""
+        super().__init__(device, entry, unique_id, coordinator)
+        self._speed_count = speed_count
+
     @property
     def operation_mode_class(self):
         """Hold operation mode class."""
@@ -1061,7 +1071,9 @@ class XiaomiFanMiot(XiaomiGenericFan):
         self._preset_mode = self.coordinator.data.mode.name
         self._oscillating = self.coordinator.data.oscillate
         if self.coordinator.data.is_on:
-            self._percentage = self.coordinator.data.speed
+            self._percentage = ranged_value_to_percentage(
+                (1, self._speed_count), self.coordinator.data.speed
+            )
         else:
             self._percentage = 0
 
@@ -1087,16 +1099,22 @@ class XiaomiFanMiot(XiaomiGenericFan):
             await self.async_turn_off()
             return
 
-        await self._try_command(
-            "Setting fan speed percentage of the miio device failed.",
-            self._device.set_speed,
-            percentage,
+        speed = math.ceil(
+            percentage_to_ranged_value((1, self._speed_count), percentage)
         )
-        self._percentage = percentage
 
+        # if the fan is not on, we have to turn it on first
         if not self.is_on:
             await self.async_turn_on()
-        else:
+
+        result = await self._try_command(
+            "Setting fan speed percentage of the miio device failed.",
+            self._device.set_speed,
+            speed,
+        )
+
+        if result:
+            self._percentage = ranged_value_to_percentage((1, self._speed_count), speed)
             self.async_write_ha_state()
 
 
-- 
GitLab