Cleanup inconsistencies in zha fan and make it a bit more dry (#46714)

Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
This commit is contained in:
J. Nick Koston 2021-02-19 19:42:14 -10:00 committed by GitHub
parent bb7e4d7daa
commit 71586b7661
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 32 additions and 22 deletions

View File

@ -13,11 +13,13 @@ from homeassistant.components.fan import (
DOMAIN, DOMAIN,
SUPPORT_SET_SPEED, SUPPORT_SET_SPEED,
FanEntity, FanEntity,
NotValidPresetModeError,
) )
from homeassistant.const import STATE_UNAVAILABLE from homeassistant.const import STATE_UNAVAILABLE
from homeassistant.core import State, callback from homeassistant.core import State, callback
from homeassistant.helpers.dispatcher import async_dispatcher_connect from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.util.percentage import ( from homeassistant.util.percentage import (
int_states_in_range,
percentage_to_ranged_value, percentage_to_ranged_value,
ranged_value_to_percentage, ranged_value_to_percentage,
) )
@ -75,7 +77,7 @@ class BaseFan(FanEntity):
"""Base representation of a ZHA fan.""" """Base representation of a ZHA fan."""
@property @property
def preset_modes(self) -> str: def preset_modes(self) -> List[str]:
"""Return the available preset modes.""" """Return the available preset modes."""
return PRESET_MODES return PRESET_MODES
@ -84,10 +86,17 @@ class BaseFan(FanEntity):
"""Flag supported features.""" """Flag supported features."""
return SUPPORT_SET_SPEED return SUPPORT_SET_SPEED
@property
def speed_count(self) -> int:
"""Return the number of speeds the fan supports."""
return int_states_in_range(SPEED_RANGE)
async def async_turn_on( async def async_turn_on(
self, speed=None, percentage=None, preset_mode=None, **kwargs self, speed=None, percentage=None, preset_mode=None, **kwargs
) -> None: ) -> None:
"""Turn the entity on.""" """Turn the entity on."""
if percentage is None:
percentage = DEFAULT_ON_PERCENTAGE
await self.async_set_percentage(percentage) await self.async_set_percentage(percentage)
async def async_turn_off(self, **kwargs) -> None: async def async_turn_off(self, **kwargs) -> None:
@ -96,15 +105,16 @@ class BaseFan(FanEntity):
async def async_set_percentage(self, percentage: Optional[int]) -> None: async def async_set_percentage(self, percentage: Optional[int]) -> None:
"""Set the speed percenage of the fan.""" """Set the speed percenage of the fan."""
if percentage is None:
percentage = DEFAULT_ON_PERCENTAGE
fan_mode = math.ceil(percentage_to_ranged_value(SPEED_RANGE, percentage)) fan_mode = math.ceil(percentage_to_ranged_value(SPEED_RANGE, percentage))
await self._async_set_fan_mode(fan_mode) await self._async_set_fan_mode(fan_mode)
async def async_set_preset_mode(self, preset_mode: str) -> None: async def async_set_preset_mode(self, preset_mode: str) -> None:
"""Set the speed percenage of the fan.""" """Set the preset mode for the fan."""
fan_mode = NAME_TO_PRESET_MODE.get(preset_mode) if preset_mode not in self.preset_modes:
await self._async_set_fan_mode(fan_mode) raise NotValidPresetModeError(
f"The preset_mode {preset_mode} is not a valid preset_mode: {self.preset_modes}"
)
await self._async_set_fan_mode(NAME_TO_PRESET_MODE[preset_mode])
@abstractmethod @abstractmethod
async def _async_set_fan_mode(self, fan_mode: int) -> None: async def _async_set_fan_mode(self, fan_mode: int) -> None:
@ -132,7 +142,7 @@ class ZhaFan(BaseFan, ZhaEntity):
) )
@property @property
def percentage(self) -> str: def percentage(self) -> Optional[int]:
"""Return the current speed percentage.""" """Return the current speed percentage."""
if ( if (
self._fan_channel.fan_mode is None self._fan_channel.fan_mode is None
@ -144,7 +154,7 @@ class ZhaFan(BaseFan, ZhaEntity):
return ranged_value_to_percentage(SPEED_RANGE, self._fan_channel.fan_mode) return ranged_value_to_percentage(SPEED_RANGE, self._fan_channel.fan_mode)
@property @property
def preset_mode(self) -> str: def preset_mode(self) -> Optional[str]:
"""Return the current preset mode.""" """Return the current preset mode."""
return PRESET_MODES_TO_NAME.get(self._fan_channel.fan_mode) return PRESET_MODES_TO_NAME.get(self._fan_channel.fan_mode)
@ -175,27 +185,15 @@ class FanGroup(BaseFan, ZhaGroupEntity):
self._preset_mode = None self._preset_mode = None
@property @property
def percentage(self) -> str: def percentage(self) -> Optional[int]:
"""Return the current speed percentage.""" """Return the current speed percentage."""
return self._percentage return self._percentage
@property @property
def preset_mode(self) -> str: def preset_mode(self) -> Optional[str]:
"""Return the current preset mode.""" """Return the current preset mode."""
return self._preset_mode return self._preset_mode
async def async_set_percentage(self, percentage: Optional[int]) -> None:
"""Set the speed percenage of the fan."""
if percentage is None:
percentage = DEFAULT_ON_PERCENTAGE
fan_mode = math.ceil(percentage_to_ranged_value(SPEED_RANGE, percentage))
await self._async_set_fan_mode(fan_mode)
async def async_set_preset_mode(self, preset_mode: str) -> None:
"""Set the speed percenage of the fan."""
fan_mode = NAME_TO_PRESET_MODE.get(preset_mode)
await self._async_set_fan_mode(fan_mode)
async def _async_set_fan_mode(self, fan_mode: int) -> None: async def _async_set_fan_mode(self, fan_mode: int) -> None:
"""Set the fan mode for the group.""" """Set the fan mode for the group."""
try: try:

View File

@ -11,6 +11,7 @@ import zigpy.zcl.foundation as zcl_f
from homeassistant.components import fan from homeassistant.components import fan
from homeassistant.components.fan import ( from homeassistant.components.fan import (
ATTR_PERCENTAGE, ATTR_PERCENTAGE,
ATTR_PERCENTAGE_STEP,
ATTR_PRESET_MODE, ATTR_PRESET_MODE,
ATTR_SPEED, ATTR_SPEED,
DOMAIN, DOMAIN,
@ -20,6 +21,7 @@ from homeassistant.components.fan import (
SPEED_LOW, SPEED_LOW,
SPEED_MEDIUM, SPEED_MEDIUM,
SPEED_OFF, SPEED_OFF,
NotValidPresetModeError,
) )
from homeassistant.components.light import DOMAIN as LIGHT_DOMAIN from homeassistant.components.light import DOMAIN as LIGHT_DOMAIN
from homeassistant.components.zha.core.discovery import GROUP_PROBE from homeassistant.components.zha.core.discovery import GROUP_PROBE
@ -188,6 +190,14 @@ async def test_fan(hass, zha_device_joined_restored, zigpy_device):
assert len(cluster.write_attributes.mock_calls) == 1 assert len(cluster.write_attributes.mock_calls) == 1
assert cluster.write_attributes.call_args == call({"fan_mode": 4}) assert cluster.write_attributes.call_args == call({"fan_mode": 4})
# set invalid preset_mode from HA
cluster.write_attributes.reset_mock()
with pytest.raises(NotValidPresetModeError):
await async_set_preset_mode(
hass, entity_id, preset_mode="invalid does not exist"
)
assert len(cluster.write_attributes.mock_calls) == 0
# test adding new fan to the network and HA # test adding new fan to the network and HA
await async_test_rejoin(hass, zigpy_device, [cluster], (1,)) await async_test_rejoin(hass, zigpy_device, [cluster], (1,))
@ -450,6 +460,7 @@ async def test_fan_update_entity(
assert hass.states.get(entity_id).attributes[ATTR_SPEED] == SPEED_OFF assert hass.states.get(entity_id).attributes[ATTR_SPEED] == SPEED_OFF
assert hass.states.get(entity_id).attributes[ATTR_PERCENTAGE] == 0 assert hass.states.get(entity_id).attributes[ATTR_PERCENTAGE] == 0
assert hass.states.get(entity_id).attributes[ATTR_PRESET_MODE] is None assert hass.states.get(entity_id).attributes[ATTR_PRESET_MODE] is None
assert hass.states.get(entity_id).attributes[ATTR_PERCENTAGE_STEP] == 100 / 3
assert cluster.read_attributes.await_count == 1 assert cluster.read_attributes.await_count == 1
await async_setup_component(hass, "homeassistant", {}) await async_setup_component(hass, "homeassistant", {})
@ -470,4 +481,5 @@ async def test_fan_update_entity(
assert hass.states.get(entity_id).attributes[ATTR_PERCENTAGE] == 33 assert hass.states.get(entity_id).attributes[ATTR_PERCENTAGE] == 33
assert hass.states.get(entity_id).attributes[ATTR_SPEED] == SPEED_LOW assert hass.states.get(entity_id).attributes[ATTR_SPEED] == SPEED_LOW
assert hass.states.get(entity_id).attributes[ATTR_PRESET_MODE] is None assert hass.states.get(entity_id).attributes[ATTR_PRESET_MODE] is None
assert hass.states.get(entity_id).attributes[ATTR_PERCENTAGE_STEP] == 100 / 3
assert cluster.read_attributes.await_count == 3 assert cluster.read_attributes.await_count == 3