Tradfri unique identities (#10414)
* Unique identity Use unique ID for generating keys and store them in config. Fallback to old id so existing installs will still work. * Remove Timeouts they don't really work. this should be fixed in pytradfri I think. * import uuid only when necessary * more selective import * lint * use load_json and save_json from util.json * remove unnecessary imports * use async configurator functions * async configurator calls * thou shalt not mixup the (a)syncs * again: no asyncs in the syncs! last warning... * Update tradfri.py
This commit is contained in:
parent
8111e3944c
commit
1e493dcb8a
1 changed files with 45 additions and 47 deletions
|
@ -5,9 +5,8 @@ For more details about this component, please refer to the documentation at
|
||||||
https://home-assistant.io/components/ikea_tradfri/
|
https://home-assistant.io/components/ikea_tradfri/
|
||||||
"""
|
"""
|
||||||
import asyncio
|
import asyncio
|
||||||
import json
|
|
||||||
import logging
|
import logging
|
||||||
import os
|
from uuid import uuid4
|
||||||
|
|
||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
|
|
||||||
|
@ -15,6 +14,7 @@ import homeassistant.helpers.config_validation as cv
|
||||||
from homeassistant.helpers import discovery
|
from homeassistant.helpers import discovery
|
||||||
from homeassistant.const import CONF_HOST
|
from homeassistant.const import CONF_HOST
|
||||||
from homeassistant.components.discovery import SERVICE_IKEA_TRADFRI
|
from homeassistant.components.discovery import SERVICE_IKEA_TRADFRI
|
||||||
|
from homeassistant.util.json import load_json, save_json
|
||||||
|
|
||||||
REQUIREMENTS = ['pytradfri==4.0.1',
|
REQUIREMENTS = ['pytradfri==4.0.1',
|
||||||
'DTLSSocket==0.1.4',
|
'DTLSSocket==0.1.4',
|
||||||
|
@ -58,26 +58,40 @@ def request_configuration(hass, config, host):
|
||||||
"""Handle the submitted configuration."""
|
"""Handle the submitted configuration."""
|
||||||
try:
|
try:
|
||||||
from pytradfri.api.aiocoap_api import APIFactory
|
from pytradfri.api.aiocoap_api import APIFactory
|
||||||
|
from pytradfri import RequestError
|
||||||
except ImportError:
|
except ImportError:
|
||||||
_LOGGER.exception("Looks like something isn't installed!")
|
_LOGGER.exception("Looks like something isn't installed!")
|
||||||
return
|
return
|
||||||
|
|
||||||
api_factory = APIFactory(host, psk_id=GATEWAY_IDENTITY)
|
identity = uuid4().hex
|
||||||
psk = yield from api_factory.generate_psk(callback_data.get('key'))
|
security_code = callback_data.get('security_code')
|
||||||
res = yield from _setup_gateway(hass, config, host, psk,
|
|
||||||
|
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:
|
||||||
|
configurator.async_notify_errors(hass, instance,
|
||||||
|
"Security Code not accepted.")
|
||||||
|
return
|
||||||
|
|
||||||
|
res = yield from _setup_gateway(hass, config, host, identity, key,
|
||||||
DEFAULT_ALLOW_TRADFRI_GROUPS)
|
DEFAULT_ALLOW_TRADFRI_GROUPS)
|
||||||
|
|
||||||
if not res:
|
if not res:
|
||||||
hass.async_add_job(configurator.notify_errors, instance,
|
configurator.async_notify_errors(hass, instance,
|
||||||
"Unable to connect.")
|
"Unable to connect.")
|
||||||
return
|
return
|
||||||
|
|
||||||
def success():
|
def success():
|
||||||
"""Set up was successful."""
|
"""Set up was successful."""
|
||||||
conf = _read_config(hass)
|
conf = load_json(hass.config.path(CONFIG_FILE))
|
||||||
conf[host] = {'key': psk}
|
conf[host] = {'identity': identity,
|
||||||
_write_config(hass, conf)
|
'key': key}
|
||||||
hass.async_add_job(configurator.request_done, instance)
|
save_json(hass.config.path(CONFIG_FILE), conf)
|
||||||
|
configurator.request_done(instance)
|
||||||
|
|
||||||
hass.async_add_job(success)
|
hass.async_add_job(success)
|
||||||
|
|
||||||
|
@ -86,7 +100,8 @@ def request_configuration(hass, config, host):
|
||||||
description='Please enter the security code written at the bottom of '
|
description='Please enter the security code written at the bottom of '
|
||||||
'your IKEA Trådfri Gateway.',
|
'your IKEA Trådfri Gateway.',
|
||||||
submit_caption="Confirm",
|
submit_caption="Confirm",
|
||||||
fields=[{'id': 'key', 'name': 'Security Code', 'type': 'password'}]
|
fields=[{'id': 'security_code', 'name': 'Security Code',
|
||||||
|
'type': 'password'}]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -96,35 +111,37 @@ def async_setup(hass, config):
|
||||||
conf = config.get(DOMAIN, {})
|
conf = config.get(DOMAIN, {})
|
||||||
host = conf.get(CONF_HOST)
|
host = conf.get(CONF_HOST)
|
||||||
allow_tradfri_groups = conf.get(CONF_ALLOW_TRADFRI_GROUPS)
|
allow_tradfri_groups = conf.get(CONF_ALLOW_TRADFRI_GROUPS)
|
||||||
keys = yield from hass.async_add_job(_read_config, hass)
|
known_hosts = yield from hass.async_add_job(load_json,
|
||||||
|
hass.config.path(CONFIG_FILE))
|
||||||
|
|
||||||
@asyncio.coroutine
|
@asyncio.coroutine
|
||||||
def gateway_discovered(service, info):
|
def gateway_discovered(service, info,
|
||||||
|
allow_tradfri_groups=DEFAULT_ALLOW_TRADFRI_GROUPS):
|
||||||
"""Run when a gateway is discovered."""
|
"""Run when a gateway is discovered."""
|
||||||
host = info['host']
|
host = info['host']
|
||||||
|
|
||||||
if host in keys:
|
if host in known_hosts:
|
||||||
yield from _setup_gateway(hass, config, host, keys[host]['key'],
|
# 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)
|
allow_tradfri_groups)
|
||||||
else:
|
else:
|
||||||
hass.async_add_job(request_configuration, hass, config, host)
|
hass.async_add_job(request_configuration, hass, config, host)
|
||||||
|
|
||||||
discovery.async_listen(hass, SERVICE_IKEA_TRADFRI, gateway_discovered)
|
discovery.async_listen(hass, SERVICE_IKEA_TRADFRI, gateway_discovered)
|
||||||
|
|
||||||
if not host:
|
if host:
|
||||||
return True
|
yield from gateway_discovered(None,
|
||||||
|
{'host': host},
|
||||||
if host and keys.get(host):
|
allow_tradfri_groups)
|
||||||
return (yield from _setup_gateway(hass, config, host,
|
return True
|
||||||
keys[host]['key'],
|
|
||||||
allow_tradfri_groups))
|
|
||||||
else:
|
|
||||||
hass.async_add_job(request_configuration, hass, config, host)
|
|
||||||
return True
|
|
||||||
|
|
||||||
|
|
||||||
@asyncio.coroutine
|
@asyncio.coroutine
|
||||||
def _setup_gateway(hass, hass_config, host, key, allow_tradfri_groups):
|
def _setup_gateway(hass, hass_config, host, identity, key,
|
||||||
|
allow_tradfri_groups):
|
||||||
"""Create a gateway."""
|
"""Create a gateway."""
|
||||||
from pytradfri import Gateway, RequestError
|
from pytradfri import Gateway, RequestError
|
||||||
try:
|
try:
|
||||||
|
@ -134,7 +151,7 @@ def _setup_gateway(hass, hass_config, host, key, allow_tradfri_groups):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
try:
|
try:
|
||||||
factory = APIFactory(host, psk_id=GATEWAY_IDENTITY, psk=key,
|
factory = APIFactory(host, psk_id=identity, psk=key,
|
||||||
loop=hass.loop)
|
loop=hass.loop)
|
||||||
api = factory.request
|
api = factory.request
|
||||||
gateway = Gateway()
|
gateway = Gateway()
|
||||||
|
@ -163,22 +180,3 @@ def _setup_gateway(hass, hass_config, host, key, allow_tradfri_groups):
|
||||||
hass.async_add_job(discovery.async_load_platform(
|
hass.async_add_job(discovery.async_load_platform(
|
||||||
hass, 'sensor', DOMAIN, {'gateway': gateway_id}, hass_config))
|
hass, 'sensor', DOMAIN, {'gateway': gateway_id}, hass_config))
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
def _read_config(hass):
|
|
||||||
"""Read tradfri config."""
|
|
||||||
path = hass.config.path(CONFIG_FILE)
|
|
||||||
|
|
||||||
if not os.path.isfile(path):
|
|
||||||
return {}
|
|
||||||
|
|
||||||
with open(path) as f_handle:
|
|
||||||
# Guard against empty file
|
|
||||||
return json.loads(f_handle.read() or '{}')
|
|
||||||
|
|
||||||
|
|
||||||
def _write_config(hass, config):
|
|
||||||
"""Write tradfri config."""
|
|
||||||
data = json.dumps(config)
|
|
||||||
with open(hass.config.path(CONFIG_FILE), 'w', encoding='utf-8') as outfile:
|
|
||||||
outfile.write(data)
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue