""" Support for Insteon fans via local hub control. For more details about this component, please refer to the documentation at https://home-assistant.io/components/fan.insteon_local/ """ import logging from datetime import timedelta from homeassistant.components.fan import ( ATTR_SPEED, SPEED_OFF, SPEED_LOW, SPEED_MEDIUM, SPEED_HIGH, SUPPORT_SET_SPEED, FanEntity) from homeassistant.helpers.entity import ToggleEntity import homeassistant.util as util from homeassistant.util.json import load_json, save_json _CONFIGURING = {} _LOGGER = logging.getLogger(__name__) DEPENDENCIES = ['insteon_local'] DOMAIN = 'fan' INSTEON_LOCAL_FANS_CONF = 'insteon_local_fans.conf' MIN_TIME_BETWEEN_FORCED_SCANS = timedelta(milliseconds=100) MIN_TIME_BETWEEN_SCANS = timedelta(seconds=5) SUPPORT_INSTEON_LOCAL = SUPPORT_SET_SPEED def setup_platform(hass, config, add_devices, discovery_info=None): """Set up the Insteon local fan platform.""" insteonhub = hass.data['insteon_local'] conf_fans = load_json(hass.config.path(INSTEON_LOCAL_FANS_CONF)) if conf_fans: for device_id in conf_fans: setup_fan(device_id, conf_fans[device_id], insteonhub, hass, add_devices) else: linked = insteonhub.get_linked() for device_id in linked: if (linked[device_id]['cat_type'] == 'dimmer' and linked[device_id]['sku'] == '2475F' and device_id not in conf_fans): request_configuration(device_id, insteonhub, linked[device_id]['model_name'] + ' ' + linked[device_id]['sku'], hass, add_devices) def request_configuration(device_id, insteonhub, model, hass, add_devices_callback): """Request configuration steps from the user.""" configurator = hass.components.configurator # We got an error if this method is called while we are configuring if device_id in _CONFIGURING: configurator.notify_errors( _CONFIGURING[device_id], 'Failed to register, please try again.') return def insteon_fan_config_callback(data): """The actions to do when our configuration callback is called.""" setup_fan(device_id, data.get('name'), insteonhub, hass, add_devices_callback) _CONFIGURING[device_id] = configurator.request_config( 'Insteon ' + model + ' addr: ' + device_id, insteon_fan_config_callback, description=('Enter a name for ' + model + ' Fan addr: ' + device_id), entity_picture='/static/images/config_insteon.png', submit_caption='Confirm', fields=[{'id': 'name', 'name': 'Name', 'type': ''}] ) def setup_fan(device_id, name, insteonhub, hass, add_devices_callback): """Set up the fan.""" if device_id in _CONFIGURING: request_id = _CONFIGURING.pop(device_id) configurator = hass.components.configurator configurator.request_done(request_id) _LOGGER.info("Device configuration done!") conf_fans = load_json(hass.config.path(INSTEON_LOCAL_FANS_CONF)) if device_id not in conf_fans: conf_fans[device_id] = name save_json(hass.config.path(INSTEON_LOCAL_FANS_CONF), conf_fans) device = insteonhub.fan(device_id) add_devices_callback([InsteonLocalFanDevice(device, name)]) class InsteonLocalFanDevice(FanEntity): """An abstract Class for an Insteon node.""" def __init__(self, node, name): """Initialize the device.""" self.node = node self.node.deviceName = name self._speed = SPEED_OFF @property def name(self): """Return the name of the node.""" return self.node.deviceName @property def unique_id(self): """Return the ID of this Insteon node.""" return 'insteon_local_{}_fan'.format(self.node.device_id) @property def speed(self) -> str: """Return the current speed.""" return self._speed @property def speed_list(self: ToggleEntity) -> list: """Get the list of available speeds.""" return [SPEED_OFF, SPEED_LOW, SPEED_MEDIUM, SPEED_HIGH] @util.Throttle(MIN_TIME_BETWEEN_SCANS, MIN_TIME_BETWEEN_FORCED_SCANS) def update(self): """Update state of the fan.""" resp = self.node.status() if 'cmd2' in resp: if resp['cmd2'] == '00': self._speed = SPEED_OFF elif resp['cmd2'] == '55': self._speed = SPEED_LOW elif resp['cmd2'] == 'AA': self._speed = SPEED_MEDIUM elif resp['cmd2'] == 'FF': self._speed = SPEED_HIGH @property def supported_features(self): """Flag supported features.""" return SUPPORT_INSTEON_LOCAL def turn_on(self: ToggleEntity, speed: str=None, **kwargs) -> None: """Turn device on.""" if speed is None: if ATTR_SPEED in kwargs: speed = kwargs[ATTR_SPEED] else: speed = SPEED_MEDIUM self.set_speed(speed) def turn_off(self: ToggleEntity, **kwargs) -> None: """Turn device off.""" self.node.off() def set_speed(self: ToggleEntity, speed: str) -> None: """Set the speed of the fan.""" if self.node.on(speed): self._speed = speed