Skip to content
3 changes: 1 addition & 2 deletions homeassistant/components/comfoconnect/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,6 @@ class ComfoConnectBridge:

def __init__(self, hass, bridge, name, token, friendly_name, pin):
"""Initialize the ComfoConnect bridge."""
self.data = {}
self.name = name
self.hass = hass
self.unique_id = bridge.uuid.hex()
Expand All @@ -117,5 +116,5 @@ def sensor_callback(self, var, value):
"""Notify listeners that we have received an update."""
_LOGGER.debug("Received update for %s: %s", var, value)
dispatcher_send(
self.hass, SIGNAL_COMFOCONNECT_UPDATE_RECEIVED.format(var), value
self.hass, SIGNAL_COMFOCONNECT_UPDATE_RECEIVED.format(var), var, value
)
104 changes: 82 additions & 22 deletions homeassistant/components/comfoconnect/fan.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,24 @@

import logging
import math
from typing import Any

from pycomfoconnect import (
CMD_FAN_MODE_AWAY,
CMD_FAN_MODE_HIGH,
CMD_FAN_MODE_LOW,
CMD_FAN_MODE_MEDIUM,
CMD_MODE_AUTO,
CMD_MODE_MANUAL,
SENSOR_FAN_SPEED_MODE,
SENSOR_OPERATING_MODE,
)

from homeassistant.components.fan import SUPPORT_SET_SPEED, FanEntity
from homeassistant.components.fan import (
SUPPORT_PRESET_MODE,
SUPPORT_SET_SPEED,
FanEntity,
)
from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.util.percentage import (
int_states_in_range,
Expand All @@ -33,23 +41,33 @@

SPEED_RANGE = (1, 3) # away is not included in speeds and instead mapped to off

PRESET_MODE_AUTO = "auto"
PRESET_MODE_MANUAL = "manual"

PRESET_MODES = [
PRESET_MODE_AUTO,
PRESET_MODE_MANUAL,
]


def setup_platform(hass, config, add_entities, discovery_info=None):
"""Set up the ComfoConnect fan platform."""
ccb = hass.data[DOMAIN]

add_entities([ComfoConnectFan(ccb.name, ccb)], True)
add_entities([ComfoConnectFan(ccb)], True)


class ComfoConnectFan(FanEntity):
"""Representation of the ComfoConnect fan platform."""

def __init__(self, name, ccb: ComfoConnectBridge) -> None:
current_speed = None
current_mode = None

def __init__(self, ccb: ComfoConnectBridge) -> None:
"""Initialize the ComfoConnect fan."""
self._ccb = ccb
self._name = name

async def async_added_to_hass(self):
async def async_added_to_hass(self) -> None:
"""Register for sensor updates."""
_LOGGER.debug("Registering for fan speed")
self.async_on_remove(
Expand All @@ -62,14 +80,27 @@ async def async_added_to_hass(self):
await self.hass.async_add_executor_job(
self._ccb.comfoconnect.register_sensor, SENSOR_FAN_SPEED_MODE
)
_LOGGER.debug("Registering for operating mode")
self.async_on_remove(
async_dispatcher_connect(
self.hass,
SIGNAL_COMFOCONNECT_UPDATE_RECEIVED.format(SENSOR_OPERATING_MODE),
self._handle_update,
)
)
await self.hass.async_add_executor_job(
self._ccb.comfoconnect.register_sensor, SENSOR_OPERATING_MODE
)

def _handle_update(self, value):
def _handle_update(self, var, value):
"""Handle update callbacks."""
_LOGGER.debug(
"Handle update for fan speed (%d): %s", SENSOR_FAN_SPEED_MODE, value
)
self._ccb.data[SENSOR_FAN_SPEED_MODE] = value
self.schedule_update_ha_state()
_LOGGER.debug("Handle update for fan: %s = %s", var, value)
if var == SENSOR_FAN_SPEED_MODE:
self.current_speed = value
self.schedule_update_ha_state()
elif var == SENSOR_OPERATING_MODE:
self.current_mode = PRESET_MODE_AUTO if value == -1 else PRESET_MODE_MANUAL
self.schedule_update_ha_state()

@property
def should_poll(self) -> bool:
Expand All @@ -84,7 +115,7 @@ def unique_id(self):
@property
def name(self):
"""Return the name of the fan."""
return self._name
return self._ccb.name

@property
def icon(self):
Expand All @@ -94,32 +125,64 @@ def icon(self):
@property
def supported_features(self) -> int:
"""Flag supported features."""
return SUPPORT_SET_SPEED
return SUPPORT_SET_SPEED | SUPPORT_PRESET_MODE

@property
def speed(self) -> str | None:
"""Return the current speed."""
percentage = self.percentage
if percentage is None:
return None
return self.percentage_to_speed(percentage)

@property
def preset_modes(self):
"""Return the available preset modes."""
return PRESET_MODES

@property
def preset_mode(self):
"""Return the current mode."""
return self.current_mode

def set_preset_mode(self, preset_mode: str) -> None:
"""Set a preset mode on the fan."""
if preset_mode not in self.preset_modes:
raise ValueError(f"Invalid preset mode: {preset_mode}")

if preset_mode == PRESET_MODE_AUTO:
self._ccb.comfoconnect.cmd_rmi_request(CMD_MODE_AUTO)
elif preset_mode == PRESET_MODE_MANUAL:
self._ccb.comfoconnect.cmd_rmi_request(CMD_MODE_MANUAL)
self.schedule_update_ha_state()

@property
def percentage(self) -> int | None:
"""Return the current speed percentage."""
speed = self._ccb.data.get(SENSOR_FAN_SPEED_MODE)
if speed is None:
if self.current_speed is None:
return None
return ranged_value_to_percentage(SPEED_RANGE, speed)
return ranged_value_to_percentage(SPEED_RANGE, self.current_speed)

@property
def speed_count(self) -> int:
"""Return the number of speeds the fan supports."""
return int_states_in_range(SPEED_RANGE)

def turn_on(
self, speed: str = None, percentage=None, preset_mode=None, **kwargs
self,
speed: str | None = None,
percentage: int | None = None,
preset_mode: str | None = None,
**kwargs,
) -> None:
"""Turn on the fan."""
self.set_percentage(percentage)

def turn_off(self, **kwargs) -> None:
def turn_off(self, **kwargs: Any) -> None:
"""Turn off the fan (to away)."""
self.set_percentage(0)

def set_percentage(self, percentage: int):
def set_percentage(self, percentage: int | None) -> None:
"""Set fan speed percentage."""
_LOGGER.debug("Changing fan speed percentage to %s", percentage)

Expand All @@ -132,6 +195,3 @@ def set_percentage(self, percentage: int):
cmd = CMD_MAPPING[speed]

self._ccb.comfoconnect.cmd_rmi_request(cmd)

# Update current mode
self.schedule_update_ha_state()
Loading