Use API to discover Hue if no bridges specified (#11909)
* Use API to discover Hue if no bridges specified * hide config filepull/11833/head^2
parent
9123dfce6d
commit
3d9ff372fc
|
@ -9,6 +9,7 @@ import logging
|
|||
import os
|
||||
import socket
|
||||
|
||||
import requests
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.components.discovery import SERVICE_HUE
|
||||
|
@ -22,6 +23,7 @@ _LOGGER = logging.getLogger(__name__)
|
|||
|
||||
DOMAIN = "hue"
|
||||
SERVICE_HUE_SCENE = "hue_activate_scene"
|
||||
API_NUPNP = 'https://www.meethue.com/api/nupnp'
|
||||
|
||||
CONF_BRIDGES = "bridges"
|
||||
|
||||
|
@ -49,7 +51,7 @@ BRIDGE_CONFIG_SCHEMA = vol.Schema([{
|
|||
|
||||
CONFIG_SCHEMA = vol.Schema({
|
||||
DOMAIN: vol.Schema({
|
||||
vol.Optional(CONF_BRIDGES, default=[]): BRIDGE_CONFIG_SCHEMA,
|
||||
vol.Optional(CONF_BRIDGES): BRIDGE_CONFIG_SCHEMA,
|
||||
}),
|
||||
}, extra=vol.ALLOW_EXTRA)
|
||||
|
||||
|
@ -69,9 +71,9 @@ Press the button on the bridge to register Philips Hue with Home Assistant.
|
|||
|
||||
def setup(hass, config):
|
||||
"""Set up the Hue platform."""
|
||||
config = config.get(DOMAIN)
|
||||
if config is None:
|
||||
config = {}
|
||||
conf = config.get(DOMAIN)
|
||||
if conf is None:
|
||||
conf = {}
|
||||
|
||||
if DOMAIN not in hass.data:
|
||||
hass.data[DOMAIN] = {}
|
||||
|
@ -82,7 +84,21 @@ def setup(hass, config):
|
|||
lambda service, discovery_info:
|
||||
bridge_discovered(hass, service, discovery_info))
|
||||
|
||||
bridges = config.get(CONF_BRIDGES, [])
|
||||
# User has configured bridges
|
||||
if CONF_BRIDGES in conf:
|
||||
bridges = conf[CONF_BRIDGES]
|
||||
# Component is part of config but no bridges specified, discover.
|
||||
elif DOMAIN in config:
|
||||
# discover from nupnp
|
||||
hosts = requests.get(API_NUPNP).json()
|
||||
bridges = [{
|
||||
CONF_HOST: entry['internalipaddress'],
|
||||
CONF_FILENAME: '.hue_{}.conf'.format(entry['id']),
|
||||
} for entry in hosts]
|
||||
else:
|
||||
# Component not specified in config, we're loaded via discovery
|
||||
bridges = []
|
||||
|
||||
for bridge in bridges:
|
||||
filename = bridge.get(CONF_FILENAME)
|
||||
allow_unreachable = bridge.get(CONF_ALLOW_UNREACHABLE)
|
||||
|
|
|
@ -542,10 +542,8 @@ class MockDependency:
|
|||
self.root = root
|
||||
self.submodules = args
|
||||
|
||||
def __call__(self, func):
|
||||
"""Apply decorator."""
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
def __enter__(self):
|
||||
"""Start mocking."""
|
||||
def resolve(mock, path):
|
||||
"""Resolve a mock."""
|
||||
if not path:
|
||||
|
@ -553,16 +551,27 @@ class MockDependency:
|
|||
|
||||
return resolve(getattr(mock, path[0]), path[1:])
|
||||
|
||||
base = MagicMock()
|
||||
to_mock = {
|
||||
"{}.{}".format(self.root, tom): resolve(base, tom.split('.'))
|
||||
for tom in self.submodules
|
||||
}
|
||||
to_mock[self.root] = base
|
||||
|
||||
self.patcher = patch.dict('sys.modules', to_mock)
|
||||
self.patcher.start()
|
||||
return base
|
||||
|
||||
def __exit__(self, *exc):
|
||||
"""Stop mocking."""
|
||||
self.patcher.stop()
|
||||
return False
|
||||
|
||||
def __call__(self, func):
|
||||
"""Apply decorator."""
|
||||
def run_mocked(*args, **kwargs):
|
||||
"""Run with mocked dependencies."""
|
||||
base = MagicMock()
|
||||
to_mock = {
|
||||
"{}.{}".format(self.root, tom): resolve(base, tom.split('.'))
|
||||
for tom in self.submodules
|
||||
}
|
||||
to_mock[self.root] = base
|
||||
|
||||
with patch.dict('sys.modules', to_mock):
|
||||
with self as base:
|
||||
args = list(args) + [base]
|
||||
func(*args, **kwargs)
|
||||
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
"""Generic Philips Hue component tests."""
|
||||
|
||||
import asyncio
|
||||
import logging
|
||||
import unittest
|
||||
from unittest.mock import call, MagicMock, patch
|
||||
|
||||
from homeassistant.components import configurator, hue
|
||||
from homeassistant.const import CONF_FILENAME, CONF_HOST
|
||||
from homeassistant.setup import setup_component
|
||||
from homeassistant.setup import setup_component, async_setup_component
|
||||
|
||||
from tests.common import (
|
||||
assert_setup_component, get_test_home_assistant, get_test_config_dir,
|
||||
|
@ -38,15 +38,6 @@ class TestSetup(unittest.TestCase):
|
|||
mock_phue.Bridge.assert_not_called()
|
||||
self.assertEquals({}, self.hass.data[hue.DOMAIN])
|
||||
|
||||
@MockDependency('phue')
|
||||
def test_setup_no_host(self, mock_phue):
|
||||
"""No host specified in any way."""
|
||||
with assert_setup_component(1):
|
||||
self.assertTrue(setup_component(
|
||||
self.hass, hue.DOMAIN, {hue.DOMAIN: {}}))
|
||||
mock_phue.Bridge.assert_not_called()
|
||||
self.assertEquals({}, self.hass.data[hue.DOMAIN])
|
||||
|
||||
@MockDependency('phue')
|
||||
def test_setup_with_host(self, mock_phue):
|
||||
"""Host specified in the config file."""
|
||||
|
@ -400,3 +391,17 @@ class TestHueBridge(unittest.TestCase):
|
|||
{hue.ATTR_GROUP_NAME: 'group', hue.ATTR_SCENE_NAME: 'scene'},
|
||||
blocking=True)
|
||||
bridge.bridge.run_scene.assert_called_once_with('group', 'scene')
|
||||
|
||||
|
||||
@asyncio.coroutine
|
||||
def test_setup_no_host(hass, requests_mock):
|
||||
"""No host specified in any way."""
|
||||
requests_mock.get(hue.API_NUPNP, json=[])
|
||||
with MockDependency('phue') as mock_phue:
|
||||
result = yield from async_setup_component(
|
||||
hass, hue.DOMAIN, {hue.DOMAIN: {}})
|
||||
assert result
|
||||
|
||||
mock_phue.Bridge.assert_not_called()
|
||||
|
||||
assert hass.data[hue.DOMAIN] == {}
|
||||
|
|
Loading…
Reference in New Issue