From ab1d42950a522abc098c3adc7024066b11cf4471 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Thu, 28 Jan 2021 04:43:43 -0600 Subject: [PATCH] Update homekit_controller to use new fan entity model (#45547) --- .../components/homekit_controller/fan.py | 54 +++----------- .../components/homekit_controller/test_fan.py | 70 ++++++++++++++++--- 2 files changed, 71 insertions(+), 53 deletions(-) diff --git a/homeassistant/components/homekit_controller/fan.py b/homeassistant/components/homekit_controller/fan.py index 828347e4b89..e2cdf7b3cfd 100644 --- a/homeassistant/components/homekit_controller/fan.py +++ b/homeassistant/components/homekit_controller/fan.py @@ -5,10 +5,6 @@ from aiohomekit.model.services import ServicesTypes from homeassistant.components.fan import ( DIRECTION_FORWARD, DIRECTION_REVERSE, - SPEED_HIGH, - SPEED_LOW, - SPEED_MEDIUM, - SPEED_OFF, SUPPORT_DIRECTION, SUPPORT_OSCILLATE, SUPPORT_SET_SPEED, @@ -26,13 +22,6 @@ DIRECTION_TO_HK = { } HK_DIRECTION_TO_HA = {v: k for (k, v) in DIRECTION_TO_HK.items()} -SPEED_TO_PCNT = { - SPEED_HIGH: 100, - SPEED_MEDIUM: 50, - SPEED_LOW: 25, - SPEED_OFF: 0, -} - class BaseHomeKitFan(HomeKitEntity, FanEntity): """Representation of a Homekit fan.""" @@ -56,30 +45,12 @@ class BaseHomeKitFan(HomeKitEntity, FanEntity): return self.service.value(self.on_characteristic) == 1 @property - def speed(self): - """Return the current speed.""" + def percentage(self): + """Return the current speed percentage.""" if not self.is_on: - return SPEED_OFF + return 0 - rotation_speed = self.service.value(CharacteristicsTypes.ROTATION_SPEED) - - if rotation_speed > SPEED_TO_PCNT[SPEED_MEDIUM]: - return SPEED_HIGH - - if rotation_speed > SPEED_TO_PCNT[SPEED_LOW]: - return SPEED_MEDIUM - - if rotation_speed > SPEED_TO_PCNT[SPEED_OFF]: - return SPEED_LOW - - return SPEED_OFF - - @property - def speed_list(self): - """Get the list of available speeds.""" - if self.supported_features & SUPPORT_SET_SPEED: - return [SPEED_OFF, SPEED_LOW, SPEED_MEDIUM, SPEED_HIGH] - return [] + return self.service.value(CharacteristicsTypes.ROTATION_SPEED) @property def current_direction(self): @@ -115,13 +86,13 @@ class BaseHomeKitFan(HomeKitEntity, FanEntity): {CharacteristicsTypes.ROTATION_DIRECTION: DIRECTION_TO_HK[direction]} ) - async def async_set_speed(self, speed): + async def async_set_percentage(self, percentage): """Set the speed of the fan.""" - if speed == SPEED_OFF: + if percentage == 0: return await self.async_turn_off() await self.async_put_characteristics( - {CharacteristicsTypes.ROTATION_SPEED: SPEED_TO_PCNT[speed]} + {CharacteristicsTypes.ROTATION_SPEED: percentage} ) async def async_oscillate(self, oscillating: bool): @@ -130,13 +101,6 @@ class BaseHomeKitFan(HomeKitEntity, FanEntity): {CharacteristicsTypes.SWING_MODE: 1 if oscillating else 0} ) - # - # 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 ): @@ -146,8 +110,8 @@ class BaseHomeKitFan(HomeKitEntity, FanEntity): if not self.is_on: characteristics[self.on_characteristic] = True - if self.supported_features & SUPPORT_SET_SPEED and speed: - characteristics[CharacteristicsTypes.ROTATION_SPEED] = SPEED_TO_PCNT[speed] + if self.supported_features & SUPPORT_SET_SPEED: + characteristics[CharacteristicsTypes.ROTATION_SPEED] = percentage if characteristics: await self.async_put_characteristics(characteristics) diff --git a/tests/components/homekit_controller/test_fan.py b/tests/components/homekit_controller/test_fan.py index e9ebce4045b..b8d42b21643 100644 --- a/tests/components/homekit_controller/test_fan.py +++ b/tests/components/homekit_controller/test_fan.py @@ -83,7 +83,7 @@ async def test_turn_on(hass, utcnow): blocking=True, ) assert helper.characteristics[V1_ON].value == 1 - assert helper.characteristics[V1_ROTATION_SPEED].value == 50 + assert helper.characteristics[V1_ROTATION_SPEED].value == 66.0 await hass.services.async_call( "fan", @@ -92,7 +92,7 @@ async def test_turn_on(hass, utcnow): blocking=True, ) assert helper.characteristics[V1_ON].value == 1 - assert helper.characteristics[V1_ROTATION_SPEED].value == 25 + assert helper.characteristics[V1_ROTATION_SPEED].value == 33.0 async def test_turn_off(hass, utcnow): @@ -130,7 +130,7 @@ async def test_set_speed(hass, utcnow): {"entity_id": "fan.testdevice", "speed": "medium"}, blocking=True, ) - assert helper.characteristics[V1_ROTATION_SPEED].value == 50 + assert helper.characteristics[V1_ROTATION_SPEED].value == 66.0 await hass.services.async_call( "fan", @@ -138,7 +138,7 @@ async def test_set_speed(hass, utcnow): {"entity_id": "fan.testdevice", "speed": "low"}, blocking=True, ) - assert helper.characteristics[V1_ROTATION_SPEED].value == 25 + assert helper.characteristics[V1_ROTATION_SPEED].value == 33.0 await hass.services.async_call( "fan", @@ -149,6 +149,29 @@ async def test_set_speed(hass, utcnow): assert helper.characteristics[V1_ON].value == 0 +async def test_set_percentage(hass, utcnow): + """Test that we set fan speed by percentage.""" + helper = await setup_test_component(hass, create_fan_service) + + helper.characteristics[V1_ON].value = 1 + + await hass.services.async_call( + "fan", + "set_percentage", + {"entity_id": "fan.testdevice", "percentage": 66}, + blocking=True, + ) + assert helper.characteristics[V1_ROTATION_SPEED].value == 66 + + await hass.services.async_call( + "fan", + "set_percentage", + {"entity_id": "fan.testdevice", "percentage": 0}, + blocking=True, + ) + assert helper.characteristics[V1_ON].value == 0 + + async def test_speed_read(hass, utcnow): """Test that we can read a fans oscillation.""" helper = await setup_test_component(hass, create_fan_service) @@ -157,19 +180,23 @@ async def test_speed_read(hass, utcnow): helper.characteristics[V1_ROTATION_SPEED].value = 100 state = await helper.poll_and_get_state() assert state.attributes["speed"] == "high" + assert state.attributes["percentage"] == 100 helper.characteristics[V1_ROTATION_SPEED].value = 50 state = await helper.poll_and_get_state() assert state.attributes["speed"] == "medium" + assert state.attributes["percentage"] == 50 helper.characteristics[V1_ROTATION_SPEED].value = 25 state = await helper.poll_and_get_state() assert state.attributes["speed"] == "low" + assert state.attributes["percentage"] == 25 helper.characteristics[V1_ON].value = 0 helper.characteristics[V1_ROTATION_SPEED].value = 0 state = await helper.poll_and_get_state() assert state.attributes["speed"] == "off" + assert state.attributes["percentage"] == 0 async def test_set_direction(hass, utcnow): @@ -239,7 +266,7 @@ async def test_v2_turn_on(hass, utcnow): blocking=True, ) assert helper.characteristics[V2_ACTIVE].value == 1 - assert helper.characteristics[V2_ROTATION_SPEED].value == 50 + assert helper.characteristics[V2_ROTATION_SPEED].value == 66.0 await hass.services.async_call( "fan", @@ -248,7 +275,7 @@ async def test_v2_turn_on(hass, utcnow): blocking=True, ) assert helper.characteristics[V2_ACTIVE].value == 1 - assert helper.characteristics[V2_ROTATION_SPEED].value == 25 + assert helper.characteristics[V2_ROTATION_SPEED].value == 33.0 async def test_v2_turn_off(hass, utcnow): @@ -286,7 +313,7 @@ async def test_v2_set_speed(hass, utcnow): {"entity_id": "fan.testdevice", "speed": "medium"}, blocking=True, ) - assert helper.characteristics[V2_ROTATION_SPEED].value == 50 + assert helper.characteristics[V2_ROTATION_SPEED].value == 66 await hass.services.async_call( "fan", @@ -294,7 +321,7 @@ async def test_v2_set_speed(hass, utcnow): {"entity_id": "fan.testdevice", "speed": "low"}, blocking=True, ) - assert helper.characteristics[V2_ROTATION_SPEED].value == 25 + assert helper.characteristics[V2_ROTATION_SPEED].value == 33 await hass.services.async_call( "fan", @@ -305,6 +332,29 @@ async def test_v2_set_speed(hass, utcnow): assert helper.characteristics[V2_ACTIVE].value == 0 +async def test_v2_set_percentage(hass, utcnow): + """Test that we set fan speed by percentage.""" + helper = await setup_test_component(hass, create_fanv2_service) + + helper.characteristics[V2_ACTIVE].value = 1 + + await hass.services.async_call( + "fan", + "set_percentage", + {"entity_id": "fan.testdevice", "percentage": 66}, + blocking=True, + ) + assert helper.characteristics[V2_ROTATION_SPEED].value == 66 + + await hass.services.async_call( + "fan", + "set_percentage", + {"entity_id": "fan.testdevice", "percentage": 0}, + blocking=True, + ) + assert helper.characteristics[V2_ACTIVE].value == 0 + + async def test_v2_speed_read(hass, utcnow): """Test that we can read a fans oscillation.""" helper = await setup_test_component(hass, create_fanv2_service) @@ -313,19 +363,23 @@ async def test_v2_speed_read(hass, utcnow): helper.characteristics[V2_ROTATION_SPEED].value = 100 state = await helper.poll_and_get_state() assert state.attributes["speed"] == "high" + assert state.attributes["percentage"] == 100 helper.characteristics[V2_ROTATION_SPEED].value = 50 state = await helper.poll_and_get_state() assert state.attributes["speed"] == "medium" + assert state.attributes["percentage"] == 50 helper.characteristics[V2_ROTATION_SPEED].value = 25 state = await helper.poll_and_get_state() assert state.attributes["speed"] == "low" + assert state.attributes["percentage"] == 25 helper.characteristics[V2_ACTIVE].value = 0 helper.characteristics[V2_ROTATION_SPEED].value = 0 state = await helper.poll_and_get_state() assert state.attributes["speed"] == "off" + assert state.attributes["percentage"] == 0 async def test_v2_set_direction(hass, utcnow):