Skip to content

Commit

Permalink
fix: fan speed (#464)
Browse files Browse the repository at this point in the history
* fix: fan speed

* fix: fan speed names map

* fix: set percentage

* docs: the instance code format of valuelist

* fix: fan level property

* fix: pylint too long line.

* style: code format

---------

Co-authored-by: topsworld <[email protected]>
  • Loading branch information
SusanPhevos and topsworld authored Jan 7, 2025
1 parent d65fe32 commit ce7ce7a
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 26 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -351,7 +351,7 @@ The instance code is the code of the MIoT-Spec-V2 instance, which is in the form
```
service:<siid> # service
service:<siid>:property:<piid> # property
service:<siid>:property:<piid>:valuelist:<value> # the value in value-list of a property
service:<siid>:property:<piid>:valuelist:<index> # The index of a value in the value-list of a property
service:<siid>:event:<eiid> # event
service:<siid>:action:<aiid> # action
```
Expand Down
80 changes: 55 additions & 25 deletions custom_components/xiaomi_home/fan.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,9 @@
from homeassistant.components.fan import FanEntity, FanEntityFeature
from homeassistant.util.percentage import (
percentage_to_ranged_value,
ranged_value_to_percentage
ranged_value_to_percentage,
ordered_list_item_to_percentage,
percentage_to_ordered_list_item
)

from .miot.miot_spec import MIoTSpecProperty
Expand Down Expand Up @@ -90,9 +92,11 @@ class Fan(MIoTServiceEntity, FanEntity):
_prop_mode: Optional[MIoTSpecProperty]
_prop_horizontal_swing: Optional[MIoTSpecProperty]

_speed_min: Optional[int]
_speed_max: Optional[int]
_speed_step: Optional[int]
_speed_min: int
_speed_max: int
_speed_step: int
_speed_names: Optional[list]
_speed_name_map: Optional[dict[int, str]]
_mode_list: Optional[dict[Any, Any]]

def __init__(
Expand All @@ -110,6 +114,9 @@ def __init__(
self._speed_min = 65535
self._speed_max = 0
self._speed_step = 1
self._speed_names = []
self._speed_name_map = {}

self._mode_list = None

# properties
Expand All @@ -124,7 +131,8 @@ def __init__(
self._speed_min = prop.value_range['min']
self._speed_max = prop.value_range['max']
self._speed_step = prop.value_range['step']
self._attr_speed_count = self._speed_max - self._speed_min+1
self._attr_speed_count = int((
self._speed_max - self._speed_min)/self._speed_step)+1
self._attr_supported_features |= FanEntityFeature.SET_SPEED
self._prop_fan_level = prop
elif (
Expand All @@ -133,10 +141,13 @@ def __init__(
and prop.value_list
):
# Fan level with value-list
for item in prop.value_list:
self._speed_min = min(self._speed_min, item['value'])
self._speed_max = max(self._speed_max, item['value'])
self._attr_speed_count = self._speed_max - self._speed_min+1
# Fan level with value-range is prior to fan level with
# value-list when a fan has both fan level properties.
self._speed_name_map = {
item['value']: item['description']
for item in prop.value_list}
self._speed_names = list(self._speed_name_map.values())
self._attr_speed_count = len(prop.value_list)
self._attr_supported_features |= FanEntityFeature.SET_SPEED
self._prop_fan_level = prop
elif prop.name == 'mode':
Expand Down Expand Up @@ -182,9 +193,19 @@ async def async_turn_on(
await self.set_property_async(prop=self._prop_on, value=True)
# percentage
if percentage:
await self.set_property_async(
prop=self._prop_fan_level,
value=int(percentage*self._attr_speed_count/100))
if self._speed_names:
speed = percentage_to_ordered_list_item(
self._speed_names, percentage)
speed_value = self.get_map_value(
map_=self._speed_name_map, description=speed)
await self.set_property_async(
prop=self._prop_fan_level, value=speed_value)
else:
await self.set_property_async(
prop=self._prop_fan_level,
value=int(percentage_to_ranged_value(
low_high_range=(self._speed_min, self._speed_max),
percentage=percentage)))
# preset_mode
if preset_mode:
await self.set_property_async(
Expand All @@ -202,11 +223,19 @@ async def async_toggle(self, **kwargs: Any) -> None:
async def async_set_percentage(self, percentage: int) -> None:
"""Set the percentage of the fan speed."""
if percentage > 0:
await self.set_property_async(
prop=self._prop_fan_level,
value=int(percentage_to_ranged_value(
low_high_range=(self._speed_min, self._speed_max),
percentage=percentage)))
if self._speed_names:
speed = percentage_to_ordered_list_item(
self._speed_names, percentage)
speed_value = self.get_map_value(
map_=self._speed_name_map, description=speed)
await self.set_property_async(
prop=self._prop_fan_level, value=speed_value)
else:
await self.set_property_async(
prop=self._prop_fan_level,
value=int(percentage_to_ranged_value(
low_high_range=(self._speed_min, self._speed_max),
percentage=percentage)))
if not self.is_on:
# If the fan is off, turn it on.
await self.set_property_async(prop=self._prop_on, value=True)
Expand Down Expand Up @@ -246,9 +275,15 @@ def preset_mode(self) -> Optional[str]:
def percentage(self) -> Optional[int]:
"""Return the current percentage of the fan speed."""
fan_level = self.get_prop_value(prop=self._prop_fan_level)
return ranged_value_to_percentage(
low_high_range=(self._speed_min, self._speed_max),
value=fan_level) if fan_level else None
if fan_level is None:
return None
if self._speed_names:
return ordered_list_item_to_percentage(
self._speed_names, self._speed_name_map[fan_level])
else:
return ranged_value_to_percentage(
low_high_range=(self._speed_min, self._speed_max),
value=fan_level)

@property
def oscillating(self) -> Optional[bool]:
Expand All @@ -257,8 +292,3 @@ def oscillating(self) -> Optional[bool]:
self.get_prop_value(
prop=self._prop_horizontal_swing)
if self._prop_horizontal_swing else None)

@property
def percentage_step(self) -> float:
"""Return the step of the fan speed."""
return self._speed_step

0 comments on commit ce7ce7a

Please sign in to comment.