Example #1
0
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
Example #3
0
    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,
            },
        )
Example #4
0
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
Example #5
0
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
Example #6
0
    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',
            )
Example #7
0
    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
Example #8
0
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())),
            })
Example #9
0
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