"""Support for Supla devices.""" import logging from typing import Optional import voluptuous as vol from homeassistant.const import CONF_ACCESS_TOKEN import homeassistant.helpers.config_validation as cv from homeassistant.helpers.discovery import load_platform from homeassistant.helpers.entity import Entity REQUIREMENTS = ['pysupla==0.0.3'] _LOGGER = logging.getLogger(__name__) DOMAIN = 'supla' CONF_SERVER = 'server' CONF_SERVERS = 'servers' SUPLA_FUNCTION_HA_CMP_MAP = { 'CONTROLLINGTHEROLLERSHUTTER': 'cover' } SUPLA_CHANNELS = 'supla_channels' SUPLA_SERVERS = 'supla_servers' SERVER_CONFIG = vol.Schema({ vol.Required(CONF_SERVER): cv.string, vol.Required(CONF_ACCESS_TOKEN): cv.string }) CONFIG_SCHEMA = vol.Schema({ DOMAIN: vol.Schema({ vol.Required(CONF_SERVERS): vol.All(cv.ensure_list, [SERVER_CONFIG]) }) }, extra=vol.ALLOW_EXTRA) def setup(hass, base_config): """Set up the Supla component.""" from pysupla import SuplaAPI server_confs = base_config[DOMAIN][CONF_SERVERS] hass.data[SUPLA_SERVERS] = {} hass.data[SUPLA_CHANNELS] = {} for server_conf in server_confs: server_address = server_conf[CONF_SERVER] server = SuplaAPI( server_address, server_conf[CONF_ACCESS_TOKEN] ) # Test connection try: srv_info = server.get_server_info() if srv_info.get('authenticated'): hass.data[SUPLA_SERVERS][server_conf[CONF_SERVER]] = server else: _LOGGER.error( 'Server: %s not configured. API call returned: %s', server_address, srv_info ) return False except IOError: _LOGGER.exception( 'Server: %s not configured. Error on Supla API access: ', server_address ) return False discover_devices(hass, base_config) return True def discover_devices(hass, hass_config): """ Run periodically to discover new devices. Currently it's only run at startup. """ component_configs = {} for server_name, server in hass.data[SUPLA_SERVERS].items(): for channel in server.get_channels(include=['iodevice']): channel_function = channel['function']['name'] component_name = SUPLA_FUNCTION_HA_CMP_MAP.get(channel_function) if component_name is None: _LOGGER.warning( 'Unsupported function: %s, channel id: %s', channel_function, channel['id'] ) continue channel['server_name'] = server_name component_configs.setdefault(component_name, []).append(channel) # Load discovered devices for component_name, channel in component_configs.items(): load_platform( hass, component_name, 'supla', channel, hass_config ) class SuplaChannel(Entity): """Base class of a Supla Channel (an equivalent of HA's Entity).""" def __init__(self, channel_data): """Channel data -- raw channel information from PySupla.""" self.server_name = channel_data['server_name'] self.channel_data = channel_data @property def server(self): """Return PySupla's server component associated with entity.""" return self.hass.data[SUPLA_SERVERS][self.server_name] @property def unique_id(self) -> str: """Return a unique ID.""" return 'supla-{}-{}'.format( self.channel_data['iodevice']['gUIDString'].lower(), self.channel_data['channelNumber'] ) @property def name(self) -> Optional[str]: """Return the name of the device.""" return self.channel_data['caption'] def action(self, action, **add_pars): """ Run server action. Actions are currently hardcoded in components. Supla's API enables autodiscovery """ _LOGGER.debug( 'Executing action %s on channel %d, params: %s', action, self.channel_data['id'], add_pars ) self.server.execute_action(self.channel_data['id'], action, **add_pars) def update(self): """Call to update state.""" self.channel_data = self.server.get_channel( self.channel_data['id'], include=['connected', 'state'] )