""" Support for Velbus platform. For more details about this platform, please refer to the documentation at https://home-assistant.io/components/fan.velbus/ """ import asyncio import logging import voluptuous as vol from homeassistant.components.fan import ( SPEED_LOW, SPEED_MEDIUM, SPEED_HIGH, FanEntity, SUPPORT_SET_SPEED, PLATFORM_SCHEMA) from homeassistant.components.velbus import DOMAIN from homeassistant.const import CONF_NAME, CONF_DEVICES, STATE_OFF import homeassistant.helpers.config_validation as cv DEPENDENCIES = ['velbus'] _LOGGER = logging.getLogger(__name__) PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ vol.Required(CONF_DEVICES): vol.All(cv.ensure_list, [ { vol.Required('module'): cv.positive_int, vol.Required('channel_low'): cv.positive_int, vol.Required('channel_medium'): cv.positive_int, vol.Required('channel_high'): cv.positive_int, vol.Required(CONF_NAME): cv.string, } ]) }) def setup_platform(hass, config, add_devices, discovery_info=None): """Set up Fans.""" velbus = hass.data[DOMAIN] add_devices(VelbusFan(fan, velbus) for fan in config[CONF_DEVICES]) class VelbusFan(FanEntity): """Representation of a Velbus Fan.""" def __init__(self, fan, velbus): """Initialize a Velbus light.""" self._velbus = velbus self._name = fan[CONF_NAME] self._module = fan['module'] self._channel_low = fan['channel_low'] self._channel_medium = fan['channel_medium'] self._channel_high = fan['channel_high'] self._channels = [self._channel_low, self._channel_medium, self._channel_high] self._channels_state = [False, False, False] self._speed = STATE_OFF @asyncio.coroutine def async_added_to_hass(self): """Add listener for Velbus messages on bus.""" def _init_velbus(): """Initialize Velbus on startup.""" self._velbus.subscribe(self._on_message) self.get_status() yield from self.hass.async_add_job(_init_velbus) def _on_message(self, message): import velbus if isinstance(message, velbus.RelayStatusMessage) and \ message.address == self._module and \ message.channel in self._channels: if message.channel == self._channel_low: self._channels_state[0] = message.is_on() elif message.channel == self._channel_medium: self._channels_state[1] = message.is_on() elif message.channel == self._channel_high: self._channels_state[2] = message.is_on() self._calculate_speed() self.schedule_update_ha_state() def _calculate_speed(self): if self._is_off(): self._speed = STATE_OFF elif self._is_low(): self._speed = SPEED_LOW elif self._is_medium(): self._speed = SPEED_MEDIUM elif self._is_high(): self._speed = SPEED_HIGH def _is_off(self): return self._channels_state[0] is False and \ self._channels_state[1] is False and \ self._channels_state[2] is False def _is_low(self): return self._channels_state[0] is True and \ self._channels_state[1] is False and \ self._channels_state[2] is False def _is_medium(self): return self._channels_state[0] is True and \ self._channels_state[1] is True and \ self._channels_state[2] is False def _is_high(self): return self._channels_state[0] is True and \ self._channels_state[1] is False and \ self._channels_state[2] is True @property def name(self): """Return the display name of this light.""" return self._name @property def should_poll(self): """Disable polling.""" return False @property def speed(self): """Return the current speed.""" return self._speed @property def speed_list(self): """Get the list of available speeds.""" return [STATE_OFF, SPEED_LOW, SPEED_MEDIUM, SPEED_HIGH] def turn_on(self, speed, **kwargs): """Turn on the entity.""" if speed is None: speed = SPEED_MEDIUM self.set_speed(speed) def turn_off(self): """Turn off the entity.""" self.set_speed(STATE_OFF) def set_speed(self, speed): """Set the speed of the fan.""" channels_off = [] channels_on = [] if speed == STATE_OFF: channels_off = self._channels elif speed == SPEED_LOW: channels_off = [self._channel_medium, self._channel_high] channels_on = [self._channel_low] elif speed == SPEED_MEDIUM: channels_off = [self._channel_high] channels_on = [self._channel_low, self._channel_medium] elif speed == SPEED_HIGH: channels_off = [self._channel_medium] channels_on = [self._channel_low, self._channel_high] for channel in channels_off: self._relay_off(channel) for channel in channels_on: self._relay_on(channel) self.schedule_update_ha_state() def _relay_on(self, channel): import velbus message = velbus.SwitchRelayOnMessage() message.set_defaults(self._module) message.relay_channels = [channel] self._velbus.send(message) def _relay_off(self, channel): import velbus message = velbus.SwitchRelayOffMessage() message.set_defaults(self._module) message.relay_channels = [channel] self._velbus.send(message) def get_status(self): """Retrieve current status.""" import velbus message = velbus.ModuleStatusRequestMessage() message.set_defaults(self._module) message.channels = self._channels self._velbus.send(message) @property def supported_features(self): """Flag supported features.""" return SUPPORT_SET_SPEED