Skip to content

Commit

Permalink
Support modern fan API
Browse files Browse the repository at this point in the history
  • Loading branch information
jason0x43 committed Jul 12, 2022
1 parent a000712 commit 1ca6375
Showing 1 changed file with 83 additions and 16 deletions.
99 changes: 83 additions & 16 deletions custom_components/hubitat/fan.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,15 @@
CMD_ON,
CMD_SET_SPEED,
DEFAULT_FAN_SPEEDS,
STATE_LOW,
STATE_OFF,
STATE_ON,
Device,
)
from logging import getLogger
from math import modf
from typing import Any, Dict, List, Optional, Sequence

from homeassistant.components.fan import SUPPORT_SET_SPEED, FanEntity
from homeassistant.components.fan import FanEntity, FanEntityFeature
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant

Expand All @@ -32,6 +32,8 @@
ATTR_SPEED,
)

_speeds = {}


class HubitatFan(HubitatEntity, FanEntity):
"""Representation of a Hubitat fan."""
Expand All @@ -43,18 +45,59 @@ def device_attrs(self) -> Optional[Sequence[str]]:

@property
def is_on(self) -> bool:
"""Return true if the entity is on."""
if CAP_SWITCH in self._device.capabilities:
return self.get_str_attr(ATTR_SWITCH) == STATE_ON
return self.get_str_attr(ATTR_SPEED) != STATE_OFF

@property
def speed(self) -> Optional[str]:
"""Return the speed of this fan."""
return self.get_str_attr(ATTR_SPEED)
def percentage(self) -> Optional[int]:
"""Return the current speed as a percentage."""
speed = self.get_str_attr(ATTR_SPEED)
_LOGGER.debug("hubitat speed: %s", speed)
if speed is None or speed == "off":
_LOGGER.debug(" returning None")
return None
if speed == "auto":
_LOGGER.debug(" returning 100")
return 100
idx = self.speeds.index(speed)
_LOGGER.debug(
" index is %d, step is %f, pct is %f",
idx,
self.percentage_step,
round(self.percentage_step * (idx + 1)),
)
return round(self.percentage_step * (idx + 1))

@property
def preset_mode(self) -> Optional[str]:
"""Return the current preset mode"""
if self.get_str_attr(ATTR_SPEED) == "auto":
return "auto"
return None

@property
def speed_list(self) -> List[str]:
def preset_modes(self) -> Optional[List[str]]:
"""Return a list of available preset modes."""
if "auto" in self.speeds_and_modes:
return ["auto"]
return None

@property
def speed_count(self) -> int:
"""Return the number of speeds supported by this fan."""
# Hubitat speeds include 'on', 'off', and 'auto'
return len(self.speeds)

@property
def speeds(self) -> List[str]:
"""Return the list of speeds for this fan."""
return [s for s in self.speeds_and_modes if s not in ["auto", "on", "off"]]

@property
def speeds_and_modes(self) -> List[str]:
"""Return the list of speeds and modes for this fan."""
return self._device.attributes[ATTR_SPEED].values or DEFAULT_FAN_SPEEDS

@property
Expand All @@ -73,29 +116,53 @@ def old_unique_ids(self) -> List[str]:
@property
def supported_features(self) -> int:
"""Flag supported features."""
return SUPPORT_SET_SPEED

async def async_turn_on(self, speed: Optional[str] = None, **kwargs: Any) -> None:
return FanEntityFeature.SET_SPEED

async def async_turn_on(
self,
percentage: Optional[int] = None,
preset_mode: Optional[str] = None,
**kwargs: Any,
) -> None:
"""Turn on the switch."""
_LOGGER.debug("Turning on %s with speed [%s]", self.name, speed)
if speed is not None:
await self.async_set_speed(speed)
_LOGGER.debug(
"Turning on %s with percent [%s] or preset[ %s]",
self.name,
percentage,
preset_mode,
)
if preset_mode in self.speeds_and_modes:
await self.send_command(CMD_SET_SPEED, preset_mode)
elif percentage is not None:
await self.async_set_percentage(percentage)
elif CAP_SWITCH in self._device.capabilities:
await self.send_command(CMD_ON)
else:
await self.async_set_speed(STATE_LOW)
await self.send_command(CMD_SET_SPEED, STATE_ON)

async def async_turn_off(self) -> None:
"""Turn off the switch."""
_LOGGER.debug("Turning off %s", self.name)
if CAP_SWITCH in self._device.capabilities:
await self.send_command(CMD_OFF)
else:
await self.async_set_speed(STATE_OFF)
await self.send_command(CMD_SET_SPEED, STATE_OFF)

async def async_set_speed(self, speed: str) -> None:
async def async_set_percentage(self, percentage: int) -> None:
"""Set the speed of the fan."""
await self.send_command(CMD_SET_SPEED, speed)
_LOGGER.debug("setting percentage to %d", percentage)
if percentage == 0:
await self.send_command(CMD_SET_SPEED, STATE_OFF)
else:
step = self.percentage_step
[stepFrac, stepInt] = modf(percentage / step)
idx = int(stepInt)
if stepFrac >= 0.5:
idx += 1
if idx == 0:
await self.send_command(CMD_SET_SPEED, STATE_OFF)
else:
await self.send_command(CMD_SET_SPEED, self.speeds[idx - 1])


def is_fan(device: Device, overrides: Optional[Dict[str, str]] = None) -> bool:
Expand Down

0 comments on commit 1ca6375

Please sign in to comment.