mirror of
https://github.com/home-assistant/core.git
synced 2025-04-25 01:38:02 +00:00
Make Tradfri discoverable (#7128)
* Make Tradfri discoverable * Fix lint errors * Fix bugs and clean up calls to light_control * Add more color util tests * Add coap client to dockerfile
This commit is contained in:
parent
75242e67a7
commit
951af6c76d
@ -97,6 +97,9 @@ omit =
|
||||
|
||||
homeassistant/components/*/thinkingcleaner.py
|
||||
|
||||
homeassistant/components/tradfri.py
|
||||
homeassistant/components/*/tradfri.py
|
||||
|
||||
homeassistant/components/twilio.py
|
||||
homeassistant/components/notify/twilio_sms.py
|
||||
homeassistant/components/notify/twilio_call.py
|
||||
|
@ -8,6 +8,7 @@ MAINTAINER Paulus Schoutsen <Paulus@PaulusSchoutsen.nl>
|
||||
#ENV INSTALL_OPENZWAVE no
|
||||
#ENV INSTALL_LIBCEC no
|
||||
#ENV INSTALL_PHANTOMJS no
|
||||
#ENV INSTALL_COAP_CLIENT no
|
||||
|
||||
VOLUME /config
|
||||
|
||||
|
@ -180,7 +180,7 @@ class Configurator(object):
|
||||
|
||||
# field validation goes here?
|
||||
|
||||
callback(call.data.get(ATTR_FIELDS, {}))
|
||||
self.hass.async_add_job(callback, call.data.get(ATTR_FIELDS, {}))
|
||||
|
||||
def _generate_unique_id(self):
|
||||
"""Generate a unique configurator ID."""
|
||||
|
@ -28,11 +28,13 @@ SCAN_INTERVAL = timedelta(seconds=300)
|
||||
SERVICE_NETGEAR = 'netgear_router'
|
||||
SERVICE_WEMO = 'belkin_wemo'
|
||||
SERVICE_HASS_IOS_APP = 'hass_ios'
|
||||
SERVICE_IKEA_TRADFRI = 'ikea_tradfri'
|
||||
|
||||
SERVICE_HANDLERS = {
|
||||
SERVICE_HASS_IOS_APP: ('ios', None),
|
||||
SERVICE_NETGEAR: ('device_tracker', None),
|
||||
SERVICE_WEMO: ('wemo', None),
|
||||
SERVICE_IKEA_TRADFRI: ('tradfri', None),
|
||||
'philips_hue': ('light', 'hue'),
|
||||
'google_cast': ('media_player', 'cast'),
|
||||
'panasonic_viera': ('media_player', 'panasonic_viera'),
|
||||
|
@ -1,52 +1,29 @@
|
||||
"""Support for the IKEA Tradfri platform."""
|
||||
|
||||
import logging
|
||||
|
||||
|
||||
import voluptuous as vol
|
||||
|
||||
import homeassistant.util.color as color_util
|
||||
from homeassistant.components.tradfri import KEY_GATEWAY
|
||||
from homeassistant.components.light import (
|
||||
ATTR_BRIGHTNESS, ATTR_RGB_COLOR, Light,
|
||||
PLATFORM_SCHEMA, SUPPORT_BRIGHTNESS, SUPPORT_RGB_COLOR)
|
||||
from homeassistant.const import CONF_API_KEY, CONF_HOST
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
ATTR_BRIGHTNESS, SUPPORT_BRIGHTNESS, Light, ATTR_RGB_COLOR,
|
||||
SUPPORT_RGB_COLOR, PLATFORM_SCHEMA as LIGHT_PLATFORM_SCHEMA)
|
||||
from homeassistant.util import color as color_util
|
||||
|
||||
DEPENDENCIES = ['tradfri']
|
||||
SUPPORTED_FEATURES = (SUPPORT_BRIGHTNESS | SUPPORT_RGB_COLOR)
|
||||
|
||||
# https://github.com/ggravlingen/pytradfri
|
||||
REQUIREMENTS = ['pytradfri==0.4']
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
# Validation of the user's configuration
|
||||
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
|
||||
vol.Required(CONF_HOST): cv.string,
|
||||
vol.Optional(CONF_API_KEY): cv.string,
|
||||
})
|
||||
PLATFORM_SCHEMA = LIGHT_PLATFORM_SCHEMA
|
||||
|
||||
|
||||
def setup_platform(hass, config, add_devices, discovery_info=None):
|
||||
"""Setup the IKEA Tradfri Light platform."""
|
||||
import pytradfri
|
||||
if discovery_info is None:
|
||||
return
|
||||
|
||||
# Assign configuration variables.
|
||||
host = config.get(CONF_HOST)
|
||||
securitycode = config.get(CONF_API_KEY)
|
||||
|
||||
api = pytradfri.coap_cli.api_factory(host, securitycode)
|
||||
|
||||
gateway = pytradfri.gateway.Gateway(api)
|
||||
gateway_id = discovery_info['gateway']
|
||||
gateway = hass.data[KEY_GATEWAY][gateway_id]
|
||||
devices = gateway.get_devices()
|
||||
lights = [dev for dev in devices if dev.has_light_control]
|
||||
|
||||
_LOGGER.debug("IKEA Tradfri Hub | init | Initialization Process Complete")
|
||||
|
||||
add_devices(IKEATradfri(light) for light in lights)
|
||||
_LOGGER.debug("IKEA Tradfri Hub | get_lights | All Lights Loaded")
|
||||
add_devices(Tradfri(light) for light in lights)
|
||||
|
||||
|
||||
class IKEATradfri(Light):
|
||||
class Tradfri(Light):
|
||||
"""The platform class required by hass."""
|
||||
|
||||
def __init__(self, light):
|
||||
@ -57,8 +34,6 @@ class IKEATradfri(Light):
|
||||
self._light_control = light.light_control
|
||||
self._light_data = light.light_control.lights[0]
|
||||
self._name = light.name
|
||||
|
||||
self._brightness = None
|
||||
self._rgb_color = None
|
||||
|
||||
@property
|
||||
@ -98,17 +73,17 @@ class IKEATradfri(Light):
|
||||
for ATTR_RGB_COLOR, this also supports Philips Hue bulbs.
|
||||
"""
|
||||
if ATTR_BRIGHTNESS in kwargs:
|
||||
self._light.light_control.set_dimmer(kwargs.get(ATTR_BRIGHTNESS))
|
||||
self._light_control.set_dimmer(kwargs[ATTR_BRIGHTNESS])
|
||||
else:
|
||||
self._light_control.set_state(True)
|
||||
|
||||
if ATTR_RGB_COLOR in kwargs and self._light_data.hex_color is not None:
|
||||
self._light.light_control.set_hex_color(
|
||||
color_util.color_rgb_to_hex(*kwargs[ATTR_RGB_COLOR]))
|
||||
else:
|
||||
self._light.light_control.set_state(True)
|
||||
|
||||
def update(self):
|
||||
"""Fetch new state data for this light."""
|
||||
self._light.update()
|
||||
self._brightness = self._light_data.dimmer
|
||||
|
||||
# Handle Hue lights paired with the gatway
|
||||
if self._light_data.hex_color is not None:
|
||||
|
141
homeassistant/components/tradfri.py
Normal file
141
homeassistant/components/tradfri.py
Normal file
@ -0,0 +1,141 @@
|
||||
"""
|
||||
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 json
|
||||
import logging
|
||||
import os
|
||||
|
||||
import voluptuous as vol
|
||||
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
from homeassistant.helpers import discovery
|
||||
from homeassistant.const import CONF_HOST, CONF_API_KEY
|
||||
from homeassistant.loader import get_component
|
||||
from homeassistant.components.discovery import SERVICE_IKEA_TRADFRI
|
||||
|
||||
DOMAIN = 'tradfri'
|
||||
CONFIG_FILE = 'tradfri.conf'
|
||||
KEY_CONFIG = 'tradfri_configuring'
|
||||
KEY_GATEWAY = 'tradfri_gateway'
|
||||
REQUIREMENTS = ['pytradfri==0.4']
|
||||
|
||||
CONFIG_SCHEMA = vol.Schema({
|
||||
DOMAIN: vol.Schema({
|
||||
vol.Inclusive(CONF_HOST, 'gateway'): cv.string,
|
||||
vol.Inclusive(CONF_API_KEY, 'gateway'): cv.string,
|
||||
})
|
||||
}, extra=vol.ALLOW_EXTRA)
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def request_configuration(hass, config, host):
|
||||
"""Request configuration steps from the user."""
|
||||
configurator = get_component('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):
|
||||
"""Called when config is submitted."""
|
||||
res = yield from _setup_gateway(hass, config, host,
|
||||
callback_data.get('key'))
|
||||
if not res:
|
||||
hass.async_add_job(configurator.notify_errors, instance,
|
||||
"Unable to connect.")
|
||||
return
|
||||
|
||||
def success():
|
||||
"""Set up was successful."""
|
||||
conf = _read_config(hass)
|
||||
conf[host] = {'key': callback_data.get('key')}
|
||||
_write_config(hass, conf)
|
||||
hass.async_add_job(configurator.request_done, instance)
|
||||
|
||||
hass.async_add_job(success)
|
||||
|
||||
instance = configurator.request_config(
|
||||
hass, "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': 'key', 'name': 'Security Code', 'type': 'password'}]
|
||||
)
|
||||
|
||||
|
||||
@asyncio.coroutine
|
||||
def async_setup(hass, config):
|
||||
"""Setup Tradfri."""
|
||||
conf = config.get(DOMAIN, {})
|
||||
host = conf.get(CONF_HOST)
|
||||
key = conf.get(CONF_API_KEY)
|
||||
|
||||
@asyncio.coroutine
|
||||
def gateway_discovered(service, info):
|
||||
"""Called when a gateway is discovered."""
|
||||
keys = yield from hass.async_add_job(_read_config, hass)
|
||||
host = info['host']
|
||||
|
||||
if host in keys:
|
||||
yield from _setup_gateway(hass, config, host, keys[host]['key'])
|
||||
else:
|
||||
hass.async_add_job(request_configuration, hass, config, host)
|
||||
|
||||
discovery.async_listen(hass, SERVICE_IKEA_TRADFRI, gateway_discovered)
|
||||
|
||||
if host is None:
|
||||
return True
|
||||
|
||||
return (yield from _setup_gateway(hass, config, host, key))
|
||||
|
||||
|
||||
@asyncio.coroutine
|
||||
def _setup_gateway(hass, hass_config, host, key):
|
||||
"""Create a gateway."""
|
||||
from pytradfri import cli_api_factory, Gateway, RequestError
|
||||
|
||||
try:
|
||||
api = cli_api_factory(host, key)
|
||||
except RequestError:
|
||||
return False
|
||||
|
||||
gateway = Gateway(api)
|
||||
gateway_id = gateway.get_gateway_info().id
|
||||
hass.data.setdefault(KEY_GATEWAY, {})
|
||||
gateways = hass.data[KEY_GATEWAY]
|
||||
|
||||
# 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))
|
||||
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)
|
@ -655,7 +655,7 @@ python-wink==1.2.3
|
||||
# homeassistant.components.device_tracker.trackr
|
||||
pytrackr==0.0.5
|
||||
|
||||
# homeassistant.components.light.tradfri
|
||||
# homeassistant.components.tradfri
|
||||
pytradfri==0.4
|
||||
|
||||
# homeassistant.components.device_tracker.unifi
|
||||
|
@ -175,8 +175,9 @@ class TestColorUtil(unittest.TestCase):
|
||||
|
||||
def test_color_rgb_to_hex(self):
|
||||
"""Test color_rgb_to_hex."""
|
||||
self.assertEqual('000000',
|
||||
color_util.color_rgb_to_hex(0, 0, 0))
|
||||
assert color_util.color_rgb_to_hex(255, 255, 255) == 'ffffff'
|
||||
assert color_util.color_rgb_to_hex(0, 0, 0) == '000000'
|
||||
assert color_util.color_rgb_to_hex(51, 153, 255) == '3399ff'
|
||||
|
||||
|
||||
class ColorTemperatureMiredToKelvinTests(unittest.TestCase):
|
||||
|
14
virtualization/Docker/scripts/coap_client
Executable file
14
virtualization/Docker/scripts/coap_client
Executable file
@ -0,0 +1,14 @@
|
||||
#!/bin/sh
|
||||
# Installs a modified coap client with support for dtls for use with IKEA Tradfri
|
||||
|
||||
# Stop on errors
|
||||
set -e
|
||||
|
||||
apt-get install -y --no-install-recommends git autoconf automake libtool
|
||||
|
||||
git clone --depth 1 --recursive -b dtls https://github.com/home-assistant/libcoap.git
|
||||
cd libcoap
|
||||
./autogen.sh
|
||||
./configure --disable-documentation --disable-shared
|
||||
make
|
||||
make install
|
@ -12,7 +12,7 @@ PACKAGES=(
|
||||
apt-get install -y --no-install-recommends ${PACKAGES[@]}
|
||||
|
||||
# Clone the latest code from GitHub
|
||||
git clone https://github.com/openalpr/openalpr.git /usr/local/src/openalpr
|
||||
git clone --depth 1 https://github.com/openalpr/openalpr.git /usr/local/src/openalpr
|
||||
|
||||
# Setup the build directory
|
||||
cd /usr/local/src/openalpr/src
|
||||
|
@ -10,6 +10,7 @@ INSTALL_FFMPEG="${INSTALL_FFMPEG:-yes}"
|
||||
INSTALL_OPENZWAVE="${INSTALL_OPENZWAVE:-yes}"
|
||||
INSTALL_LIBCEC="${INSTALL_LIBCEC:-yes}"
|
||||
INSTALL_PHANTOMJS="${INSTALL_PHANTOMJS:-yes}"
|
||||
INSTALL_COAP_CLIENT="${INSTALL_COAP_CLIENT:-yes}"
|
||||
|
||||
# Required debian packages for running hass or components
|
||||
PACKAGES=(
|
||||
@ -62,6 +63,10 @@ if [ "$INSTALL_PHANTOMJS" == "yes" ]; then
|
||||
virtualization/Docker/scripts/phantomjs
|
||||
fi
|
||||
|
||||
if [ "$INSTALL_COAP_CLIENT" == "yes" ]; then
|
||||
virtualization/Docker/scripts/coap_client
|
||||
fi
|
||||
|
||||
# Remove packages
|
||||
apt-get remove -y --purge ${PACKAGES_DEV[@]}
|
||||
apt-get -y --purge autoremove
|
||||
|
Loading…
x
Reference in New Issue
Block a user