Update homekit_controller to use new fan entity model (#45547)

This commit is contained in:
J. Nick Koston 2021-01-28 04:43:43 -06:00 committed by GitHub
parent babfef829d
commit ab1d42950a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 71 additions and 53 deletions

View file

@ -5,10 +5,6 @@ from aiohomekit.model.services import ServicesTypes
from homeassistant.components.fan import ( from homeassistant.components.fan import (
DIRECTION_FORWARD, DIRECTION_FORWARD,
DIRECTION_REVERSE, DIRECTION_REVERSE,
SPEED_HIGH,
SPEED_LOW,
SPEED_MEDIUM,
SPEED_OFF,
SUPPORT_DIRECTION, SUPPORT_DIRECTION,
SUPPORT_OSCILLATE, SUPPORT_OSCILLATE,
SUPPORT_SET_SPEED, SUPPORT_SET_SPEED,
@ -26,13 +22,6 @@ DIRECTION_TO_HK = {
} }
HK_DIRECTION_TO_HA = {v: k for (k, v) in DIRECTION_TO_HK.items()} 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): class BaseHomeKitFan(HomeKitEntity, FanEntity):
"""Representation of a Homekit fan.""" """Representation of a Homekit fan."""
@ -56,30 +45,12 @@ class BaseHomeKitFan(HomeKitEntity, FanEntity):
return self.service.value(self.on_characteristic) == 1 return self.service.value(self.on_characteristic) == 1
@property @property
def speed(self): def percentage(self):
"""Return the current speed.""" """Return the current speed percentage."""
if not self.is_on: if not self.is_on:
return SPEED_OFF return 0
rotation_speed = self.service.value(CharacteristicsTypes.ROTATION_SPEED) return 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 []
@property @property
def current_direction(self): def current_direction(self):
@ -115,13 +86,13 @@ class BaseHomeKitFan(HomeKitEntity, FanEntity):
{CharacteristicsTypes.ROTATION_DIRECTION: DIRECTION_TO_HK[direction]} {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.""" """Set the speed of the fan."""
if speed == SPEED_OFF: if percentage == 0:
return await self.async_turn_off() return await self.async_turn_off()
await self.async_put_characteristics( await self.async_put_characteristics(
{CharacteristicsTypes.ROTATION_SPEED: SPEED_TO_PCNT[speed]} {CharacteristicsTypes.ROTATION_SPEED: percentage}
) )
async def async_oscillate(self, oscillating: bool): async def async_oscillate(self, oscillating: bool):
@ -130,13 +101,6 @@ class BaseHomeKitFan(HomeKitEntity, FanEntity):
{CharacteristicsTypes.SWING_MODE: 1 if oscillating else 0} {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( async def async_turn_on(
self, speed=None, percentage=None, preset_mode=None, **kwargs self, speed=None, percentage=None, preset_mode=None, **kwargs
): ):
@ -146,8 +110,8 @@ class BaseHomeKitFan(HomeKitEntity, FanEntity):
if not self.is_on: if not self.is_on:
characteristics[self.on_characteristic] = True characteristics[self.on_characteristic] = True
if self.supported_features & SUPPORT_SET_SPEED and speed: if self.supported_features & SUPPORT_SET_SPEED:
characteristics[CharacteristicsTypes.ROTATION_SPEED] = SPEED_TO_PCNT[speed] characteristics[CharacteristicsTypes.ROTATION_SPEED] = percentage
if characteristics: if characteristics:
await self.async_put_characteristics(characteristics) await self.async_put_characteristics(characteristics)

View file

@ -83,7 +83,7 @@ async def test_turn_on(hass, utcnow):
blocking=True, blocking=True,
) )
assert helper.characteristics[V1_ON].value == 1 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( await hass.services.async_call(
"fan", "fan",
@ -92,7 +92,7 @@ async def test_turn_on(hass, utcnow):
blocking=True, blocking=True,
) )
assert helper.characteristics[V1_ON].value == 1 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): async def test_turn_off(hass, utcnow):
@ -130,7 +130,7 @@ async def test_set_speed(hass, utcnow):
{"entity_id": "fan.testdevice", "speed": "medium"}, {"entity_id": "fan.testdevice", "speed": "medium"},
blocking=True, blocking=True,
) )
assert helper.characteristics[V1_ROTATION_SPEED].value == 50 assert helper.characteristics[V1_ROTATION_SPEED].value == 66.0
await hass.services.async_call( await hass.services.async_call(
"fan", "fan",
@ -138,7 +138,7 @@ async def test_set_speed(hass, utcnow):
{"entity_id": "fan.testdevice", "speed": "low"}, {"entity_id": "fan.testdevice", "speed": "low"},
blocking=True, blocking=True,
) )
assert helper.characteristics[V1_ROTATION_SPEED].value == 25 assert helper.characteristics[V1_ROTATION_SPEED].value == 33.0
await hass.services.async_call( await hass.services.async_call(
"fan", "fan",
@ -149,6 +149,29 @@ async def test_set_speed(hass, utcnow):
assert helper.characteristics[V1_ON].value == 0 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): async def test_speed_read(hass, utcnow):
"""Test that we can read a fans oscillation.""" """Test that we can read a fans oscillation."""
helper = await setup_test_component(hass, create_fan_service) 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 helper.characteristics[V1_ROTATION_SPEED].value = 100
state = await helper.poll_and_get_state() state = await helper.poll_and_get_state()
assert state.attributes["speed"] == "high" assert state.attributes["speed"] == "high"
assert state.attributes["percentage"] == 100
helper.characteristics[V1_ROTATION_SPEED].value = 50 helper.characteristics[V1_ROTATION_SPEED].value = 50
state = await helper.poll_and_get_state() state = await helper.poll_and_get_state()
assert state.attributes["speed"] == "medium" assert state.attributes["speed"] == "medium"
assert state.attributes["percentage"] == 50
helper.characteristics[V1_ROTATION_SPEED].value = 25 helper.characteristics[V1_ROTATION_SPEED].value = 25
state = await helper.poll_and_get_state() state = await helper.poll_and_get_state()
assert state.attributes["speed"] == "low" assert state.attributes["speed"] == "low"
assert state.attributes["percentage"] == 25
helper.characteristics[V1_ON].value = 0 helper.characteristics[V1_ON].value = 0
helper.characteristics[V1_ROTATION_SPEED].value = 0 helper.characteristics[V1_ROTATION_SPEED].value = 0
state = await helper.poll_and_get_state() state = await helper.poll_and_get_state()
assert state.attributes["speed"] == "off" assert state.attributes["speed"] == "off"
assert state.attributes["percentage"] == 0
async def test_set_direction(hass, utcnow): async def test_set_direction(hass, utcnow):
@ -239,7 +266,7 @@ async def test_v2_turn_on(hass, utcnow):
blocking=True, blocking=True,
) )
assert helper.characteristics[V2_ACTIVE].value == 1 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( await hass.services.async_call(
"fan", "fan",
@ -248,7 +275,7 @@ async def test_v2_turn_on(hass, utcnow):
blocking=True, blocking=True,
) )
assert helper.characteristics[V2_ACTIVE].value == 1 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): 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"}, {"entity_id": "fan.testdevice", "speed": "medium"},
blocking=True, blocking=True,
) )
assert helper.characteristics[V2_ROTATION_SPEED].value == 50 assert helper.characteristics[V2_ROTATION_SPEED].value == 66
await hass.services.async_call( await hass.services.async_call(
"fan", "fan",
@ -294,7 +321,7 @@ async def test_v2_set_speed(hass, utcnow):
{"entity_id": "fan.testdevice", "speed": "low"}, {"entity_id": "fan.testdevice", "speed": "low"},
blocking=True, blocking=True,
) )
assert helper.characteristics[V2_ROTATION_SPEED].value == 25 assert helper.characteristics[V2_ROTATION_SPEED].value == 33
await hass.services.async_call( await hass.services.async_call(
"fan", "fan",
@ -305,6 +332,29 @@ async def test_v2_set_speed(hass, utcnow):
assert helper.characteristics[V2_ACTIVE].value == 0 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): async def test_v2_speed_read(hass, utcnow):
"""Test that we can read a fans oscillation.""" """Test that we can read a fans oscillation."""
helper = await setup_test_component(hass, create_fanv2_service) 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 helper.characteristics[V2_ROTATION_SPEED].value = 100
state = await helper.poll_and_get_state() state = await helper.poll_and_get_state()
assert state.attributes["speed"] == "high" assert state.attributes["speed"] == "high"
assert state.attributes["percentage"] == 100
helper.characteristics[V2_ROTATION_SPEED].value = 50 helper.characteristics[V2_ROTATION_SPEED].value = 50
state = await helper.poll_and_get_state() state = await helper.poll_and_get_state()
assert state.attributes["speed"] == "medium" assert state.attributes["speed"] == "medium"
assert state.attributes["percentage"] == 50
helper.characteristics[V2_ROTATION_SPEED].value = 25 helper.characteristics[V2_ROTATION_SPEED].value = 25
state = await helper.poll_and_get_state() state = await helper.poll_and_get_state()
assert state.attributes["speed"] == "low" assert state.attributes["speed"] == "low"
assert state.attributes["percentage"] == 25
helper.characteristics[V2_ACTIVE].value = 0 helper.characteristics[V2_ACTIVE].value = 0
helper.characteristics[V2_ROTATION_SPEED].value = 0 helper.characteristics[V2_ROTATION_SPEED].value = 0
state = await helper.poll_and_get_state() state = await helper.poll_and_get_state()
assert state.attributes["speed"] == "off" assert state.attributes["speed"] == "off"
assert state.attributes["percentage"] == 0
async def test_v2_set_direction(hass, utcnow): async def test_v2_set_direction(hass, utcnow):