async def async_setup_entry(hass, entry): """Create a tellduslive session.""" from tellduslive import Session conf = entry.data[KEY_SESSION] if KEY_HOST in conf: session = Session(**conf) else: session = Session( PUBLIC_KEY, NOT_SO_PRIVATE_KEY, application=APPLICATION_NAME, **conf, ) if not session.is_authorized: _LOGGER.error('Authentication Error') return False hass.data[DATA_CONFIG_ENTRY_LOCK] = asyncio.Lock() hass.data[CONFIG_ENTRY_IS_SETUP] = set() client = TelldusLiveClient(hass, entry, session) hass.data[DOMAIN] = client await client.update() interval = timedelta(seconds=entry.data[KEY_SCAN_INTERVAL]) _LOGGER.debug('Update interval %s', interval) hass.data[INTERVAL_TRACKER] = async_track_time_interval( hass, client.update, interval) return True
def collect(self): def _new_metric(metric_desc: str, metric_name: str): metric = Metric('telldus_sensor_data', metric_desc, metric_name) return metric def _add_metric(metric: Metric, name: str, value: float, labels: Dict): metric.add_sample(name, value=value, labels=labels) """Dump configured devices and sensors.""" logging.basicConfig(level=logging.WARN) credentials = read_credentials() session = Session(**credentials) session.update() device_sensors = dict() sensor_metric = _new_metric('Sensor data fromm Telldus Live', 'histogram') # Iterate over all the device IDS. for device in session.device_ids: # Get the raw device info. sensor = Device(session, device) # Is it a device or a sensor? if not sensor.is_sensor: continue # It's a sensor lets continue raw_sensor = sensor.device # Grab some values we may want to use later on... s_id = raw_sensor.get('id', 'NO_ID') s_name = slugify(raw_sensor.get('name', 'NO_NAME'), separator='_') c_name = slugify(raw_sensor.get('clientName', 'NO_CLIENTNAME'), separator='_') # Iterate sensors and create a metric for each. if raw_sensor.get('data', False): data = raw_sensor.get('data') for measurement in data: m_name = measurement['name'] metric_name = 'telldus_sensor' _add_metric(sensor_metric, metric_name, float(measurement['value']), labels={ 'client_name': c_name, 'sensor_name': s_name, 'metric_name': m_name, 'sensor_scale': measurement['scale'] }) yield sensor_metric
async def async_step_auth(self, user_input=None): """Handle the submitted configuration.""" if not self._session: from tellduslive import Session self._session = Session( public_key=PUBLIC_KEY, private_key=NOT_SO_PRIVATE_KEY, host=self._host, application=APPLICATION_NAME, ) if user_input is not None and self._session.authorize(): host = self._host or CLOUD_NAME if self._host: session = { KEY_HOST: host, KEY_TOKEN: self._session.access_token } else: session = { KEY_TOKEN: self._session.access_token, KEY_TOKEN_SECRET: self._session.access_token_secret } return self.async_create_entry( title=host, data={ KEY_HOST: host, KEY_SCAN_INTERVAL: self._scan_interval.seconds, KEY_SESSION: session, }) try: with async_timeout.timeout(10): auth_url = await self.hass.async_add_executor_job( self._get_auth_url) except asyncio.TimeoutError: return self.async_abort(reason='authorize_url_timeout') except Exception: # pylint: disable=broad-except _LOGGER.exception("Unexpected error generating auth url") return self.async_abort(reason='authorize_url_fail') _LOGGER.debug('Got authorization URL %s', auth_url) return self.async_show_form( step_id='auth', description_placeholders={ 'app_name': APPLICATION_NAME, 'auth_url': auth_url, }, )
async def async_setup_entry(hass, entry): """Create a tellduslive session.""" conf = entry.data[KEY_SESSION] if CONF_HOST in conf: # Session(**conf) does blocking IO when # communicating with local devices. session = await hass.async_add_executor_job(partial(Session, **conf)) else: session = Session(PUBLIC_KEY, NOT_SO_PRIVATE_KEY, application=APPLICATION_NAME, **conf) if not session.is_authorized: _LOGGER.error("Authentication Error") return False hass.data[DATA_CONFIG_ENTRY_LOCK] = asyncio.Lock() hass.data[CONFIG_ENTRY_IS_SETUP] = set() hass.data[NEW_CLIENT_TASK] = hass.loop.create_task( async_new_client(hass, session, entry)) return True
async def async_setup_entry(hass, entry): """Create a tellduslive session.""" from tellduslive import Session conf = entry.data[KEY_SESSION] if KEY_HOST in conf: # Session(**conf) does blocking IO when # communicating with local devices. session = await hass.async_add_executor_job(partial(Session, **conf)) else: session = Session( PUBLIC_KEY, NOT_SO_PRIVATE_KEY, application=APPLICATION_NAME, **conf, ) if not session.is_authorized: _LOGGER.error('Authentication Error') return False hass.data[DATA_CONFIG_ENTRY_LOCK] = asyncio.Lock() hass.data[CONFIG_ENTRY_IS_SETUP] = set() client = TelldusLiveClient(hass, entry, session) hass.data[DOMAIN] = client await async_add_hubs(hass, client, entry.entry_id) hass.async_create_task(client.update()) interval = timedelta(seconds=entry.data[KEY_SCAN_INTERVAL]) _LOGGER.debug('Update interval %s', interval) hass.data[INTERVAL_TRACKER] = async_track_time_interval( hass, client.update, interval) return True
def request_configuration(host=None): """Request TelldusLive authorization.""" configurator = hass.components.configurator hass.data.setdefault(KEY_CONFIG, {}) data_key = host or DOMAIN # Configuration already in progress if hass.data[KEY_CONFIG].get(data_key): return _LOGGER.info('Configuring TelldusLive %s', 'local client: {}'.format(host) if host else 'cloud service') session = Session(public_key=PUBLIC_KEY, private_key=NOT_SO_PRIVATE_KEY, host=host, application=APPLICATION_NAME) auth_url = session.authorize_url if not auth_url: _LOGGER.warning('Failed to retrieve authorization URL') return _LOGGER.debug('Got authorization URL %s', auth_url) def configuration_callback(callback_data): """Handle the submitted configuration.""" session.authorize() res = setup(hass, config, session) if not res: configurator.notify_errors( hass.data[KEY_CONFIG].get(data_key), 'Unable to connect.') return conf.update( {host: {CONF_HOST: host, CONF_TOKEN: session.access_token}} if host else {DOMAIN: {CONF_TOKEN: session.access_token, CONF_TOKEN_SECRET: session.access_token_secret}}) save_json(config_filename, conf) # Close all open configurators: for now, we only support one # tellstick device, and configuration via either cloud service # or via local API, not both at the same time for instance in hass.data[KEY_CONFIG].values(): configurator.request_done(instance) hass.data[KEY_CONFIG][data_key] = \ configurator.request_config( 'TelldusLive ({})'.format( 'LocalAPI' if host else 'Cloud service'), configuration_callback, description=CONFIG_INSTRUCTIONS.format( app_name=APPLICATION_NAME, auth_url=auth_url), submit_caption='Confirm', entity_picture='/static/images/logo_tellduslive.png', )
def _get_auth_url(self): self._session = Session( public_key=PUBLIC_KEY, private_key=NOT_SO_PRIVATE_KEY, host=self._host, application=APPLICATION_NAME, ) return self._session.authorize_url
class FlowHandler(config_entries.ConfigFlow): """Handle a config flow.""" VERSION = 1 CONNECTION_CLASS = config_entries.CONN_CLASS_LOCAL_POLL def __init__(self): """Init config flow.""" self._hosts = [CLOUD_NAME] self._host = None self._session = None self._scan_interval = SCAN_INTERVAL def _get_auth_url(self): return self._session.authorize_url async def async_step_user(self, user_input=None): """Let user select host or cloud.""" if self.hass.config_entries.async_entries(DOMAIN): return self.async_abort(reason='already_setup') if user_input is not None or len(self._hosts) == 1: if user_input is not None and user_input[KEY_HOST] != CLOUD_NAME: self._host = user_input[KEY_HOST] return await self.async_step_auth() return self.async_show_form( step_id='user', data_schema=vol.Schema({ vol.Required(KEY_HOST): vol.In(list(self._hosts)) })) async def async_step_auth(self, user_input=None): """Handle the submitted configuration.""" if not self._session: from tellduslive import Session self._session = Session( public_key=PUBLIC_KEY, private_key=NOT_SO_PRIVATE_KEY, host=self._host, application=APPLICATION_NAME, ) if user_input is not None and self._session.authorize(): host = self._host or CLOUD_NAME if self._host: session = { KEY_HOST: host, KEY_TOKEN: self._session.access_token } else: session = { KEY_TOKEN: self._session.access_token, KEY_TOKEN_SECRET: self._session.access_token_secret } return self.async_create_entry( title=host, data={ KEY_HOST: host, KEY_SCAN_INTERVAL: self._scan_interval.seconds, KEY_SESSION: session, }) try: with async_timeout.timeout(10): auth_url = await self.hass.async_add_executor_job( self._get_auth_url) except asyncio.TimeoutError: return self.async_abort(reason='authorize_url_timeout') except Exception: # pylint: disable=broad-except _LOGGER.exception("Unexpected error generating auth url") return self.async_abort(reason='authorize_url_fail') _LOGGER.debug('Got authorization URL %s', auth_url) return self.async_show_form( step_id='auth', description_placeholders={ 'app_name': APPLICATION_NAME, 'auth_url': auth_url, }, ) async def async_step_discovery(self, user_input): """Run when a Tellstick is discovered.""" from tellduslive import supports_local_api _LOGGER.info('Discovered tellstick device: %s', user_input) # Ignore any known devices for entry in self._async_current_entries(): if entry.data[KEY_HOST] == user_input[0]: return self.async_abort(reason='already_configured') if not supports_local_api(user_input[1]): _LOGGER.debug('Tellstick does not support local API') # Configure the cloud service return await self.async_step_auth() self._hosts.append(user_input[0]) return await self.async_step_user() async def async_step_import(self, user_input): """Import a config entry.""" if self.hass.config_entries.async_entries(DOMAIN): return self.async_abort(reason='already_setup') self._scan_interval = user_input[KEY_SCAN_INTERVAL] if user_input[KEY_HOST] != DOMAIN: self._hosts.append(user_input[KEY_HOST]) if not await self.hass.async_add_executor_job( os.path.isfile, self.hass.config.path(TELLDUS_CONFIG_FILE)): return await self.async_step_user() conf = await self.hass.async_add_executor_job( load_json, self.hass.config.path(TELLDUS_CONFIG_FILE)) host = next(iter(conf)) if user_input[KEY_HOST] != host: return await self.async_step_user() host = CLOUD_NAME if host == 'tellduslive' else host return self.async_create_entry( title=host, data={ KEY_HOST: host, KEY_SCAN_INTERVAL: self._scan_interval.seconds, KEY_SESSION: next(iter(conf.values())), })
def setup(hass, config, session=None): """Set up the Telldus Live component.""" from tellduslive import Session, supports_local_api config_filename = hass.config.path(TELLLDUS_CONFIG_FILE) conf = load_json(config_filename) def request_configuration(host=None): """Request TelldusLive authorization.""" configurator = hass.components.configurator hass.data.setdefault(KEY_CONFIG, {}) data_key = host or DOMAIN # Configuration already in progress if hass.data[KEY_CONFIG].get(data_key): return _LOGGER.info('Configuring TelldusLive %s', 'local client: {}'.format(host) if host else 'cloud service') session = Session(public_key=PUBLIC_KEY, private_key=NOT_SO_PRIVATE_KEY, host=host, application=APPLICATION_NAME) auth_url = session.authorize_url if not auth_url: _LOGGER.warning('Failed to retrieve authorization URL') return _LOGGER.debug('Got authorization URL %s', auth_url) def configuration_callback(callback_data): """Handle the submitted configuration.""" session.authorize() res = setup(hass, config, session) if not res: configurator.notify_errors( hass.data[KEY_CONFIG].get(data_key), 'Unable to connect.') return conf.update( {host: {CONF_HOST: host, CONF_TOKEN: session.access_token}} if host else {DOMAIN: {CONF_TOKEN: session.access_token, CONF_TOKEN_SECRET: session.access_token_secret}}) save_json(config_filename, conf) # Close all open configurators: for now, we only support one # tellstick device, and configuration via either cloud service # or via local API, not both at the same time for instance in hass.data[KEY_CONFIG].values(): configurator.request_done(instance) hass.data[KEY_CONFIG][data_key] = \ configurator.request_config( 'TelldusLive ({})'.format( 'LocalAPI' if host else 'Cloud service'), configuration_callback, description=CONFIG_INSTRUCTIONS.format( app_name=APPLICATION_NAME, auth_url=auth_url), submit_caption='Confirm', entity_picture='/static/images/logo_tellduslive.png', ) def tellstick_discovered(service, info): """Run when a Tellstick is discovered.""" _LOGGER.info('Discovered tellstick device') if DOMAIN in hass.data: _LOGGER.debug('Tellstick already configured') return host, device = info[:2] if not supports_local_api(device): _LOGGER.debug('Tellstick does not support local API') # Configure the cloud service hass.async_add_job(request_configuration) return _LOGGER.debug('Tellstick does support local API') # Ignore any known devices if conf and host in conf: _LOGGER.debug('Discovered already known device: %s', host) return # Offer configuration of both live and local API request_configuration() request_configuration(host) discovery.listen(hass, SERVICE_TELLDUSLIVE, tellstick_discovered) if session: _LOGGER.debug('Continuing setup configured by configurator') elif conf and CONF_HOST in next(iter(conf.values())): # For now, only one local device is supported _LOGGER.debug('Using Local API pre-configured by configurator') session = Session(**next(iter(conf.values()))) elif DOMAIN in conf: _LOGGER.debug('Using TelldusLive cloud service ' 'pre-configured by configurator') session = Session(PUBLIC_KEY, NOT_SO_PRIVATE_KEY, application=APPLICATION_NAME, **conf[DOMAIN]) elif config.get(DOMAIN): _LOGGER.info('Found entry in configuration.yaml. ' 'Requesting TelldusLive cloud service configuration') request_configuration() if CONF_HOST in config.get(DOMAIN, {}): _LOGGER.info('Found TelldusLive host entry in configuration.yaml. ' 'Requesting Telldus Local API configuration') request_configuration(config.get(DOMAIN).get(CONF_HOST)) return True else: _LOGGER.info('Tellstick discovered, awaiting discovery callback') return True if not session.is_authorized: _LOGGER.error( 'Authentication Error') return False client = TelldusLiveClient(hass, config, session) hass.data[DOMAIN] = client if session: client.update() else: hass.bus.listen(EVENT_HOMEASSISTANT_START, client.update) return True