From e43d8651124dc89dd0af6314052c504008ae24cd Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Thu, 28 Jan 2021 02:40:10 -0600 Subject: [PATCH] Update ozw to use new fan entity model (#45577) --- homeassistant/components/ozw/fan.py | 59 +++++++++-------------------- tests/components/ozw/test_fan.py | 44 ++++++++++----------- 2 files changed, 38 insertions(+), 65 deletions(-) diff --git a/homeassistant/components/ozw/fan.py b/homeassistant/components/ozw/fan.py index 5043379303f..b4054207d0f 100644 --- a/homeassistant/components/ozw/fan.py +++ b/homeassistant/components/ozw/fan.py @@ -4,15 +4,15 @@ import math from homeassistant.components.fan import ( DOMAIN as FAN_DOMAIN, - SPEED_HIGH, - SPEED_LOW, - SPEED_MEDIUM, - SPEED_OFF, SUPPORT_SET_SPEED, FanEntity, ) from homeassistant.core import callback from homeassistant.helpers.dispatcher import async_dispatcher_connect +from homeassistant.util.percentage import ( + percentage_to_ranged_value, + ranged_value_to_percentage, +) from .const import DATA_UNSUBSCRIBE, DOMAIN from .entity import ZWaveDeviceEntity @@ -20,11 +20,7 @@ from .entity import ZWaveDeviceEntity _LOGGER = logging.getLogger(__name__) SUPPORTED_FEATURES = SUPPORT_SET_SPEED - -# Value will first be divided to an integer -VALUE_TO_SPEED = {0: SPEED_OFF, 1: SPEED_LOW, 2: SPEED_MEDIUM, 3: SPEED_HIGH} -SPEED_TO_VALUE = {SPEED_OFF: 0, SPEED_LOW: 1, SPEED_MEDIUM: 50, SPEED_HIGH: 99} -SPEED_LIST = [*SPEED_TO_VALUE] +SPEED_RANGE = (1, 99) # off is not included async def async_setup_entry(hass, config_entry, async_add_entities): @@ -44,35 +40,22 @@ async def async_setup_entry(hass, config_entry, async_add_entities): class ZwaveFan(ZWaveDeviceEntity, FanEntity): """Representation of a Z-Wave fan.""" - def __init__(self, values): - """Initialize the fan.""" - super().__init__(values) - self._previous_speed = None + async def async_set_percentage(self, percentage): + """Set the speed percentage of the fan.""" + if percentage is None: + # Value 255 tells device to return to previous value + zwave_speed = 255 + elif percentage == 0: + zwave_speed = 0 + else: + zwave_speed = math.ceil(percentage_to_ranged_value(SPEED_RANGE, percentage)) + self.values.primary.send_value(zwave_speed) - async def async_set_speed(self, speed): - """Set the speed of the fan.""" - if speed not in SPEED_TO_VALUE: - _LOGGER.warning("Invalid speed received: %s", speed) - return - self._previous_speed = speed - self.values.primary.send_value(SPEED_TO_VALUE[speed]) - - # - # The fan entity model has changed to use percentages and preset_modes - # instead of speeds. - # - # Please review - # https://developers.home-assistant.io/docs/core/entity/fan/ - # async def async_turn_on( self, speed=None, percentage=None, preset_mode=None, **kwargs ): """Turn the device on.""" - if speed is None: - # Value 255 tells device to return to previous value - self.values.primary.send_value(255) - else: - await self.async_set_speed(speed) + await self.async_set_percentage(percentage) async def async_turn_off(self, **kwargs): """Turn the device off.""" @@ -84,19 +67,13 @@ class ZwaveFan(ZWaveDeviceEntity, FanEntity): return self.values.primary.value > 0 @property - def speed(self): + def percentage(self): """Return the current speed. The Z-Wave speed value is a byte 0-255. 255 means previous value. The normal range of the speed is 0-99. 0 means off. """ - value = math.ceil(self.values.primary.value * 3 / 100) - return VALUE_TO_SPEED.get(value, self._previous_speed) - - @property - def speed_list(self): - """Get the list of available speeds.""" - return SPEED_LIST + return ranged_value_to_percentage(SPEED_RANGE, self.values.primary.value) @property def supported_features(self): diff --git a/tests/components/ozw/test_fan.py b/tests/components/ozw/test_fan.py index cca1143c44b..5556b663f6f 100644 --- a/tests/components/ozw/test_fan.py +++ b/tests/components/ozw/test_fan.py @@ -1,5 +1,5 @@ -"""Test Z-Wave Lights.""" -from homeassistant.components.ozw.fan import SPEED_TO_VALUE +"""Test Z-Wave Fans.""" +import pytest from .common import setup_ozw @@ -38,11 +38,10 @@ async def test_fan(hass, fan_data, fan_msg, sent_messages, caplog): assert state.state == "off" # Test turning on - new_speed = "medium" await hass.services.async_call( "fan", "turn_on", - {"entity_id": "fan.in_wall_smart_fan_control_level", "speed": new_speed}, + {"entity_id": "fan.in_wall_smart_fan_control_level", "percentage": 66}, blocking=True, ) @@ -50,13 +49,13 @@ async def test_fan(hass, fan_data, fan_msg, sent_messages, caplog): msg = sent_messages[-1] assert msg["topic"] == "OpenZWave/1/command/setvalue/" assert msg["payload"] == { - "Value": SPEED_TO_VALUE[new_speed], + "Value": 66, "ValueIDKey": 172589073, } # Feedback on state fan_msg.decode() - fan_msg.payload["Value"] = SPEED_TO_VALUE[new_speed] + fan_msg.payload["Value"] = 66 fan_msg.encode() receive_message(fan_msg) await hass.async_block_till_done() @@ -64,7 +63,7 @@ async def test_fan(hass, fan_data, fan_msg, sent_messages, caplog): state = hass.states.get("fan.in_wall_smart_fan_control_level") assert state is not None assert state.state == "on" - assert state.attributes["speed"] == new_speed + assert state.attributes["percentage"] == 66 # Test turn on without speed await hass.services.async_call( @@ -84,7 +83,7 @@ async def test_fan(hass, fan_data, fan_msg, sent_messages, caplog): # Feedback on state fan_msg.decode() - fan_msg.payload["Value"] = SPEED_TO_VALUE[new_speed] + fan_msg.payload["Value"] = 99 fan_msg.encode() receive_message(fan_msg) await hass.async_block_till_done() @@ -92,14 +91,13 @@ async def test_fan(hass, fan_data, fan_msg, sent_messages, caplog): state = hass.states.get("fan.in_wall_smart_fan_control_level") assert state is not None assert state.state == "on" - assert state.attributes["speed"] == new_speed + assert state.attributes["percentage"] == 100 - # Test set speed to off - new_speed = "off" + # Test set percentage to 0 await hass.services.async_call( "fan", - "set_speed", - {"entity_id": "fan.in_wall_smart_fan_control_level", "speed": new_speed}, + "set_percentage", + {"entity_id": "fan.in_wall_smart_fan_control_level", "percentage": 0}, blocking=True, ) @@ -107,13 +105,13 @@ async def test_fan(hass, fan_data, fan_msg, sent_messages, caplog): msg = sent_messages[-1] assert msg["topic"] == "OpenZWave/1/command/setvalue/" assert msg["payload"] == { - "Value": SPEED_TO_VALUE[new_speed], + "Value": 0, "ValueIDKey": 172589073, } # Feedback on state fan_msg.decode() - fan_msg.payload["Value"] = SPEED_TO_VALUE[new_speed] + fan_msg.payload["Value"] = 0 fan_msg.encode() receive_message(fan_msg) await hass.async_block_till_done() @@ -124,12 +122,10 @@ async def test_fan(hass, fan_data, fan_msg, sent_messages, caplog): # Test invalid speed new_speed = "invalid" - await hass.services.async_call( - "fan", - "set_speed", - {"entity_id": "fan.in_wall_smart_fan_control_level", "speed": new_speed}, - blocking=True, - ) - - assert len(sent_messages) == 4 - assert "Invalid speed received: invalid" in caplog.text + with pytest.raises(ValueError): + await hass.services.async_call( + "fan", + "set_speed", + {"entity_id": "fan.in_wall_smart_fan_control_level", "speed": new_speed}, + blocking=True, + )