diff --git a/homeassistant/components/hue.py b/homeassistant/components/hue.py index a83b55e84e5287..36d5a1a56a0549 100644 --- a/homeassistant/components/hue.py +++ b/homeassistant/components/hue.py @@ -9,6 +9,7 @@ import os import socket +import requests import voluptuous as vol from homeassistant.components.discovery import SERVICE_HUE @@ -22,6 +23,7 @@ DOMAIN = "hue" SERVICE_HUE_SCENE = "hue_activate_scene" +API_NUPNP = 'https://www.meethue.com/api/nupnp' CONF_BRIDGES = "bridges" @@ -49,7 +51,7 @@ 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 @@ 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) diff --git a/tests/common.py b/tests/common.py index d7b603cca58d07..3823a1e2b4ef72 100644 --- a/tests/common.py +++ b/tests/common.py @@ -542,10 +542,8 @@ def __init__(self, root, *args): 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 @@ def resolve(mock, path): 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) diff --git a/tests/components/test_hue.py b/tests/components/test_hue.py index 227295594db6c2..b8568f3aabaa79 100644 --- a/tests/components/test_hue.py +++ b/tests/components/test_hue.py @@ -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 @@ def test_setup_no_domain(self, mock_phue): 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 @@ def test_hue_activate_scene(self, mock_phue): {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] == {}