diff --git a/README.md b/README.md
index 523ce94582c688..08564802e77a34 100644
--- a/README.md
+++ b/README.md
@@ -55,6 +55,8 @@ After you got the demo mode running it is time to enable some real components an
*Note:* you can append `?api_password=YOUR_PASSWORD` to the url of the web interface to log in automatically.
+*Note:* for the light and switch component, you can specify multiple types by using sequential sections: [switch], [switch 2], [switch 3] etc
+
### Philips Hue
To get Philips Hue working you will have to connect Home Assistant to the Hue bridge.
@@ -68,7 +70,7 @@ After that add the following lines to your `home-assistant.conf`:
```
[light]
-type=hue
+platform=hue
```
### Wireless router
@@ -77,7 +79,7 @@ Your wireless router is used to track which devices are connected. Three differe
```
[device_tracker]
-type=netgear
+platform=netgear
host=192.168.1.1
username=admin
password=MY_PASSWORD
diff --git a/config/home-assistant.conf.example b/config/home-assistant.conf.example
index 9eb0cf4a90ea07..5a919ac38b06ff 100644
--- a/config/home-assistant.conf.example
+++ b/config/home-assistant.conf.example
@@ -9,11 +9,11 @@ api_password=mypass
# development=1
[light]
-type=hue
+platform=hue
[device_tracker]
# The following types are available: netgear, tomato, luci
-type=netgear
+platform=netgear
host=192.168.1.1
username=admin
password=PASSWORD
@@ -26,7 +26,7 @@ password=PASSWORD
# hosts=192.168.1.9,192.168.1.12
[switch]
-type=wemo
+platform=wemo
# Optional: hard code the hosts (comma seperated) to avoid scanning the network
# hosts=192.168.1.9,192.168.1.12
diff --git a/ha_test/config/custom_components/light/test.py b/ha_test/config/custom_components/light/test.py
index 757099ddca044e..0ed04a21717a04 100644
--- a/ha_test/config/custom_components/light/test.py
+++ b/ha_test/config/custom_components/light/test.py
@@ -6,8 +6,8 @@
Call init before using it in your tests to ensure clean test data.
"""
-import homeassistant.components as components
-from ha_test.helper import MockToggleDevice
+from homeassistant.const import STATE_ON, STATE_OFF
+from ha_test.helpers import MockToggleDevice
DEVICES = []
@@ -18,9 +18,9 @@ def init(empty=False):
global DEVICES
DEVICES = [] if empty else [
- MockToggleDevice('Ceiling', components.STATE_ON),
- MockToggleDevice('Ceiling', components.STATE_OFF),
- MockToggleDevice(None, components.STATE_OFF)
+ MockToggleDevice('Ceiling', STATE_ON),
+ MockToggleDevice('Ceiling', STATE_OFF),
+ MockToggleDevice(None, STATE_OFF)
]
diff --git a/ha_test/config/custom_components/switch/test.py b/ha_test/config/custom_components/switch/test.py
index 927aca24feb641..682c27f695f428 100644
--- a/ha_test/config/custom_components/switch/test.py
+++ b/ha_test/config/custom_components/switch/test.py
@@ -6,8 +6,8 @@
Call init before using it in your tests to ensure clean test data.
"""
-import homeassistant.components as components
-from ha_test.helper import MockToggleDevice
+from homeassistant.const import STATE_ON, STATE_OFF
+from ha_test.helpers import MockToggleDevice
DEVICES = []
@@ -18,9 +18,9 @@ def init(empty=False):
global DEVICES
DEVICES = [] if empty else [
- MockToggleDevice('AC', components.STATE_ON),
- MockToggleDevice('AC', components.STATE_OFF),
- MockToggleDevice(None, components.STATE_OFF)
+ MockToggleDevice('AC', STATE_ON),
+ MockToggleDevice('AC', STATE_OFF),
+ MockToggleDevice(None, STATE_OFF)
]
diff --git a/ha_test/helper.py b/ha_test/helpers.py
similarity index 88%
rename from ha_test/helper.py
rename to ha_test/helpers.py
index 109b4185ba59e0..f04dac72553c72 100644
--- a/ha_test/helper.py
+++ b/ha_test/helpers.py
@@ -7,7 +7,8 @@
import os
import homeassistant as ha
-import homeassistant.components as components
+from homeassistant.helpers import ToggleDevice
+from homeassistant.const import STATE_ON, STATE_OFF
def get_test_home_assistant():
@@ -41,7 +42,7 @@ def __init__(self, domain, dependencies=[], setup=None):
self.setup = lambda hass, config: False if setup is None else setup
-class MockToggleDevice(components.ToggleDevice):
+class MockToggleDevice(ToggleDevice):
""" Provides a mock toggle device. """
def __init__(self, name, state):
self.name = name
@@ -56,17 +57,17 @@ def get_name(self):
def turn_on(self, **kwargs):
""" Turn the device on. """
self.calls.append(('turn_on', kwargs))
- self.state = components.STATE_ON
+ self.state = STATE_ON
def turn_off(self, **kwargs):
""" Turn the device off. """
self.calls.append(('turn_off', kwargs))
- self.state = components.STATE_OFF
+ self.state = STATE_OFF
def is_on(self):
""" True if device is on. """
self.calls.append(('is_on', {}))
- return self.state == components.STATE_ON
+ return self.state == STATE_ON
def last_call(self, method=None):
if method is None:
diff --git a/ha_test/test_component_chromecast.py b/ha_test/test_component_chromecast.py
index 3b80c700606b1d..3d9733648c9a5c 100644
--- a/ha_test/test_component_chromecast.py
+++ b/ha_test/test_component_chromecast.py
@@ -9,9 +9,13 @@
import unittest
import homeassistant as ha
-import homeassistant.components as components
+from homeassistant.const import (
+ SERVICE_TURN_OFF, SERVICE_VOLUME_UP, SERVICE_VOLUME_DOWN,
+ SERVICE_MEDIA_PLAY_PAUSE, SERVICE_MEDIA_PLAY, SERVICE_MEDIA_PAUSE,
+ SERVICE_MEDIA_NEXT_TRACK, SERVICE_MEDIA_PREV_TRACK, ATTR_ENTITY_ID,
+ CONF_HOSTS)
import homeassistant.components.chromecast as chromecast
-from helper import mock_service
+from helpers import mock_service
def setUpModule(): # pylint: disable=invalid-name
@@ -45,14 +49,14 @@ def test_services(self):
Test if the call service methods conver to correct service calls.
"""
services = {
- components.SERVICE_TURN_OFF: chromecast.turn_off,
- components.SERVICE_VOLUME_UP: chromecast.volume_up,
- components.SERVICE_VOLUME_DOWN: chromecast.volume_down,
- components.SERVICE_MEDIA_PLAY_PAUSE: chromecast.media_play_pause,
- components.SERVICE_MEDIA_PLAY: chromecast.media_play,
- components.SERVICE_MEDIA_PAUSE: chromecast.media_pause,
- components.SERVICE_MEDIA_NEXT_TRACK: chromecast.media_next_track,
- components.SERVICE_MEDIA_PREV_TRACK: chromecast.media_prev_track
+ SERVICE_TURN_OFF: chromecast.turn_off,
+ SERVICE_VOLUME_UP: chromecast.volume_up,
+ SERVICE_VOLUME_DOWN: chromecast.volume_down,
+ SERVICE_MEDIA_PLAY_PAUSE: chromecast.media_play_pause,
+ SERVICE_MEDIA_PLAY: chromecast.media_play,
+ SERVICE_MEDIA_PAUSE: chromecast.media_pause,
+ SERVICE_MEDIA_NEXT_TRACK: chromecast.media_next_track,
+ SERVICE_MEDIA_PREV_TRACK: chromecast.media_prev_track
}
for service_name, service_method in services.items():
@@ -75,7 +79,7 @@ def test_services(self):
self.assertEqual(call.domain, chromecast.DOMAIN)
self.assertEqual(call.service, service_name)
self.assertEqual(call.data,
- {components.ATTR_ENTITY_ID: self.test_entity})
+ {ATTR_ENTITY_ID: self.test_entity})
def test_setup(self):
"""
@@ -84,4 +88,4 @@ def test_setup(self):
In an ideal world we would create a mock pychromecast API..
"""
self.assertFalse(chromecast.setup(
- self.hass, {chromecast.DOMAIN: {ha.CONF_HOSTS: '127.0.0.1'}}))
+ self.hass, {chromecast.DOMAIN: {CONF_HOSTS: '127.0.0.1'}}))
diff --git a/ha_test/test_component_core.py b/ha_test/test_component_core.py
index 2a4a942a5ba052..927bfb98a7c293 100644
--- a/ha_test/test_component_core.py
+++ b/ha_test/test_component_core.py
@@ -9,6 +9,8 @@
import homeassistant as ha
import homeassistant.loader as loader
+from homeassistant.const import (
+ STATE_ON, STATE_OFF, SERVICE_TURN_ON, SERVICE_TURN_OFF)
import homeassistant.components as comps
@@ -21,8 +23,8 @@ def setUp(self): # pylint: disable=invalid-name
loader.prepare(self.hass)
self.assertTrue(comps.setup(self.hass, {}))
- self.hass.states.set('light.Bowl', comps.STATE_ON)
- self.hass.states.set('light.Ceiling', comps.STATE_OFF)
+ self.hass.states.set('light.Bowl', STATE_ON)
+ self.hass.states.set('light.Ceiling', STATE_OFF)
def tearDown(self): # pylint: disable=invalid-name
""" Stop down stuff we started. """
@@ -38,7 +40,7 @@ def test_turn_on(self):
""" Test turn_on method. """
runs = []
self.hass.services.register(
- 'light', comps.SERVICE_TURN_ON, lambda x: runs.append(1))
+ 'light', SERVICE_TURN_ON, lambda x: runs.append(1))
comps.turn_on(self.hass, 'light.Ceiling')
@@ -50,24 +52,10 @@ def test_turn_off(self):
""" Test turn_off method. """
runs = []
self.hass.services.register(
- 'light', comps.SERVICE_TURN_OFF, lambda x: runs.append(1))
+ 'light', SERVICE_TURN_OFF, lambda x: runs.append(1))
comps.turn_off(self.hass, 'light.Bowl')
self.hass._pool.block_till_done()
self.assertEqual(1, len(runs))
-
- def test_extract_entity_ids(self):
- """ Test extract_entity_ids method. """
- call = ha.ServiceCall('light', 'turn_on',
- {comps.ATTR_ENTITY_ID: 'light.Bowl'})
-
- self.assertEqual(['light.Bowl'],
- comps.extract_entity_ids(self.hass, call))
-
- call = ha.ServiceCall('light', 'turn_on',
- {comps.ATTR_ENTITY_ID: ['light.Bowl']})
-
- self.assertEqual(['light.Bowl'],
- comps.extract_entity_ids(self.hass, call))
diff --git a/ha_test/test_component_demo.py b/ha_test/test_component_demo.py
index a510759a8ea2a2..72be2d12525282 100644
--- a/ha_test/test_component_demo.py
+++ b/ha_test/test_component_demo.py
@@ -9,7 +9,7 @@
import homeassistant as ha
import homeassistant.components.demo as demo
-from homeassistant.components import (
+from homeassistant.const import (
SERVICE_TURN_ON, SERVICE_TURN_OFF, STATE_ON, STATE_OFF, ATTR_ENTITY_ID)
diff --git a/ha_test/test_component_device_scanner.py b/ha_test/test_component_device_scanner.py
index 26a7ddb5590c5a..09900951eebbd9 100644
--- a/ha_test/test_component_device_scanner.py
+++ b/ha_test/test_component_device_scanner.py
@@ -12,11 +12,11 @@
import homeassistant as ha
import homeassistant.loader as loader
-from homeassistant.components import (
- STATE_HOME, STATE_NOT_HOME, ATTR_ENTITY_PICTURE)
+from homeassistant.const import (
+ STATE_HOME, STATE_NOT_HOME, ATTR_ENTITY_PICTURE, CONF_PLATFORM)
import homeassistant.components.device_tracker as device_tracker
-from helper import get_test_home_assistant
+from helpers import get_test_home_assistant
def setUpModule(): # pylint: disable=invalid-name
@@ -64,7 +64,7 @@ def test_setup(self):
# Test with non-existing component
self.assertFalse(device_tracker.setup(
- self.hass, {device_tracker.DOMAIN: {ha.CONF_TYPE: 'nonexisting'}}
+ self.hass, {device_tracker.DOMAIN: {CONF_PLATFORM: 'nonexisting'}}
))
# Test with a bad known device file around
@@ -72,7 +72,7 @@ def test_setup(self):
fil.write("bad data\nbad data\n")
self.assertFalse(device_tracker.setup(self.hass, {
- device_tracker.DOMAIN: {ha.CONF_TYPE: 'test'}
+ device_tracker.DOMAIN: {CONF_PLATFORM: 'test'}
}))
def test_device_tracker(self):
@@ -84,7 +84,7 @@ def test_device_tracker(self):
scanner.come_home('dev2')
self.assertTrue(device_tracker.setup(self.hass, {
- device_tracker.DOMAIN: {ha.CONF_TYPE: 'test'}
+ device_tracker.DOMAIN: {CONF_PLATFORM: 'test'}
}))
# Ensure a new known devices file has been created.
diff --git a/ha_test/test_component_group.py b/ha_test/test_component_group.py
index d1d9dccbb27fed..d83596cee9db5a 100644
--- a/ha_test/test_component_group.py
+++ b/ha_test/test_component_group.py
@@ -9,7 +9,7 @@
import logging
import homeassistant as ha
-import homeassistant.components as comps
+from homeassistant.const import STATE_ON, STATE_OFF, STATE_HOME, STATE_NOT_HOME
import homeassistant.components.group as group
@@ -25,9 +25,9 @@ def setUp(self): # pylint: disable=invalid-name
""" Init needed objects. """
self.hass = ha.HomeAssistant()
- self.hass.states.set('light.Bowl', comps.STATE_ON)
- self.hass.states.set('light.Ceiling', comps.STATE_OFF)
- self.hass.states.set('switch.AC', comps.STATE_OFF)
+ self.hass.states.set('light.Bowl', STATE_ON)
+ self.hass.states.set('light.Ceiling', STATE_OFF)
+ self.hass.states.set('switch.AC', STATE_OFF)
group.setup_group(self.hass, 'init_group',
['light.Bowl', 'light.Ceiling'], False)
group.setup_group(self.hass, 'mixed_group',
@@ -47,27 +47,27 @@ def test_setup_and_monitor_group(self):
self.assertIn(self.group_name, self.hass.states.entity_ids())
group_state = self.hass.states.get(self.group_name)
- self.assertEqual(comps.STATE_ON, group_state.state)
+ self.assertEqual(STATE_ON, group_state.state)
self.assertTrue(group_state.attributes[group.ATTR_AUTO])
# Turn the Bowl off and see if group turns off
- self.hass.states.set('light.Bowl', comps.STATE_OFF)
+ self.hass.states.set('light.Bowl', STATE_OFF)
self.hass._pool.block_till_done()
group_state = self.hass.states.get(self.group_name)
- self.assertEqual(comps.STATE_OFF, group_state.state)
+ self.assertEqual(STATE_OFF, group_state.state)
# Turn the Ceiling on and see if group turns on
- self.hass.states.set('light.Ceiling', comps.STATE_ON)
+ self.hass.states.set('light.Ceiling', STATE_ON)
self.hass._pool.block_till_done()
group_state = self.hass.states.get(self.group_name)
- self.assertEqual(comps.STATE_ON, group_state.state)
+ self.assertEqual(STATE_ON, group_state.state)
# Try to setup a group with mixed groupable states
- self.hass.states.set('device_tracker.Paulus', comps.STATE_HOME)
+ self.hass.states.set('device_tracker.Paulus', STATE_HOME)
self.assertFalse(group.setup_group(
self.hass, 'person_and_light',
['light.Bowl', 'device_tracker.Paulus']))
@@ -91,12 +91,12 @@ def test_setup_and_monitor_group(self):
def test__get_group_type(self):
""" Test _get_group_type method. """
- self.assertEqual('on_off', group._get_group_type(comps.STATE_ON))
- self.assertEqual('on_off', group._get_group_type(comps.STATE_OFF))
+ self.assertEqual('on_off', group._get_group_type(STATE_ON))
+ self.assertEqual('on_off', group._get_group_type(STATE_OFF))
self.assertEqual('home_not_home',
- group._get_group_type(comps.STATE_HOME))
+ group._get_group_type(STATE_HOME))
self.assertEqual('home_not_home',
- group._get_group_type(comps.STATE_NOT_HOME))
+ group._get_group_type(STATE_NOT_HOME))
# Unsupported state
self.assertIsNone(group._get_group_type('unsupported_state'))
@@ -104,7 +104,7 @@ def test__get_group_type(self):
def test_is_on(self):
""" Test is_on method. """
self.assertTrue(group.is_on(self.hass, self.group_name))
- self.hass.states.set('light.Bowl', comps.STATE_OFF)
+ self.hass.states.set('light.Bowl', STATE_OFF)
self.hass._pool.block_till_done()
self.assertFalse(group.is_on(self.hass, self.group_name))
@@ -159,5 +159,5 @@ def test_setup(self):
group_state = self.hass.states.get(
group.ENTITY_ID_FORMAT.format('second_group'))
- self.assertEqual(comps.STATE_ON, group_state.state)
+ self.assertEqual(STATE_ON, group_state.state)
self.assertFalse(group_state.attributes[group.ATTR_AUTO])
diff --git a/ha_test/test_component_light.py b/ha_test/test_component_light.py
index 3d4b5c1f3eba33..4d781c70132169 100644
--- a/ha_test/test_component_light.py
+++ b/ha_test/test_component_light.py
@@ -11,12 +11,12 @@
import homeassistant as ha
import homeassistant.loader as loader
import homeassistant.util as util
-from homeassistant.components import (
- get_component, ATTR_ENTITY_ID, STATE_ON, STATE_OFF,
+from homeassistant.const import (
+ ATTR_ENTITY_ID, STATE_ON, STATE_OFF, CONF_TYPE,
SERVICE_TURN_ON, SERVICE_TURN_OFF)
import homeassistant.components.light as light
-from helper import mock_service, get_test_home_assistant
+from helpers import mock_service, get_test_home_assistant
class TestLight(unittest.TestCase):
@@ -98,11 +98,11 @@ def test_methods(self):
def test_services(self):
""" Test the provided services. """
- platform = get_component('light.test')
+ platform = loader.get_component('light.test')
platform.init()
self.assertTrue(
- light.setup(self.hass, {light.DOMAIN: {ha.CONF_TYPE: 'test'}}))
+ light.setup(self.hass, {light.DOMAIN: {CONF_TYPE: 'test'}}))
dev1, dev2, dev3 = platform.get_lights(None, None)
@@ -223,22 +223,22 @@ def test_setup(self):
# Test with non-existing component
self.assertFalse(light.setup(
- self.hass, {light.DOMAIN: {ha.CONF_TYPE: 'nonexisting'}}
+ self.hass, {light.DOMAIN: {CONF_TYPE: 'nonexisting'}}
))
# Test if light component returns 0 lightes
- platform = get_component('light.test')
+ platform = loader.get_component('light.test')
platform.init(True)
self.assertEqual([], platform.get_lights(None, None))
self.assertFalse(light.setup(
- self.hass, {light.DOMAIN: {ha.CONF_TYPE: 'test'}}
+ self.hass, {light.DOMAIN: {CONF_TYPE: 'test'}}
))
def test_light_profiles(self):
""" Test light profiles. """
- platform = get_component('light.test')
+ platform = loader.get_component('light.test')
platform.init()
user_light_file = self.hass.get_config_path(light.LIGHT_PROFILES_FILE)
@@ -249,7 +249,7 @@ def test_light_profiles(self):
user_file.write('I,WILL,NOT,WORK\n')
self.assertFalse(light.setup(
- self.hass, {light.DOMAIN: {ha.CONF_TYPE: 'test'}}
+ self.hass, {light.DOMAIN: {CONF_TYPE: 'test'}}
))
# Clean up broken file
@@ -260,7 +260,7 @@ def test_light_profiles(self):
user_file.write('test,.4,.6,100\n')
self.assertTrue(light.setup(
- self.hass, {light.DOMAIN: {ha.CONF_TYPE: 'test'}}
+ self.hass, {light.DOMAIN: {CONF_TYPE: 'test'}}
))
dev1, dev2, dev3 = platform.get_lights(None, None)
diff --git a/ha_test/test_component_sun.py b/ha_test/test_component_sun.py
index a83f8de51a7a27..daf8970f406b96 100644
--- a/ha_test/test_component_sun.py
+++ b/ha_test/test_component_sun.py
@@ -11,6 +11,7 @@
import ephem
import homeassistant as ha
+from homeassistant.const import CONF_LATITUDE, CONF_LONGITUDE
import homeassistant.components.sun as sun
@@ -37,8 +38,8 @@ def test_setting_rising(self):
self.assertTrue(sun.setup(
self.hass,
{ha.DOMAIN: {
- ha.CONF_LATITUDE: '32.87336',
- ha.CONF_LONGITUDE: '117.22743'
+ CONF_LATITUDE: '32.87336',
+ CONF_LONGITUDE: '117.22743'
}}))
observer = ephem.Observer()
@@ -76,8 +77,8 @@ def test_state_change(self):
self.assertTrue(sun.setup(
self.hass,
{ha.DOMAIN: {
- ha.CONF_LATITUDE: '32.87336',
- ha.CONF_LONGITUDE: '117.22743'
+ CONF_LATITUDE: '32.87336',
+ CONF_LONGITUDE: '117.22743'
}}))
if sun.is_on(self.hass):
@@ -101,24 +102,24 @@ def test_setup(self):
self.assertFalse(sun.setup(self.hass, {}))
self.assertFalse(sun.setup(self.hass, {sun.DOMAIN: {}}))
self.assertFalse(sun.setup(
- self.hass, {ha.DOMAIN: {ha.CONF_LATITUDE: '32.87336'}}))
+ self.hass, {ha.DOMAIN: {CONF_LATITUDE: '32.87336'}}))
self.assertFalse(sun.setup(
- self.hass, {ha.DOMAIN: {ha.CONF_LONGITUDE: '117.22743'}}))
+ self.hass, {ha.DOMAIN: {CONF_LONGITUDE: '117.22743'}}))
self.assertFalse(sun.setup(
- self.hass, {ha.DOMAIN: {ha.CONF_LATITUDE: 'hello'}}))
+ self.hass, {ha.DOMAIN: {CONF_LATITUDE: 'hello'}}))
self.assertFalse(sun.setup(
- self.hass, {ha.DOMAIN: {ha.CONF_LONGITUDE: 'how are you'}}))
+ self.hass, {ha.DOMAIN: {CONF_LONGITUDE: 'how are you'}}))
self.assertFalse(sun.setup(
self.hass, {ha.DOMAIN: {
- ha.CONF_LATITUDE: 'wrong', ha.CONF_LONGITUDE: '117.22743'
+ CONF_LATITUDE: 'wrong', CONF_LONGITUDE: '117.22743'
}}))
self.assertFalse(sun.setup(
self.hass, {ha.DOMAIN: {
- ha.CONF_LATITUDE: '32.87336', ha.CONF_LONGITUDE: 'wrong'
+ CONF_LATITUDE: '32.87336', CONF_LONGITUDE: 'wrong'
}}))
# Test with correct config
self.assertTrue(sun.setup(
self.hass, {ha.DOMAIN: {
- ha.CONF_LATITUDE: '32.87336', ha.CONF_LONGITUDE: '117.22743'
+ CONF_LATITUDE: '32.87336', CONF_LONGITUDE: '117.22743'
}}))
diff --git a/ha_test/test_component_switch.py b/ha_test/test_component_switch.py
index 0df05f0617ba24..daab9cde4d1ac6 100644
--- a/ha_test/test_component_switch.py
+++ b/ha_test/test_component_switch.py
@@ -9,10 +9,10 @@
import homeassistant as ha
import homeassistant.loader as loader
-from homeassistant.components import get_component, STATE_ON, STATE_OFF
+from homeassistant.const import STATE_ON, STATE_OFF, CONF_PLATFORM
import homeassistant.components.switch as switch
-from helper import get_test_home_assistant
+from helpers import get_test_home_assistant
class TestSwitch(unittest.TestCase):
@@ -22,11 +22,11 @@ def setUp(self): # pylint: disable=invalid-name
self.hass = get_test_home_assistant()
loader.prepare(self.hass)
- platform = get_component('switch.test')
+ platform = loader.get_component('switch.test')
platform.init()
self.assertTrue(switch.setup(
- self.hass, {switch.DOMAIN: {ha.CONF_TYPE: 'test'}}
+ self.hass, {switch.DOMAIN: {CONF_PLATFORM: 'test'}}
))
# Switch 1 is ON, switch 2 is OFF
@@ -90,15 +90,27 @@ def test_setup(self):
# Test with non-existing component
self.assertFalse(switch.setup(
- self.hass, {switch.DOMAIN: {ha.CONF_TYPE: 'nonexisting'}}
+ self.hass, {switch.DOMAIN: {CONF_PLATFORM: 'nonexisting'}}
))
# Test if switch component returns 0 switches
- get_component('switch.test').init(True)
+ test_platform = loader.get_component('switch.test')
+ test_platform.init(True)
self.assertEqual(
- [], get_component('switch.test').get_switches(None, None))
+ [], test_platform.get_switches(None, None))
self.assertFalse(switch.setup(
- self.hass, {switch.DOMAIN: {ha.CONF_TYPE: 'test'}}
+ self.hass, {switch.DOMAIN: {CONF_PLATFORM: 'test'}}
+ ))
+
+ # Test if we can load 2 platforms
+ loader.set_component('switch.test2', test_platform)
+ test_platform.init(False)
+
+ self.assertTrue(switch.setup(
+ self.hass, {
+ switch.DOMAIN: {CONF_PLATFORM: 'test'},
+ '{} 2'.format(switch.DOMAIN): {CONF_PLATFORM: 'test2'},
+ }
))
diff --git a/ha_test/test_helpers.py b/ha_test/test_helpers.py
new file mode 100644
index 00000000000000..f61204c837f81f
--- /dev/null
+++ b/ha_test/test_helpers.py
@@ -0,0 +1,49 @@
+"""
+ha_test.test_helpers
+~~~~~~~~~~~~~~~~~~~~
+
+Tests component helpers.
+"""
+# pylint: disable=protected-access,too-many-public-methods
+import unittest
+
+from helpers import get_test_home_assistant
+
+import homeassistant as ha
+import homeassistant.loader as loader
+from homeassistant.const import STATE_ON, STATE_OFF, ATTR_ENTITY_ID
+from homeassistant.helpers import extract_entity_ids
+
+
+class TestComponentsCore(unittest.TestCase):
+ """ Tests homeassistant.components module. """
+
+ def setUp(self): # pylint: disable=invalid-name
+ """ Init needed objects. """
+ self.hass = get_test_home_assistant()
+ loader.prepare(self.hass)
+
+ self.hass.states.set('light.Bowl', STATE_ON)
+ self.hass.states.set('light.Ceiling', STATE_OFF)
+ self.hass.states.set('light.Kitchen', STATE_OFF)
+
+ loader.get_component('group').setup_group(
+ self.hass, 'test', ['light.Ceiling', 'light.Kitchen'])
+
+ def tearDown(self): # pylint: disable=invalid-name
+ """ Stop down stuff we started. """
+ self.hass.stop()
+
+ def test_extract_entity_ids(self):
+ """ Test extract_entity_ids method. """
+ call = ha.ServiceCall('light', 'turn_on',
+ {ATTR_ENTITY_ID: 'light.Bowl'})
+
+ self.assertEqual(['light.Bowl'],
+ extract_entity_ids(self.hass, call))
+
+ call = ha.ServiceCall('light', 'turn_on',
+ {ATTR_ENTITY_ID: 'group.test'})
+
+ self.assertEqual(['light.Ceiling', 'light.Kitchen'],
+ extract_entity_ids(self.hass, call))
diff --git a/ha_test/test_loader.py b/ha_test/test_loader.py
index 4d9bc190145a72..b7ae75c0e2a6f6 100644
--- a/ha_test/test_loader.py
+++ b/ha_test/test_loader.py
@@ -10,7 +10,7 @@
import homeassistant.loader as loader
import homeassistant.components.http as http
-from helper import get_test_home_assistant, MockModule
+from helpers import get_test_home_assistant, MockModule
class TestLoader(unittest.TestCase):
diff --git a/homeassistant/__init__.py b/homeassistant/__init__.py
index 6fbe1a2c3e3d25..74f27b9f6f5a42 100644
--- a/homeassistant/__init__.py
+++ b/homeassistant/__init__.py
@@ -15,32 +15,14 @@
import datetime as dt
import functools as ft
+from homeassistant.const import (
+ EVENT_HOMEASSISTANT_START, EVENT_HOMEASSISTANT_STOP,
+ SERVICE_HOMEASSISTANT_STOP, EVENT_TIME_CHANGED, EVENT_STATE_CHANGED,
+ EVENT_CALL_SERVICE, ATTR_NOW, ATTR_DOMAIN, ATTR_SERVICE, MATCH_ALL)
import homeassistant.util as util
-MATCH_ALL = '*'
-
DOMAIN = "homeassistant"
-SERVICE_HOMEASSISTANT_STOP = "stop"
-
-EVENT_HOMEASSISTANT_START = "homeassistant_start"
-EVENT_HOMEASSISTANT_STOP = "homeassistant_stop"
-EVENT_STATE_CHANGED = "state_changed"
-EVENT_TIME_CHANGED = "time_changed"
-EVENT_CALL_SERVICE = "services.call"
-
-ATTR_NOW = "now"
-ATTR_DOMAIN = "domain"
-ATTR_SERVICE = "service"
-
-CONF_LATITUDE = "latitude"
-CONF_LONGITUDE = "longitude"
-CONF_TYPE = "type"
-CONF_HOST = "host"
-CONF_HOSTS = "hosts"
-CONF_USERNAME = "username"
-CONF_PASSWORD = "password"
-
# How often time_changed event should fire
TIMER_INTERVAL = 10 # seconds
diff --git a/homeassistant/bootstrap.py b/homeassistant/bootstrap.py
index 3875c23b4ce0c5..7675d3f12f32ed 100644
--- a/homeassistant/bootstrap.py
+++ b/homeassistant/bootstrap.py
@@ -37,8 +37,9 @@ def from_config_dict(config, hass=None):
# Convert it to defaultdict so components can always have config dict
config = defaultdict(dict, config)
- # Filter out the common config section [homeassistant]
- components = (key for key in config.keys() if key != homeassistant.DOMAIN)
+ # Filter out the repeating and common config section [homeassistant]
+ components = (key for key in config.keys()
+ if ' ' not in key and key != homeassistant.DOMAIN)
# Setup the components
if core_components.setup(hass, config):
diff --git a/homeassistant/components/__init__.py b/homeassistant/components/__init__.py
index 3acaf11a4fd035..0680b5c67af7c4 100644
--- a/homeassistant/components/__init__.py
+++ b/homeassistant/components/__init__.py
@@ -19,36 +19,10 @@
import homeassistant as ha
import homeassistant.util as util
+from homeassistant.helpers import extract_entity_ids
from homeassistant.loader import get_component
-
-# Contains one string or a list of strings, each being an entity id
-ATTR_ENTITY_ID = 'entity_id'
-
-# String with a friendly name for the entity
-ATTR_FRIENDLY_NAME = "friendly_name"
-
-# A picture to represent entity
-ATTR_ENTITY_PICTURE = "entity_picture"
-
-# The unit of measurement if applicable
-ATTR_UNIT_OF_MEASUREMENT = "unit_of_measurement"
-
-STATE_ON = 'on'
-STATE_OFF = 'off'
-STATE_HOME = 'home'
-STATE_NOT_HOME = 'not_home'
-
-SERVICE_TURN_ON = 'turn_on'
-SERVICE_TURN_OFF = 'turn_off'
-
-SERVICE_VOLUME_UP = "volume_up"
-SERVICE_VOLUME_DOWN = "volume_down"
-SERVICE_VOLUME_MUTE = "volume_mute"
-SERVICE_MEDIA_PLAY_PAUSE = "media_play_pause"
-SERVICE_MEDIA_PLAY = "media_play"
-SERVICE_MEDIA_PAUSE = "media_pause"
-SERVICE_MEDIA_NEXT_TRACK = "media_next_track"
-SERVICE_MEDIA_PREV_TRACK = "media_prev_track"
+from homeassistant.const import (
+ ATTR_ENTITY_ID, SERVICE_TURN_ON, SERVICE_TURN_OFF)
_LOGGER = logging.getLogger(__name__)
@@ -96,79 +70,6 @@ def turn_off(hass, entity_id=None, **service_data):
hass.services.call(ha.DOMAIN, SERVICE_TURN_OFF, service_data)
-def extract_entity_ids(hass, service):
- """
- Helper method to extract a list of entity ids from a service call.
- Will convert group entity ids to the entity ids it represents.
- """
- entity_ids = []
-
- if service.data and ATTR_ENTITY_ID in service.data:
- group = get_component('group')
-
- # Entity ID attr can be a list or a string
- service_ent_id = service.data[ATTR_ENTITY_ID]
- if isinstance(service_ent_id, list):
- ent_ids = service_ent_id
- else:
- ent_ids = [service_ent_id]
-
- entity_ids.extend(
- ent_id for ent_id
- in group.expand_entity_ids(hass, ent_ids)
- if ent_id not in entity_ids)
-
- return entity_ids
-
-
-class ToggleDevice(object):
- """ ABC for devices that can be turned on and off. """
- # pylint: disable=no-self-use
-
- entity_id = None
-
- def get_name(self):
- """ Returns the name of the device if any. """
- return None
-
- def turn_on(self, **kwargs):
- """ Turn the device on. """
- pass
-
- def turn_off(self, **kwargs):
- """ Turn the device off. """
- pass
-
- def is_on(self):
- """ True if device is on. """
- return False
-
- def get_state_attributes(self):
- """ Returns optional state attributes. """
- return {}
-
- def update(self):
- """ Retrieve latest state from the real device. """
- pass
-
- def update_ha_state(self, hass, force_refresh=False):
- """
- Updates Home Assistant with current state of device.
- If force_refresh == True will update device before setting state.
- """
- if self.entity_id is None:
- raise ha.NoEntitySpecifiedError(
- "No entity specified for device {}".format(self.get_name()))
-
- if force_refresh:
- self.update()
-
- state = STATE_ON if self.is_on() else STATE_OFF
-
- return hass.states.set(self.entity_id, state,
- self.get_state_attributes())
-
-
# pylint: disable=unused-argument
def setup(hass, config):
""" Setup general services related to homeassistant. """
diff --git a/homeassistant/components/chromecast.py b/homeassistant/components/chromecast.py
index d6e9971dc0d6f4..fc5f7e73dc3d81 100644
--- a/homeassistant/components/chromecast.py
+++ b/homeassistant/components/chromecast.py
@@ -6,9 +6,14 @@
"""
import logging
-import homeassistant as ha
import homeassistant.util as util
-import homeassistant.components as components
+from homeassistant.helpers import extract_entity_ids
+from homeassistant.const import (
+ ATTR_ENTITY_ID, ATTR_FRIENDLY_NAME, SERVICE_TURN_OFF, SERVICE_VOLUME_UP,
+ SERVICE_VOLUME_DOWN, SERVICE_MEDIA_PLAY_PAUSE, SERVICE_MEDIA_PLAY,
+ SERVICE_MEDIA_PAUSE, SERVICE_MEDIA_NEXT_TRACK, SERVICE_MEDIA_PREV_TRACK,
+ CONF_HOSTS)
+
DOMAIN = 'chromecast'
DEPENDENCIES = []
@@ -46,58 +51,58 @@ def is_on(hass, entity_id=None):
def turn_off(hass, entity_id=None):
""" Will turn off specified Chromecast or all. """
- data = {components.ATTR_ENTITY_ID: entity_id} if entity_id else {}
+ data = {ATTR_ENTITY_ID: entity_id} if entity_id else {}
- hass.services.call(DOMAIN, components.SERVICE_TURN_OFF, data)
+ hass.services.call(DOMAIN, SERVICE_TURN_OFF, data)
def volume_up(hass, entity_id=None):
""" Send the chromecast the command for volume up. """
- data = {components.ATTR_ENTITY_ID: entity_id} if entity_id else {}
+ data = {ATTR_ENTITY_ID: entity_id} if entity_id else {}
- hass.services.call(DOMAIN, components.SERVICE_VOLUME_UP, data)
+ hass.services.call(DOMAIN, SERVICE_VOLUME_UP, data)
def volume_down(hass, entity_id=None):
""" Send the chromecast the command for volume down. """
- data = {components.ATTR_ENTITY_ID: entity_id} if entity_id else {}
+ data = {ATTR_ENTITY_ID: entity_id} if entity_id else {}
- hass.services.call(DOMAIN, components.SERVICE_VOLUME_DOWN, data)
+ hass.services.call(DOMAIN, SERVICE_VOLUME_DOWN, data)
def media_play_pause(hass, entity_id=None):
""" Send the chromecast the command for play/pause. """
- data = {components.ATTR_ENTITY_ID: entity_id} if entity_id else {}
+ data = {ATTR_ENTITY_ID: entity_id} if entity_id else {}
- hass.services.call(DOMAIN, components.SERVICE_MEDIA_PLAY_PAUSE, data)
+ hass.services.call(DOMAIN, SERVICE_MEDIA_PLAY_PAUSE, data)
def media_play(hass, entity_id=None):
""" Send the chromecast the command for play/pause. """
- data = {components.ATTR_ENTITY_ID: entity_id} if entity_id else {}
+ data = {ATTR_ENTITY_ID: entity_id} if entity_id else {}
- hass.services.call(DOMAIN, components.SERVICE_MEDIA_PLAY, data)
+ hass.services.call(DOMAIN, SERVICE_MEDIA_PLAY, data)
def media_pause(hass, entity_id=None):
""" Send the chromecast the command for play/pause. """
- data = {components.ATTR_ENTITY_ID: entity_id} if entity_id else {}
+ data = {ATTR_ENTITY_ID: entity_id} if entity_id else {}
- hass.services.call(DOMAIN, components.SERVICE_MEDIA_PAUSE, data)
+ hass.services.call(DOMAIN, SERVICE_MEDIA_PAUSE, data)
def media_next_track(hass, entity_id=None):
""" Send the chromecast the command for next track. """
- data = {components.ATTR_ENTITY_ID: entity_id} if entity_id else {}
+ data = {ATTR_ENTITY_ID: entity_id} if entity_id else {}
- hass.services.call(DOMAIN, components.SERVICE_MEDIA_NEXT_TRACK, data)
+ hass.services.call(DOMAIN, SERVICE_MEDIA_NEXT_TRACK, data)
def media_prev_track(hass, entity_id=None):
""" Send the chromecast the command for prev track. """
- data = {components.ATTR_ENTITY_ID: entity_id} if entity_id else {}
+ data = {ATTR_ENTITY_ID: entity_id} if entity_id else {}
- hass.services.call(DOMAIN, components.SERVICE_MEDIA_PREV_TRACK, data)
+ hass.services.call(DOMAIN, SERVICE_MEDIA_PREV_TRACK, data)
# pylint: disable=too-many-locals, too-many-branches
@@ -114,8 +119,8 @@ def setup(hass, config):
return False
- if ha.CONF_HOSTS in config[DOMAIN]:
- hosts = config[DOMAIN][ha.CONF_HOSTS].split(",")
+ if CONF_HOSTS in config[DOMAIN]:
+ hosts = config[DOMAIN][CONF_HOSTS].split(",")
# If no hosts given, scan for chromecasts
else:
@@ -131,7 +136,7 @@ def setup(hass, config):
entity_id = util.ensure_unique_string(
ENTITY_ID_FORMAT.format(
util.slugify(cast.device.friendly_name)),
- list(casts.keys()))
+ casts.keys())
casts[entity_id] = cast
@@ -148,7 +153,7 @@ def update_chromecast_state(entity_id, chromecast):
status = chromecast.app
- state_attr = {components.ATTR_FRIENDLY_NAME:
+ state_attr = {ATTR_FRIENDLY_NAME:
chromecast.device.friendly_name}
if status and status.app_id != pychromecast.APP_ID['HOME']:
@@ -196,7 +201,7 @@ def update_chromecast_states(time): # pylint: disable=unused-argument
def _service_to_entities(service):
""" Helper method to get entities from service. """
- entity_ids = components.extract_entity_ids(hass, service)
+ entity_ids = extract_entity_ids(hass, service)
if entity_ids:
for entity_id in entity_ids:
@@ -274,25 +279,25 @@ def play_youtube_video_service(service, video_id):
hass.track_time_change(update_chromecast_states)
- hass.services.register(DOMAIN, components.SERVICE_TURN_OFF,
+ hass.services.register(DOMAIN, SERVICE_TURN_OFF,
turn_off_service)
- hass.services.register(DOMAIN, components.SERVICE_VOLUME_UP,
+ hass.services.register(DOMAIN, SERVICE_VOLUME_UP,
volume_up_service)
- hass.services.register(DOMAIN, components.SERVICE_VOLUME_DOWN,
+ hass.services.register(DOMAIN, SERVICE_VOLUME_DOWN,
volume_down_service)
- hass.services.register(DOMAIN, components.SERVICE_MEDIA_PLAY_PAUSE,
+ hass.services.register(DOMAIN, SERVICE_MEDIA_PLAY_PAUSE,
media_play_pause_service)
- hass.services.register(DOMAIN, components.SERVICE_MEDIA_PLAY,
+ hass.services.register(DOMAIN, SERVICE_MEDIA_PLAY,
media_play_service)
- hass.services.register(DOMAIN, components.SERVICE_MEDIA_PAUSE,
+ hass.services.register(DOMAIN, SERVICE_MEDIA_PAUSE,
media_pause_service)
- hass.services.register(DOMAIN, components.SERVICE_MEDIA_NEXT_TRACK,
+ hass.services.register(DOMAIN, SERVICE_MEDIA_NEXT_TRACK,
media_next_track_service)
hass.services.register(DOMAIN, "start_fireplace",
diff --git a/homeassistant/components/demo.py b/homeassistant/components/demo.py
index ca04d90e7fc1a5..3bd7d2f1e33706 100644
--- a/homeassistant/components/demo.py
+++ b/homeassistant/components/demo.py
@@ -8,9 +8,10 @@
import homeassistant as ha
import homeassistant.loader as loader
-from homeassistant.components import (
+from homeassistant.helpers import extract_entity_ids
+from homeassistant.const import (
SERVICE_TURN_ON, SERVICE_TURN_OFF, STATE_ON, STATE_OFF,
- ATTR_ENTITY_PICTURE, ATTR_ENTITY_ID, extract_entity_ids)
+ ATTR_ENTITY_PICTURE, ATTR_ENTITY_ID, CONF_LATITUDE, CONF_LONGITUDE)
from homeassistant.components.light import (
ATTR_XY_COLOR, ATTR_BRIGHTNESS, GROUP_NAME_ALL_LIGHTS)
from homeassistant.util import split_entity_id
@@ -65,11 +66,11 @@ def mock_turn_off(service):
hass.states.set(entity_id, STATE_OFF)
# Setup sun
- if ha.CONF_LATITUDE not in config[ha.DOMAIN]:
- config[ha.DOMAIN][ha.CONF_LATITUDE] = '32.87336'
+ if CONF_LATITUDE not in config[ha.DOMAIN]:
+ config[ha.DOMAIN][CONF_LATITUDE] = '32.87336'
- if ha.CONF_LONGITUDE not in config[ha.DOMAIN]:
- config[ha.DOMAIN][ha.CONF_LONGITUDE] = '-117.22743'
+ if CONF_LONGITUDE not in config[ha.DOMAIN]:
+ config[ha.DOMAIN][CONF_LONGITUDE] = '-117.22743'
loader.get_component('sun').setup(hass, config)
diff --git a/homeassistant/components/device_sun_light_trigger.py b/homeassistant/components/device_sun_light_trigger.py
index 5e2b99e64a715c..5136340832fb53 100644
--- a/homeassistant/components/device_sun_light_trigger.py
+++ b/homeassistant/components/device_sun_light_trigger.py
@@ -8,7 +8,7 @@
import logging
from datetime import datetime, timedelta
-import homeassistant.components as components
+from homeassistant.const import STATE_HOME, STATE_NOT_HOME
from . import light, sun, device_tracker, group
DOMAIN = "device_sun_light_trigger"
@@ -108,7 +108,7 @@ def check_light_on_dev_state_change(entity, old_state, new_state):
# Specific device came home ?
if entity != device_tracker.ENTITY_ID_ALL_DEVICES and \
- new_state.state == components.STATE_HOME:
+ new_state.state == STATE_HOME:
# These variables are needed for the elif check
now = datetime.now()
@@ -143,7 +143,7 @@ def check_light_on_dev_state_change(entity, old_state, new_state):
# Did all devices leave the house?
elif (entity == device_tracker.ENTITY_ID_ALL_DEVICES and
- new_state.state == components.STATE_NOT_HOME and lights_are_on
+ new_state.state == STATE_NOT_HOME and lights_are_on
and not disable_turn_off):
logger.info(
@@ -154,12 +154,12 @@ def check_light_on_dev_state_change(entity, old_state, new_state):
# Track home coming of each device
hass.states.track_change(
device_entity_ids, check_light_on_dev_state_change,
- components.STATE_NOT_HOME, components.STATE_HOME)
+ STATE_NOT_HOME, STATE_HOME)
# Track when all devices are gone to shut down lights
hass.states.track_change(
device_tracker.ENTITY_ID_ALL_DEVICES,
check_light_on_dev_state_change,
- components.STATE_HOME, components.STATE_NOT_HOME)
+ STATE_HOME, STATE_NOT_HOME)
return True
diff --git a/homeassistant/components/device_tracker/__init__.py b/homeassistant/components/device_tracker/__init__.py
index 08f1abd9ff12d3..fa96a5b3c2815b 100644
--- a/homeassistant/components/device_tracker/__init__.py
+++ b/homeassistant/components/device_tracker/__init__.py
@@ -10,12 +10,14 @@
import csv
from datetime import datetime, timedelta
-import homeassistant as ha
from homeassistant.loader import get_component
+from homeassistant.helpers import validate_config
import homeassistant.util as util
-from homeassistant.components import (
- group, STATE_HOME, STATE_NOT_HOME, ATTR_ENTITY_PICTURE, ATTR_FRIENDLY_NAME)
+from homeassistant.const import (
+ STATE_HOME, STATE_NOT_HOME, ATTR_ENTITY_PICTURE, ATTR_FRIENDLY_NAME,
+ CONF_PLATFORM, CONF_TYPE)
+from homeassistant.components import group
DOMAIN = "device_tracker"
DEPENDENCIES = []
@@ -49,10 +51,20 @@ def is_on(hass, entity_id=None):
def setup(hass, config):
""" Sets up the device tracker. """
- if not util.validate_config(config, {DOMAIN: [ha.CONF_TYPE]}, _LOGGER):
+ # CONF_TYPE is deprecated for CONF_PLATOFRM. We keep supporting it for now.
+ if not (validate_config(config, {DOMAIN: [CONF_PLATFORM]}, _LOGGER)
+ or validate_config(config, {DOMAIN: [CONF_TYPE]}, _LOGGER)):
+
return False
- tracker_type = config[DOMAIN][ha.CONF_TYPE]
+ tracker_type = config[DOMAIN].get(CONF_PLATFORM)
+
+ if tracker_type is None:
+ tracker_type = config[DOMAIN][CONF_TYPE]
+
+ _LOGGER.warning((
+ "Please update your config for %s to use 'platform' "
+ "instead of 'type'"), tracker_type)
tracker_implementation = get_component(
'device_tracker.{}'.format(tracker_type))
diff --git a/homeassistant/components/device_tracker/luci.py b/homeassistant/components/device_tracker/luci.py
index dba41c11c031bf..9ed73f21375aa4 100644
--- a/homeassistant/components/device_tracker/luci.py
+++ b/homeassistant/components/device_tracker/luci.py
@@ -6,8 +6,9 @@
import threading
import requests
-import homeassistant as ha
-import homeassistant.util as util
+from homeassistant.const import CONF_HOST, CONF_USERNAME, CONF_PASSWORD
+from homeassistant.helpers import validate_config
+from homeassistant.util import Throttle
from homeassistant.components.device_tracker import DOMAIN
# Return cached results if last scan was less then this time ago
@@ -19,10 +20,9 @@
# pylint: disable=unused-argument
def get_scanner(hass, config):
""" Validates config and returns a Luci scanner. """
- if not util.validate_config(config,
- {DOMAIN: [ha.CONF_HOST, ha.CONF_USERNAME,
- ha.CONF_PASSWORD]},
- _LOGGER):
+ if not validate_config(config,
+ {DOMAIN: [CONF_HOST, CONF_USERNAME, CONF_PASSWORD]},
+ _LOGGER):
return None
scanner = LuciDeviceScanner(config[DOMAIN])
@@ -45,8 +45,8 @@ class LuciDeviceScanner(object):
"""
def __init__(self, config):
- host = config[ha.CONF_HOST]
- username, password = config[ha.CONF_USERNAME], config[ha.CONF_PASSWORD]
+ host = config[CONF_HOST]
+ username, password = config[CONF_USERNAME], config[CONF_PASSWORD]
self.parse_api_pattern = re.compile(r"(?P\w*) = (?P.*);")
@@ -87,7 +87,7 @@ def get_device_name(self, device):
return
return self.mac2name.get(device, None)
- @util.Throttle(MIN_TIME_BETWEEN_SCANS)
+ @Throttle(MIN_TIME_BETWEEN_SCANS)
def _update_info(self):
""" Ensures the information from the Luci router is up to date.
Returns boolean if scanning successful. """
diff --git a/homeassistant/components/device_tracker/netgear.py b/homeassistant/components/device_tracker/netgear.py
index a57e2f28c7034a..0b0f1107b21536 100644
--- a/homeassistant/components/device_tracker/netgear.py
+++ b/homeassistant/components/device_tracker/netgear.py
@@ -3,8 +3,9 @@
from datetime import timedelta
import threading
-import homeassistant as ha
-import homeassistant.util as util
+from homeassistant.const import CONF_HOST, CONF_USERNAME, CONF_PASSWORD
+from homeassistant.helpers import validate_config
+from homeassistant.util import Throttle
from homeassistant.components.device_tracker import DOMAIN
# Return cached results if last scan was less then this time ago
@@ -16,10 +17,9 @@
# pylint: disable=unused-argument
def get_scanner(hass, config):
""" Validates config and returns a Netgear scanner. """
- if not util.validate_config(config,
- {DOMAIN: [ha.CONF_HOST, ha.CONF_USERNAME,
- ha.CONF_PASSWORD]},
- _LOGGER):
+ if not validate_config(config,
+ {DOMAIN: [CONF_HOST, CONF_USERNAME, CONF_PASSWORD]},
+ _LOGGER):
return None
scanner = NetgearDeviceScanner(config[DOMAIN])
@@ -31,8 +31,8 @@ class NetgearDeviceScanner(object):
""" This class queries a Netgear wireless router using the SOAP-api. """
def __init__(self, config):
- host = config[ha.CONF_HOST]
- username, password = config[ha.CONF_USERNAME], config[ha.CONF_PASSWORD]
+ host = config[CONF_HOST]
+ username, password = config[CONF_USERNAME], config[CONF_PASSWORD]
self.last_results = []
@@ -82,7 +82,7 @@ def get_device_name(self, mac):
else:
return None
- @util.Throttle(MIN_TIME_BETWEEN_SCANS)
+ @Throttle(MIN_TIME_BETWEEN_SCANS)
def _update_info(self):
""" Retrieves latest information from the Netgear router.
Returns boolean if scanning successful. """
diff --git a/homeassistant/components/device_tracker/tomato.py b/homeassistant/components/device_tracker/tomato.py
index c3b7e5dec940c5..81755f42c6608a 100644
--- a/homeassistant/components/device_tracker/tomato.py
+++ b/homeassistant/components/device_tracker/tomato.py
@@ -7,8 +7,9 @@
import requests
-import homeassistant as ha
-import homeassistant.util as util
+from homeassistant.const import CONF_HOST, CONF_USERNAME, CONF_PASSWORD
+from homeassistant.helpers import validate_config
+from homeassistant.util import Throttle
from homeassistant.components.device_tracker import DOMAIN
# Return cached results if last scan was less then this time ago
@@ -22,10 +23,10 @@
# pylint: disable=unused-argument
def get_scanner(hass, config):
""" Validates config and returns a Tomato scanner. """
- if not util.validate_config(config,
- {DOMAIN: [ha.CONF_HOST, ha.CONF_USERNAME,
- ha.CONF_PASSWORD, CONF_HTTP_ID]},
- _LOGGER):
+ if not validate_config(config,
+ {DOMAIN: [CONF_HOST, CONF_USERNAME,
+ CONF_PASSWORD, CONF_HTTP_ID]},
+ _LOGGER):
return None
return TomatoDeviceScanner(config[DOMAIN])
@@ -40,8 +41,8 @@ class TomatoDeviceScanner(object):
"""
def __init__(self, config):
- host, http_id = config[ha.CONF_HOST], config[CONF_HTTP_ID]
- username, password = config[ha.CONF_USERNAME], config[ha.CONF_PASSWORD]
+ host, http_id = config[CONF_HOST], config[CONF_HTTP_ID]
+ username, password = config[CONF_USERNAME], config[CONF_PASSWORD]
self.req = requests.Request('POST',
'http://{}/update.cgi'.format(host),
@@ -78,7 +79,7 @@ def get_device_name(self, device):
else:
return filter_named[0]
- @util.Throttle(MIN_TIME_BETWEEN_SCANS)
+ @Throttle(MIN_TIME_BETWEEN_SCANS)
def _update_tomato_info(self):
""" Ensures the information from the Tomato router is up to date.
Returns boolean if scanning successful. """
diff --git a/homeassistant/components/downloader.py b/homeassistant/components/downloader.py
index 362f7d43e0488d..6978dbd7fa9cec 100644
--- a/homeassistant/components/downloader.py
+++ b/homeassistant/components/downloader.py
@@ -9,7 +9,8 @@
import re
import threading
-import homeassistant.util as util
+from homeassistant.helpers import validate_config
+from homeassistant.util import sanitize_filename
DOMAIN = "downloader"
DEPENDENCIES = []
@@ -36,7 +37,7 @@ def setup(hass, config):
return False
- if not util.validate_config(config, {DOMAIN: [CONF_DOWNLOAD_DIR]}, logger):
+ if not validate_config(config, {DOMAIN: [CONF_DOWNLOAD_DIR]}, logger):
return False
download_path = config[DOMAIN][CONF_DOWNLOAD_DIR]
@@ -64,7 +65,7 @@ def do_download():
subdir = service.data.get(ATTR_SUBDIR)
if subdir:
- subdir = util.sanitize_filename(subdir)
+ subdir = sanitize_filename(subdir)
final_path = None
@@ -88,7 +89,7 @@ def do_download():
filename = "ha_download"
# Remove stuff to ruin paths
- filename = util.sanitize_filename(filename)
+ filename = sanitize_filename(filename)
# Do we want to download to subdir, create if needed
if subdir:
diff --git a/homeassistant/components/group.py b/homeassistant/components/group.py
index f0ce5cc0f9434f..59033b02b688c1 100644
--- a/homeassistant/components/group.py
+++ b/homeassistant/components/group.py
@@ -9,9 +9,8 @@
import homeassistant as ha
import homeassistant.util as util
-from homeassistant.components import (STATE_ON, STATE_OFF,
- STATE_HOME, STATE_NOT_HOME,
- ATTR_ENTITY_ID)
+from homeassistant.const import (
+ ATTR_ENTITY_ID, STATE_ON, STATE_OFF, STATE_HOME, STATE_NOT_HOME)
DOMAIN = "group"
DEPENDENCIES = []
diff --git a/homeassistant/components/http/__init__.py b/homeassistant/components/http/__init__.py
index 02a1bea0272cbf..0149130c0fcc57 100644
--- a/homeassistant/components/http/__init__.py
+++ b/homeassistant/components/http/__init__.py
@@ -83,6 +83,10 @@
from urllib.parse import urlparse, parse_qs
import homeassistant as ha
+from homeassistant.const import (
+ SERVER_PORT, URL_API, URL_API_STATES, URL_API_EVENTS, URL_API_SERVICES,
+ URL_API_EVENT_FORWARD, URL_API_STATES_ENTITY, AUTH_HEADER)
+from homeassistant.helpers import validate_config
import homeassistant.remote as rem
import homeassistant.util as util
from . import frontend
@@ -116,8 +120,7 @@
def setup(hass, config):
""" Sets up the HTTP API and debug interface. """
- if not util.validate_config(config, {DOMAIN: [CONF_API_PASSWORD]},
- _LOGGER):
+ if not validate_config(config, {DOMAIN: [CONF_API_PASSWORD]}, _LOGGER):
return False
api_password = config[DOMAIN][CONF_API_PASSWORD]
@@ -125,7 +128,7 @@ def setup(hass, config):
# If no server host is given, accept all incoming requests
server_host = config[DOMAIN].get(CONF_SERVER_HOST, '0.0.0.0')
- server_port = config[DOMAIN].get(CONF_SERVER_PORT, rem.SERVER_PORT)
+ server_port = config[DOMAIN].get(CONF_SERVER_PORT, SERVER_PORT)
development = config[DOMAIN].get(CONF_DEVELOPMENT, "") == "1"
@@ -196,10 +199,10 @@ class RequestHandler(SimpleHTTPRequestHandler):
('GET', URL_ROOT, '_handle_get_root'),
# /api - for validation purposes
- ('GET', rem.URL_API, '_handle_get_api'),
+ ('GET', URL_API, '_handle_get_api'),
# /states
- ('GET', rem.URL_API_STATES, '_handle_get_api_states'),
+ ('GET', URL_API_STATES, '_handle_get_api_states'),
('GET',
re.compile(r'/api/states/(?P[a-zA-Z\._0-9]+)'),
'_handle_get_api_states_entity'),
@@ -211,13 +214,13 @@ class RequestHandler(SimpleHTTPRequestHandler):
'_handle_post_state_entity'),
# /events
- ('GET', rem.URL_API_EVENTS, '_handle_get_api_events'),
+ ('GET', URL_API_EVENTS, '_handle_get_api_events'),
('POST',
re.compile(r'/api/events/(?P[a-zA-Z\._0-9]+)'),
'_handle_api_post_events_event'),
# /services
- ('GET', rem.URL_API_SERVICES, '_handle_get_api_services'),
+ ('GET', URL_API_SERVICES, '_handle_get_api_services'),
('POST',
re.compile((r'/api/services/'
r'(?P[a-zA-Z\._0-9]+)/'
@@ -225,8 +228,8 @@ class RequestHandler(SimpleHTTPRequestHandler):
'_handle_post_api_services_domain_service'),
# /event_forwarding
- ('POST', rem.URL_API_EVENT_FORWARD, '_handle_post_api_event_forward'),
- ('DELETE', rem.URL_API_EVENT_FORWARD,
+ ('POST', URL_API_EVENT_FORWARD, '_handle_post_api_event_forward'),
+ ('DELETE', URL_API_EVENT_FORWARD,
'_handle_delete_api_event_forward'),
# Static files
@@ -270,7 +273,7 @@ def _handle_request(self, method): # pylint: disable=too-many-branches
"Error parsing JSON", HTTP_UNPROCESSABLE_ENTITY)
return
- api_password = self.headers.get(rem.AUTH_HEADER)
+ api_password = self.headers.get(AUTH_HEADER)
if not api_password and DATA_API_PASSWORD in data:
api_password = data[DATA_API_PASSWORD]
@@ -427,7 +430,7 @@ def _handle_post_state_entity(self, path_match, data):
self._write_json(
state.as_dict(),
status_code=status_code,
- location=rem.URL_API_STATES_ENTITY.format(entity_id))
+ location=URL_API_STATES_ENTITY.format(entity_id))
def _handle_get_api_events(self, path_match, data):
""" Handles getting overview of event listeners. """
diff --git a/homeassistant/components/keyboard.py b/homeassistant/components/keyboard.py
index e2d156d5c7e9ec..2d8c3995a2fb8d 100644
--- a/homeassistant/components/keyboard.py
+++ b/homeassistant/components/keyboard.py
@@ -1,12 +1,16 @@
"""
-homeassistant.components.keyboard
+homeassistant.keyboard
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Provides functionality to emulate keyboard presses on host machine.
"""
import logging
-import homeassistant.components as components
+from homeassistant.const import (
+ SERVICE_VOLUME_UP, SERVICE_VOLUME_DOWN, SERVICE_VOLUME_MUTE,
+ SERVICE_MEDIA_NEXT_TRACK, SERVICE_MEDIA_PREV_TRACK,
+ SERVICE_MEDIA_PLAY_PAUSE)
+
DOMAIN = "keyboard"
DEPENDENCIES = []
@@ -14,32 +18,32 @@
def volume_up(hass):
""" Press the keyboard button for volume up. """
- hass.services.call(DOMAIN, components.SERVICE_VOLUME_UP)
+ hass.services.call(DOMAIN, SERVICE_VOLUME_UP)
def volume_down(hass):
""" Press the keyboard button for volume down. """
- hass.services.call(DOMAIN, components.SERVICE_VOLUME_DOWN)
+ hass.services.call(DOMAIN, SERVICE_VOLUME_DOWN)
def volume_mute(hass):
""" Press the keyboard button for muting volume. """
- hass.services.call(DOMAIN, components.SERVICE_VOLUME_MUTE)
+ hass.services.call(DOMAIN, SERVICE_VOLUME_MUTE)
def media_play_pause(hass):
""" Press the keyboard button for play/pause. """
- hass.services.call(DOMAIN, components.SERVICE_MEDIA_PLAY_PAUSE)
+ hass.services.call(DOMAIN, SERVICE_MEDIA_PLAY_PAUSE)
def media_next_track(hass):
""" Press the keyboard button for next track. """
- hass.services.call(DOMAIN, components.SERVICE_MEDIA_NEXT_TRACK)
+ hass.services.call(DOMAIN, SERVICE_MEDIA_NEXT_TRACK)
def media_prev_track(hass):
""" Press the keyboard button for prev track. """
- hass.services.call(DOMAIN, components.SERVICE_MEDIA_PREV_TRACK)
+ hass.services.call(DOMAIN, SERVICE_MEDIA_PREV_TRACK)
# pylint: disable=unused-argument
@@ -56,27 +60,27 @@ def setup(hass, config):
keyboard = pykeyboard.PyKeyboard()
keyboard.special_key_assignment()
- hass.services.register(DOMAIN, components.SERVICE_VOLUME_UP,
+ hass.services.register(DOMAIN, SERVICE_VOLUME_UP,
lambda service:
keyboard.tap_key(keyboard.volume_up_key))
- hass.services.register(DOMAIN, components.SERVICE_VOLUME_DOWN,
+ hass.services.register(DOMAIN, SERVICE_VOLUME_DOWN,
lambda service:
keyboard.tap_key(keyboard.volume_down_key))
- hass.services.register(DOMAIN, components.SERVICE_VOLUME_MUTE,
+ hass.services.register(DOMAIN, SERVICE_VOLUME_MUTE,
lambda service:
keyboard.tap_key(keyboard.volume_mute_key))
- hass.services.register(DOMAIN, components.SERVICE_MEDIA_PLAY_PAUSE,
+ hass.services.register(DOMAIN, SERVICE_MEDIA_PLAY_PAUSE,
lambda service:
keyboard.tap_key(keyboard.media_play_pause_key))
- hass.services.register(DOMAIN, components.SERVICE_MEDIA_NEXT_TRACK,
+ hass.services.register(DOMAIN, SERVICE_MEDIA_NEXT_TRACK,
lambda service:
keyboard.tap_key(keyboard.media_next_track_key))
- hass.services.register(DOMAIN, components.SERVICE_MEDIA_PREV_TRACK,
+ hass.services.register(DOMAIN, SERVICE_MEDIA_PREV_TRACK,
lambda service:
keyboard.tap_key(keyboard.media_prev_track_key))
diff --git a/homeassistant/components/light/__init__.py b/homeassistant/components/light/__init__.py
index 957a318ce3c138..55bbdb307f2b12 100644
--- a/homeassistant/components/light/__init__.py
+++ b/homeassistant/components/light/__init__.py
@@ -52,12 +52,12 @@
import os
import csv
-import homeassistant as ha
-from homeassistant.loader import get_component
import homeassistant.util as util
-from homeassistant.components import (
- group, extract_entity_ids, STATE_ON,
- SERVICE_TURN_ON, SERVICE_TURN_OFF, ATTR_ENTITY_ID)
+from homeassistant.const import (
+ STATE_ON, SERVICE_TURN_ON, SERVICE_TURN_OFF, ATTR_ENTITY_ID)
+from homeassistant.helpers import (
+ extract_entity_ids, platform_devices_from_config)
+from homeassistant.components import group
DOMAIN = "light"
@@ -138,9 +138,6 @@ def turn_off(hass, entity_id=None, transition=None):
def setup(hass, config):
""" Exposes light control via statemachine and services. """
- if not util.validate_config(config, {DOMAIN: [ha.CONF_TYPE]}, _LOGGER):
- return False
-
# Load built-in profiles and custom profiles
profile_paths = [os.path.join(os.path.dirname(__file__),
LIGHT_PROFILES_FILE),
@@ -169,20 +166,9 @@ def setup(hass, config):
return False
- # Load platform
- light_type = config[DOMAIN][ha.CONF_TYPE]
-
- light_init = get_component('light.{}'.format(light_type))
-
- if light_init is None:
- _LOGGER.error("Unknown light type specified: %s", light_type)
-
- return False
-
- lights = light_init.get_lights(hass, config[DOMAIN])
+ lights = platform_devices_from_config(config, DOMAIN, hass, _LOGGER)
- if len(lights) == 0:
- _LOGGER.error("No lights found")
+ if not lights:
return False
ent_to_light = {}
@@ -198,7 +184,7 @@ def setup(hass, config):
entity_id = util.ensure_unique_string(
ENTITY_ID_FORMAT.format(util.slugify(name)),
- list(ent_to_light.keys()))
+ ent_to_light.keys())
light.entity_id = entity_id
ent_to_light[entity_id] = light
diff --git a/homeassistant/components/light/hue.py b/homeassistant/components/light/hue.py
index c7db591a4f7d65..19f4034eb392bf 100644
--- a/homeassistant/components/light/hue.py
+++ b/homeassistant/components/light/hue.py
@@ -3,9 +3,9 @@
import socket
from datetime import timedelta
-import homeassistant as ha
import homeassistant.util as util
-from homeassistant.components import ToggleDevice, ATTR_FRIENDLY_NAME
+from homeassistant.helpers import ToggleDevice
+from homeassistant.const import ATTR_FRIENDLY_NAME, CONF_HOST
from homeassistant.components.light import (
ATTR_BRIGHTNESS, ATTR_XY_COLOR, ATTR_TRANSITION)
@@ -15,7 +15,7 @@
PHUE_CONFIG_FILE = "phue.conf"
-def get_lights(hass, config):
+def get_devices(hass, config):
""" Gets the Hue lights. """
logger = logging.getLogger(__name__)
try:
@@ -25,7 +25,7 @@ def get_lights(hass, config):
return []
- host = config.get(ha.CONF_HOST, None)
+ host = config.get(CONF_HOST, None)
try:
bridge = phue.Bridge(
diff --git a/homeassistant/components/process.py b/homeassistant/components/process.py
index 1c0e6b62373e21..5d18557f99865c 100644
--- a/homeassistant/components/process.py
+++ b/homeassistant/components/process.py
@@ -10,7 +10,7 @@
import os
-from homeassistant.components import STATE_ON, STATE_OFF
+from homeassistant.const import STATE_ON, STATE_OFF
import homeassistant.util as util
DOMAIN = 'process'
diff --git a/homeassistant/components/sun.py b/homeassistant/components/sun.py
index c6acbc05230ea2..c6bacb45f876af 100644
--- a/homeassistant/components/sun.py
+++ b/homeassistant/components/sun.py
@@ -8,7 +8,9 @@
from datetime import datetime, timedelta
import homeassistant as ha
-import homeassistant.util as util
+from homeassistant.const import CONF_LATITUDE, CONF_LONGITUDE
+from homeassistant.helpers import validate_config
+from homeassistant.util import str_to_datetime, datetime_to_str
DEPENDENCIES = []
DOMAIN = "sun"
@@ -35,7 +37,7 @@ def next_setting(hass, entity_id=None):
state = hass.states.get(ENTITY_ID)
try:
- return util.str_to_datetime(state.attributes[STATE_ATTR_NEXT_SETTING])
+ return str_to_datetime(state.attributes[STATE_ATTR_NEXT_SETTING])
except (AttributeError, KeyError):
# AttributeError if state is None
# KeyError if STATE_ATTR_NEXT_SETTING does not exist
@@ -49,7 +51,7 @@ def next_rising(hass, entity_id=None):
state = hass.states.get(ENTITY_ID)
try:
- return util.str_to_datetime(state.attributes[STATE_ATTR_NEXT_RISING])
+ return str_to_datetime(state.attributes[STATE_ATTR_NEXT_RISING])
except (AttributeError, KeyError):
# AttributeError if state is None
# KeyError if STATE_ATTR_NEXT_RISING does not exist
@@ -60,10 +62,9 @@ def setup(hass, config):
""" Tracks the state of the sun. """
logger = logging.getLogger(__name__)
- if not util.validate_config(config,
- {ha.DOMAIN: [ha.CONF_LATITUDE,
- ha.CONF_LONGITUDE]},
- logger):
+ if not validate_config(config,
+ {ha.DOMAIN: [CONF_LATITUDE, CONF_LONGITUDE]},
+ logger):
return False
try:
@@ -74,8 +75,8 @@ def setup(hass, config):
sun = ephem.Sun() # pylint: disable=no-member
- latitude = config[ha.DOMAIN][ha.CONF_LATITUDE]
- longitude = config[ha.DOMAIN][ha.CONF_LONGITUDE]
+ latitude = config[ha.DOMAIN][CONF_LATITUDE]
+ longitude = config[ha.DOMAIN][CONF_LONGITUDE]
# Validate latitude and longitude
observer = ephem.Observer()
@@ -123,8 +124,8 @@ def update_sun_state(now):
new_state, next_change.strftime("%H:%M"))
state_attributes = {
- STATE_ATTR_NEXT_RISING: util.datetime_to_str(next_rising_dt),
- STATE_ATTR_NEXT_SETTING: util.datetime_to_str(next_setting_dt)
+ STATE_ATTR_NEXT_RISING: datetime_to_str(next_rising_dt),
+ STATE_ATTR_NEXT_SETTING: datetime_to_str(next_setting_dt)
}
hass.states.set(ENTITY_ID, new_state, state_attributes)
diff --git a/homeassistant/components/switch/__init__.py b/homeassistant/components/switch/__init__.py
index 98da108484e6f7..7f7a70e184207d 100644
--- a/homeassistant/components/switch/__init__.py
+++ b/homeassistant/components/switch/__init__.py
@@ -6,12 +6,12 @@
import logging
from datetime import timedelta
-import homeassistant as ha
import homeassistant.util as util
-from homeassistant.loader import get_component
-from homeassistant.components import (
- group, extract_entity_ids, STATE_ON,
- SERVICE_TURN_ON, SERVICE_TURN_OFF, ATTR_ENTITY_ID)
+from homeassistant.const import (
+ STATE_ON, SERVICE_TURN_ON, SERVICE_TURN_OFF, ATTR_ENTITY_ID)
+from homeassistant.helpers import (
+ extract_entity_ids, platform_devices_from_config)
+from homeassistant.components import group
DOMAIN = 'switch'
DEPENDENCIES = []
@@ -53,27 +53,13 @@ def turn_off(hass, entity_id=None):
hass.services.call(DOMAIN, SERVICE_TURN_OFF, data)
-# pylint: disable=too-many-branches
def setup(hass, config):
""" Track states and offer events for switches. """
logger = logging.getLogger(__name__)
- if not util.validate_config(config, {DOMAIN: [ha.CONF_TYPE]}, logger):
- return False
-
- switch_type = config[DOMAIN][ha.CONF_TYPE]
-
- switch_init = get_component('switch.{}'.format(switch_type))
-
- if switch_init is None:
- logger.error("Error loading switch component %s", switch_type)
-
- return False
-
- switches = switch_init.get_switches(hass, config[DOMAIN])
+ switches = platform_devices_from_config(config, DOMAIN, hass, logger)
- if len(switches) == 0:
- logger.error("No switches found")
+ if not switches:
return False
# Setup a dict mapping entity IDs to devices
@@ -90,7 +76,7 @@ def setup(hass, config):
entity_id = util.ensure_unique_string(
ENTITY_ID_FORMAT.format(util.slugify(name)),
- list(ent_to_switch.keys()))
+ ent_to_switch.keys())
switch.entity_id = entity_id
ent_to_switch[entity_id] = switch
diff --git a/homeassistant/components/switch/tellstick.py b/homeassistant/components/switch/tellstick.py
index b34aea38e67495..54b85b3ecb4f63 100644
--- a/homeassistant/components/switch/tellstick.py
+++ b/homeassistant/components/switch/tellstick.py
@@ -1,7 +1,8 @@
""" Support for Tellstick switches. """
import logging
-from homeassistant.components import ToggleDevice, ATTR_FRIENDLY_NAME
+from homeassistant.helpers import ToggleDevice
+from homeassistant.const import ATTR_FRIENDLY_NAME
try:
import tellcore.constants as tc_constants
@@ -11,7 +12,7 @@
# pylint: disable=unused-argument
-def get_switches(hass, config):
+def get_devices(hass, config):
""" Find and return Tellstick switches. """
try:
import tellcore.telldus as telldus
diff --git a/homeassistant/components/switch/wemo.py b/homeassistant/components/switch/wemo.py
index 5eb3d7c14f02bb..b6392ec0f0cf1a 100644
--- a/homeassistant/components/switch/wemo.py
+++ b/homeassistant/components/switch/wemo.py
@@ -1,12 +1,12 @@
""" Support for WeMo switchces. """
import logging
-import homeassistant as ha
-from homeassistant.components import ToggleDevice, ATTR_FRIENDLY_NAME
+from homeassistant.helpers import ToggleDevice
+from homeassistant.const import ATTR_FRIENDLY_NAME, CONF_HOSTS
# pylint: disable=unused-argument
-def get_switches(hass, config):
+def get_devices(hass, config):
""" Find and return WeMo switches. """
try:
@@ -21,9 +21,9 @@ def get_switches(hass, config):
return []
- if ha.CONF_HOSTS in config:
+ if CONF_HOSTS in config:
switches = (pywemo.device_from_host(host) for host
- in config[ha.CONF_HOSTS].split(","))
+ in config[CONF_HOSTS].split(","))
else:
logging.getLogger(__name__).info("Scanning for WeMo devices")
diff --git a/homeassistant/components/tellstick_sensor.py b/homeassistant/components/tellstick_sensor.py
index 89a32f1218b5ec..e021632095b708 100644
--- a/homeassistant/components/tellstick_sensor.py
+++ b/homeassistant/components/tellstick_sensor.py
@@ -26,8 +26,7 @@
from collections import namedtuple
import homeassistant.util as util
-from homeassistant.components import (ATTR_FRIENDLY_NAME,
- ATTR_UNIT_OF_MEASUREMENT)
+from homeassistant.const import ATTR_FRIENDLY_NAME, ATTR_UNIT_OF_MEASUREMENT
# The domain of your component. Should be equal to the name of your component
DOMAIN = "tellstick_sensor"
diff --git a/homeassistant/const.py b/homeassistant/const.py
new file mode 100644
index 00000000000000..8930ae5649cbb9
--- /dev/null
+++ b/homeassistant/const.py
@@ -0,0 +1,78 @@
+""" Constants used by Home Assistant components. """
+# Can be used to specify a catch all when registering state or event listeners.
+MATCH_ALL = '*'
+
+# #### CONFIG ####
+CONF_LATITUDE = "latitude"
+CONF_LONGITUDE = "longitude"
+
+# This one is deprecated. Use platform instead.
+CONF_TYPE = "type"
+
+CONF_PLATFORM = "platform"
+CONF_HOST = "host"
+CONF_HOSTS = "hosts"
+CONF_USERNAME = "username"
+CONF_PASSWORD = "password"
+
+# #### EVENTS ####
+EVENT_HOMEASSISTANT_START = "homeassistant_start"
+EVENT_HOMEASSISTANT_STOP = "homeassistant_stop"
+EVENT_STATE_CHANGED = "state_changed"
+EVENT_TIME_CHANGED = "time_changed"
+EVENT_CALL_SERVICE = "services.call"
+
+# #### STATES ####
+STATE_ON = 'on'
+STATE_OFF = 'off'
+STATE_HOME = 'home'
+STATE_NOT_HOME = 'not_home'
+
+# #### STATE ATTRIBUTES ####
+# Contains current time for a TIME_CHANGED event
+ATTR_NOW = "now"
+
+# Contains domain, service for a SERVICE_CALL event
+ATTR_DOMAIN = "domain"
+ATTR_SERVICE = "service"
+
+# Contains one string or a list of strings, each being an entity id
+ATTR_ENTITY_ID = 'entity_id'
+
+# String with a friendly name for the entity
+ATTR_FRIENDLY_NAME = "friendly_name"
+
+# A picture to represent entity
+ATTR_ENTITY_PICTURE = "entity_picture"
+
+# The unit of measurement if applicable
+ATTR_UNIT_OF_MEASUREMENT = "unit_of_measurement"
+
+# #### SERVICES ####
+SERVICE_HOMEASSISTANT_STOP = "stop"
+
+SERVICE_TURN_ON = 'turn_on'
+SERVICE_TURN_OFF = 'turn_off'
+
+SERVICE_VOLUME_UP = "volume_up"
+SERVICE_VOLUME_DOWN = "volume_down"
+SERVICE_VOLUME_MUTE = "volume_mute"
+SERVICE_MEDIA_PLAY_PAUSE = "media_play_pause"
+SERVICE_MEDIA_PLAY = "media_play"
+SERVICE_MEDIA_PAUSE = "media_pause"
+SERVICE_MEDIA_NEXT_TRACK = "media_next_track"
+SERVICE_MEDIA_PREV_TRACK = "media_prev_track"
+
+# #### API / REMOTE ####
+SERVER_PORT = 8123
+
+AUTH_HEADER = "HA-access"
+
+URL_API = "/api/"
+URL_API_STATES = "/api/states"
+URL_API_STATES_ENTITY = "/api/states/{}"
+URL_API_EVENTS = "/api/events"
+URL_API_EVENTS_EVENT = "/api/events/{}"
+URL_API_SERVICES = "/api/services"
+URL_API_SERVICES_SERVICE = "/api/services/{}/{}"
+URL_API_EVENT_FORWARD = "/api/event_forwarding"
diff --git a/homeassistant/helpers.py b/homeassistant/helpers.py
new file mode 100644
index 00000000000000..f673cc5345fdc6
--- /dev/null
+++ b/homeassistant/helpers.py
@@ -0,0 +1,176 @@
+"""
+Helper methods for components within Home Assistant.
+"""
+from homeassistant import NoEntitySpecifiedError
+
+from homeassistant.loader import get_component
+from homeassistant.const import (
+ ATTR_ENTITY_ID, STATE_ON, STATE_OFF, CONF_PLATFORM, CONF_TYPE)
+
+
+def extract_entity_ids(hass, service):
+ """
+ Helper method to extract a list of entity ids from a service call.
+ Will convert group entity ids to the entity ids it represents.
+ """
+ entity_ids = []
+
+ if service.data and ATTR_ENTITY_ID in service.data:
+ group = get_component('group')
+
+ # Entity ID attr can be a list or a string
+ service_ent_id = service.data[ATTR_ENTITY_ID]
+ if isinstance(service_ent_id, list):
+ ent_ids = service_ent_id
+ else:
+ ent_ids = [service_ent_id]
+
+ entity_ids.extend(
+ ent_id for ent_id
+ in group.expand_entity_ids(hass, ent_ids)
+ if ent_id not in entity_ids)
+
+ return entity_ids
+
+
+def validate_config(config, items, logger):
+ """
+ Validates if all items are available in the configuration.
+
+ config is the general dictionary with all the configurations.
+ items is a dict with per domain which attributes we require.
+ logger is the logger from the caller to log the errors to.
+
+ Returns True if all required items were found.
+ """
+ errors_found = False
+ for domain in items.keys():
+ config.setdefault(domain, {})
+
+ errors = [item for item in items[domain] if item not in config[domain]]
+
+ if errors:
+ logger.error(
+ "Missing required configuration items in {}: {}".format(
+ domain, ", ".join(errors)))
+
+ errors_found = True
+
+ return not errors_found
+
+
+def config_per_platform(config, domain, logger):
+ """
+ Generator to break a component config into different platforms.
+ For example, will find 'switch', 'switch 2', 'switch 3', .. etc
+ """
+ config_key = domain
+ found = 1
+
+ while config_key in config:
+ platform_config = config[config_key]
+
+ platform_type = platform_config.get(CONF_PLATFORM)
+
+ # DEPRECATED, still supported for now.
+ if platform_type is None:
+ platform_type = platform_config.get(CONF_TYPE)
+
+ if platform_type is not None:
+ logger.warning((
+ 'Please update your config for {}.{} to use "platform" '
+ 'instead of "type"').format(domain, platform_type))
+
+ if platform_type is None:
+ logger.warning('No platform specified for %s', config_key)
+ break
+
+ yield platform_type, platform_config
+
+ found += 1
+ config_key = "{} {}".format(domain, found)
+
+
+def platform_devices_from_config(config, domain, hass, logger):
+ """ Parses the config for specified domain.
+ Loads different platforms and retrieve domains. """
+ devices = []
+
+ for p_type, p_config in config_per_platform(config, domain, logger):
+ platform = get_component('{}.{}'.format(domain, p_type))
+
+ if platform is None:
+ logger.error("Unknown %s type specified: %s", domain, p_type)
+
+ else:
+ try:
+ p_devices = platform.get_devices(hass, p_config)
+ except AttributeError:
+ # DEPRECATED, still supported for now
+ logger.warning(
+ 'Platform %s should migrate to use the method get_devices',
+ p_type)
+
+ if domain == 'light':
+ p_devices = platform.get_lights(hass, p_config)
+ elif domain == 'switch':
+ p_devices = platform.get_switches(hass, p_config)
+ else:
+ raise
+
+ logger.info("Found %d %s %ss", len(p_devices), p_type, domain)
+
+ devices.extend(p_devices)
+
+ if len(devices) == 0:
+ logger.error("No devices found for %s", domain)
+
+ return devices
+
+
+class ToggleDevice(object):
+ """ ABC for devices that can be turned on and off. """
+ # pylint: disable=no-self-use
+
+ entity_id = None
+
+ def get_name(self):
+ """ Returns the name of the device if any. """
+ return None
+
+ def turn_on(self, **kwargs):
+ """ Turn the device on. """
+ pass
+
+ def turn_off(self, **kwargs):
+ """ Turn the device off. """
+ pass
+
+ def is_on(self):
+ """ True if device is on. """
+ return False
+
+ def get_state_attributes(self):
+ """ Returns optional state attributes. """
+ return {}
+
+ def update(self):
+ """ Retrieve latest state from the real device. """
+ pass
+
+ def update_ha_state(self, hass, force_refresh=False):
+ """
+ Updates Home Assistant with current state of device.
+ If force_refresh == True will update device before setting state.
+ """
+ if self.entity_id is None:
+ raise NoEntitySpecifiedError(
+ "No entity specified for device {}".format(self.get_name()))
+
+ if force_refresh:
+ self.update()
+
+ state = STATE_ON if self.is_on() else STATE_OFF
+
+ return hass.states.set(self.entity_id, state,
+ self.get_state_attributes())
diff --git a/homeassistant/remote.py b/homeassistant/remote.py
index bcfe6e68e65f28..869c690be6be97 100644
--- a/homeassistant/remote.py
+++ b/homeassistant/remote.py
@@ -19,18 +19,10 @@
import homeassistant as ha
-SERVER_PORT = 8123
-
-AUTH_HEADER = "HA-access"
-
-URL_API = "/api/"
-URL_API_STATES = "/api/states"
-URL_API_STATES_ENTITY = "/api/states/{}"
-URL_API_EVENTS = "/api/events"
-URL_API_EVENTS_EVENT = "/api/events/{}"
-URL_API_SERVICES = "/api/services"
-URL_API_SERVICES_SERVICE = "/api/services/{}/{}"
-URL_API_EVENT_FORWARD = "/api/event_forwarding"
+from homeassistant.const import (
+ SERVER_PORT, AUTH_HEADER, URL_API, URL_API_STATES, URL_API_STATES_ENTITY,
+ URL_API_EVENTS, URL_API_EVENTS_EVENT, URL_API_SERVICES,
+ URL_API_SERVICES_SERVICE, URL_API_EVENT_FORWARD)
METHOD_GET = "get"
METHOD_POST = "post"
diff --git a/homeassistant/util.py b/homeassistant/util.py
index d6bb9423a42572..4598a230c655ea 100644
--- a/homeassistant/util.py
+++ b/homeassistant/util.py
@@ -127,6 +127,7 @@ def ensure_unique_string(preferred_string, current_strings):
""" Returns a string that is not present in current_strings.
If preferred string exists will append _2, _3, .. """
string = preferred_string
+ current_strings = list(current_strings)
tries = 1
@@ -248,32 +249,6 @@ def __eq__(self, other):
return set(self) == set(other)
-def validate_config(config, items, logger):
- """
- Validates if all items are available in the configuration.
-
- config is the general dictionary with all the configurations.
- items is a dict with per domain which attributes we require.
- logger is the logger from the caller to log the errors to.
-
- Returns True if all required items were found.
- """
- errors_found = False
- for domain in items.keys():
- config.setdefault(domain, {})
-
- errors = [item for item in items[domain] if item not in config[domain]]
-
- if errors:
- logger.error(
- "Missing required configuration items in {}: {}".format(
- domain, ", ".join(errors)))
-
- errors_found = True
-
- return not errors_found
-
-
class Throttle(object):
"""
A method decorator to add a cooldown to a method to prevent it from being