Skip to content

Commit

Permalink
Add support for fan preset modes in HomeKit
Browse files Browse the repository at this point in the history
  • Loading branch information
bdraco committed Feb 20, 2021
1 parent e44da7c commit 9e26356
Showing 1 changed file with 43 additions and 0 deletions.
43 changes: 43 additions & 0 deletions homeassistant/components/homekit/type_fans.py
Expand Up @@ -8,12 +8,15 @@
ATTR_OSCILLATING,
ATTR_PERCENTAGE,
ATTR_PERCENTAGE_STEP,
ATTR_PRESET_MODE,
ATTR_PRESET_MODES,
DIRECTION_FORWARD,
DIRECTION_REVERSE,
DOMAIN,
SERVICE_OSCILLATE,
SERVICE_SET_DIRECTION,
SERVICE_SET_PERCENTAGE,
SERVICE_SET_PRESET_MODE,
SUPPORT_DIRECTION,
SUPPORT_OSCILLATE,
SUPPORT_SET_SPEED,
Expand All @@ -31,11 +34,14 @@
from .accessories import TYPES, HomeAccessory
from .const import (
CHAR_ACTIVE,
CHAR_NAME,
CHAR_ON,
CHAR_ROTATION_DIRECTION,
CHAR_ROTATION_SPEED,
CHAR_SWING_MODE,
PROP_MIN_STEP,
SERV_FANV2,
SERV_SWITCH,
)

_LOGGER = logging.getLogger(__name__)
Expand All @@ -56,6 +62,7 @@ def __init__(self, *args):

features = state.attributes.get(ATTR_SUPPORTED_FEATURES, 0)
percentage_step = state.attributes.get(ATTR_PERCENTAGE_STEP, 1)
preset_modes = state.attributes.get(ATTR_PRESET_MODES)

if features & SUPPORT_DIRECTION:
chars.append(CHAR_ROTATION_DIRECTION)
Expand All @@ -65,11 +72,13 @@ def __init__(self, *args):
chars.append(CHAR_ROTATION_SPEED)

serv_fan = self.add_preload_service(SERV_FANV2, chars)
self.set_primary_service(serv_fan)
self.char_active = serv_fan.configure_char(CHAR_ACTIVE, value=0)

self.char_direction = None
self.char_speed = None
self.char_swing = None
self.preset_mode_chars = {}

if CHAR_ROTATION_DIRECTION in chars:
self.char_direction = serv_fan.configure_char(
Expand All @@ -86,6 +95,22 @@ def __init__(self, *args):
properties={PROP_MIN_STEP: percentage_step},
)

if preset_modes:
for preset_mode in preset_modes:
preset_serv = self.add_preload_service(SERV_SWITCH, CHAR_NAME)
serv_fan.add_linked_service(preset_serv)
preset_serv.configure_char(
CHAR_NAME, value=f"{self.display_name} {preset_mode}"
)

self.preset_mode_chars[preset_mode] = preset_serv.configure_char(
CHAR_ON,
value=False,
setter_callback=lambda value, preset_mode=preset_mode: self.set_preset_mode(
value, preset_mode
),
)

if CHAR_SWING_MODE in chars:
self.char_swing = serv_fan.configure_char(CHAR_SWING_MODE, value=0)
self.async_update_state(state)
Expand Down Expand Up @@ -120,6 +145,18 @@ def _set_chars(self, char_values):
if CHAR_ROTATION_SPEED in char_values:
self.set_percentage(char_values[CHAR_ROTATION_SPEED])

def set_preset_mode(self, value, preset_mode):
"""Set preset_mode if call came from HomeKit."""
_LOGGER.debug(
"%s: Set preset_mode %s to %d", self.entity_id, preset_mode, value
)
params = {ATTR_ENTITY_ID: self.entity_id}
if value:
params[ATTR_PRESET_MODE] = preset_mode
self.async_call_service(DOMAIN, SERVICE_SET_PRESET_MODE, params)
else:
self.async_call_service(DOMAIN, SERVICE_TURN_ON, params)

def set_state(self, value):
"""Set state if call came from HomeKit."""
_LOGGER.debug("%s: Set state to %d", self.entity_id, value)
Expand Down Expand Up @@ -193,3 +230,9 @@ def async_update_state(self, new_state):
hk_oscillating = 1 if oscillating else 0
if self.char_swing.value != hk_oscillating:
self.char_swing.set_value(hk_oscillating)

current_preset_mode = new_state.attributes.get(ATTR_PRESET_MODE)
for preset_mode, char in self.preset_mode_chars.items():
hk_value = 1 if preset_mode == current_preset_mode else 0
if char.value != hk_value:
char.set_value(hk_value)

0 comments on commit 9e26356

Please sign in to comment.