""" Support for Ikea Tradfri. For more details about this component, please refer to the documentation at https://home-assistant.io/components/ikea_tradfri/ """ import asyncio import logging import voluptuous as vol import homeassistant.helpers.config_validation as cv from homeassistant.helpers import discovery from homeassistant.const import CONF_HOST from homeassistant.components.discovery import SERVICE_IKEA_TRADFRI from homeassistant.util.json import load_json, save_json REQUIREMENTS = ['pytradfri==4.0.1', 'DTLSSocket==0.1.4', 'https://github.com/chrysn/aiocoap/archive/' '3286f48f0b949901c8b5c04c0719dc54ab63d431.zip' '#aiocoap==0.3'] DOMAIN = 'tradfri' GATEWAY_IDENTITY = 'homeassistant' CONFIG_FILE = '.tradfri_psk.conf' KEY_CONFIG = 'tradfri_configuring' KEY_GATEWAY = 'tradfri_gateway' KEY_API = 'tradfri_api' KEY_TRADFRI_GROUPS = 'tradfri_allow_tradfri_groups' CONF_ALLOW_TRADFRI_GROUPS = 'allow_tradfri_groups' DEFAULT_ALLOW_TRADFRI_GROUPS = True CONFIG_SCHEMA = vol.Schema({ DOMAIN: vol.Schema({ vol.Inclusive(CONF_HOST, 'gateway'): cv.string, vol.Optional(CONF_ALLOW_TRADFRI_GROUPS, default=DEFAULT_ALLOW_TRADFRI_GROUPS): cv.boolean, }) }, extra=vol.ALLOW_EXTRA) _LOGGER = logging.getLogger(__name__) def request_configuration(hass, config, host): """Request configuration steps from the user.""" configurator = hass.components.configurator hass.data.setdefault(KEY_CONFIG, {}) instance = hass.data[KEY_CONFIG].get(host) # Configuration already in progress if instance: return @asyncio.coroutine def configuration_callback(callback_data): """Handle the submitted configuration.""" try: from pytradfri.api.aiocoap_api import APIFactory from pytradfri import RequestError from uuid import uuid4 except ImportError: _LOGGER.exception("Looks like something isn't installed!") return identity = uuid4().hex security_code = callback_data.get('security_code') api_factory = APIFactory(host, psk_id=identity, loop=hass.loop) # Need To Fix: currently entering a wrong security code sends # pytradfri aiocoap API into an endless loop. # Should just raise a requestError or something. try: key = yield from api_factory.generate_psk(security_code) except RequestError: hass.async_add_job(configurator.notify_errors, instance, "Security Code not accepted.") return res = yield from _setup_gateway(hass, config, host, identity, key, DEFAULT_ALLOW_TRADFRI_GROUPS) if not res: hass.async_add_job(configurator.notify_errors, instance, "Unable to connect.") return def success(): """Set up was successful.""" conf = load_json(hass.config.path(CONFIG_FILE)) conf[host] = {'identity': identity, 'key': key} save_json(hass.config.path(CONFIG_FILE), conf) hass.async_add_job(configurator.request_done, instance) hass.async_add_job(success) instance = configurator.request_config( "IKEA Trådfri", configuration_callback, description='Please enter the security code written at the bottom of ' 'your IKEA Trådfri Gateway.', submit_caption="Confirm", fields=[{'id': 'security_code', 'name': 'Security Code', 'type': 'password'}] ) @asyncio.coroutine def async_setup(hass, config): """Set up the Tradfri component.""" conf = config.get(DOMAIN, {}) host = conf.get(CONF_HOST) allow_tradfri_groups = conf.get(CONF_ALLOW_TRADFRI_GROUPS) known_hosts = yield from hass.async_add_job(load_json, hass.config.path(CONFIG_FILE)) @asyncio.coroutine def gateway_discovered(service, info, allow_tradfri_groups=DEFAULT_ALLOW_TRADFRI_GROUPS): """Run when a gateway is discovered.""" host = info['host'] if host in known_hosts: # use fallbacks for old config style # identity was hard coded as 'homeassistant' identity = known_hosts[host].get('identity', 'homeassistant') key = known_hosts[host].get('key') yield from _setup_gateway(hass, config, host, identity, key, allow_tradfri_groups) else: hass.async_add_job(request_configuration, hass, config, host) discovery.async_listen(hass, SERVICE_IKEA_TRADFRI, gateway_discovered) if host: yield from gateway_discovered(None, {'host': host}, allow_tradfri_groups) return True @asyncio.coroutine def _setup_gateway(hass, hass_config, host, identity, key, allow_tradfri_groups): """Create a gateway.""" from pytradfri import Gateway, RequestError try: from pytradfri.api.aiocoap_api import APIFactory except ImportError: _LOGGER.exception("Looks like something isn't installed!") return False try: factory = APIFactory(host, psk_id=identity, psk=key, loop=hass.loop) api = factory.request gateway = Gateway() gateway_info_result = yield from api(gateway.get_gateway_info()) except RequestError: _LOGGER.exception("Tradfri setup failed.") return False gateway_id = gateway_info_result.id hass.data.setdefault(KEY_API, {}) hass.data.setdefault(KEY_GATEWAY, {}) gateways = hass.data[KEY_GATEWAY] hass.data[KEY_API][gateway_id] = api hass.data.setdefault(KEY_TRADFRI_GROUPS, {}) tradfri_groups = hass.data[KEY_TRADFRI_GROUPS] tradfri_groups[gateway_id] = allow_tradfri_groups # Check if already set up if gateway_id in gateways: return True gateways[gateway_id] = gateway hass.async_add_job(discovery.async_load_platform( hass, 'light', DOMAIN, {'gateway': gateway_id}, hass_config)) hass.async_add_job(discovery.async_load_platform( hass, 'sensor', DOMAIN, {'gateway': gateway_id}, hass_config)) return True