Refactor: code moved to new helper and constants file. Also adds support for multiple types for switch/light components.
This commit is contained in:
parent
513a03fb46
commit
0527760e9b
41 changed files with 603 additions and 442 deletions
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -6,8 +6,8 @@ Provides a mock switch platform.
|
|||
|
||||
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)
|
||||
]
|
||||
|
||||
|
||||
|
|
|
@ -6,8 +6,8 @@ Provides a mock switch platform.
|
|||
|
||||
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)
|
||||
]
|
||||
|
||||
|
||||
|
|
|
@ -7,7 +7,8 @@ Helper method for writing tests.
|
|||
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 @@ class MockModule(object):
|
|||
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 @@ class MockToggleDevice(components.ToggleDevice):
|
|||
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:
|
|
@ -9,9 +9,13 @@ import logging
|
|||
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 @@ class TestChromecast(unittest.TestCase):
|
|||
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 @@ class TestChromecast(unittest.TestCase):
|
|||
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 @@ class TestChromecast(unittest.TestCase):
|
|||
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'}}))
|
||||
|
|
|
@ -9,6 +9,8 @@ import unittest
|
|||
|
||||
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 @@ class TestComponentsCore(unittest.TestCase):
|
|||
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 @@ class TestComponentsCore(unittest.TestCase):
|
|||
""" 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 @@ class TestComponentsCore(unittest.TestCase):
|
|||
""" 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))
|
||||
|
|
|
@ -9,7 +9,7 @@ import unittest
|
|||
|
||||
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)
|
||||
|
||||
|
||||
|
|
|
@ -12,11 +12,11 @@ import os
|
|||
|
||||
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 @@ class TestComponentsDeviceTracker(unittest.TestCase):
|
|||
|
||||
# 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 @@ class TestComponentsDeviceTracker(unittest.TestCase):
|
|||
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 @@ class TestComponentsDeviceTracker(unittest.TestCase):
|
|||
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.
|
||||
|
|
|
@ -9,7 +9,7 @@ import unittest
|
|||
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 @@ class TestComponentsGroup(unittest.TestCase):
|
|||
""" 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 @@ class TestComponentsGroup(unittest.TestCase):
|
|||
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 @@ class TestComponentsGroup(unittest.TestCase):
|
|||
|
||||
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 @@ class TestComponentsGroup(unittest.TestCase):
|
|||
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 @@ class TestComponentsGroup(unittest.TestCase):
|
|||
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])
|
||||
|
|
|
@ -11,12 +11,12 @@ import os
|
|||
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 @@ class TestLight(unittest.TestCase):
|
|||
|
||||
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 @@ class TestLight(unittest.TestCase):
|
|||
|
||||
# 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 @@ class TestLight(unittest.TestCase):
|
|||
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 @@ class TestLight(unittest.TestCase):
|
|||
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)
|
||||
|
|
|
@ -11,6 +11,7 @@ import datetime as dt
|
|||
import ephem
|
||||
|
||||
import homeassistant as ha
|
||||
from homeassistant.const import CONF_LATITUDE, CONF_LONGITUDE
|
||||
import homeassistant.components.sun as sun
|
||||
|
||||
|
||||
|
@ -37,8 +38,8 @@ class TestSun(unittest.TestCase):
|
|||
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 @@ class TestSun(unittest.TestCase):
|
|||
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 @@ class TestSun(unittest.TestCase):
|
|||
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'
|
||||
}}))
|
||||
|
|
|
@ -9,10 +9,10 @@ import unittest
|
|||
|
||||
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 @@ class TestSwitch(unittest.TestCase):
|
|||
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 @@ class TestSwitch(unittest.TestCase):
|
|||
|
||||
# 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'},
|
||||
}
|
||||
))
|
||||
|
|
49
ha_test/test_helpers.py
Normal file
49
ha_test/test_helpers.py
Normal file
|
@ -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))
|
|
@ -10,7 +10,7 @@ import unittest
|
|||
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):
|
||||
|
|
|
@ -15,32 +15,14 @@ import re
|
|||
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
|
||||
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -19,36 +19,10 @@ import logging
|
|||
|
||||
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. """
|
||||
|
|
|
@ -6,9 +6,14 @@ Provides functionality to interact with Chromecasts.
|
|||
"""
|
||||
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 setup(hass, config):
|
|||
|
||||
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 setup(hass, config):
|
|||
|
||||
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 setup(hass, config):
|
|||
|
||||
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",
|
||||
|
|
|
@ -8,9 +8,10 @@ import random
|
|||
|
||||
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 setup(hass, config):
|
|||
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)
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ the state of the sun and devices.
|
|||
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 setup(hass, config):
|
|||
|
||||
# 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 setup(hass, config):
|
|||
|
||||
# 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 setup(hass, config):
|
|||
# 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
|
||||
|
|
|
@ -10,12 +10,14 @@ import os
|
|||
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))
|
||||
|
|
|
@ -6,8 +6,9 @@ import re
|
|||
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 @@ _LOGGER = logging.getLogger(__name__)
|
|||
# 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<param>\w*) = (?P<value>.*);")
|
||||
|
||||
|
@ -87,7 +87,7 @@ class LuciDeviceScanner(object):
|
|||
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. """
|
||||
|
|
|
@ -3,8 +3,9 @@ import logging
|
|||
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 @@ _LOGGER = logging.getLogger(__name__)
|
|||
# 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 @@ class NetgearDeviceScanner(object):
|
|||
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. """
|
||||
|
|
|
@ -7,8 +7,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
|
||||
|
@ -22,10 +23,10 @@ _LOGGER = logging.getLogger(__name__)
|
|||
# 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 @@ class TomatoDeviceScanner(object):
|
|||
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. """
|
||||
|
|
|
@ -9,7 +9,8 @@ import logging
|
|||
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 setup(hass, config):
|
|||
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 setup(hass, config):
|
|||
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:
|
||||
|
|
|
@ -9,9 +9,8 @@ import logging
|
|||
|
||||
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 = []
|
||||
|
|
|
@ -83,6 +83,10 @@ from socketserver import ThreadingMixIn
|
|||
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 @@ _LOGGER = logging.getLogger(__name__)
|
|||
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<entity_id>[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<event_type>[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<domain>[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 @@ class RequestHandler(SimpleHTTPRequestHandler):
|
|||
"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 @@ class RequestHandler(SimpleHTTPRequestHandler):
|
|||
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. """
|
||||
|
|
|
@ -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 @@ DEPENDENCIES = []
|
|||
|
||||
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))
|
||||
|
||||
|
|
|
@ -52,12 +52,12 @@ import logging
|
|||
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]
|
||||
lights = platform_devices_from_config(config, DOMAIN, hass, _LOGGER)
|
||||
|
||||
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])
|
||||
|
||||
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
|
||||
|
|
|
@ -3,9 +3,9 @@ import logging
|
|||
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 @@ MIN_TIME_BETWEEN_FORCED_SCANS = timedelta(seconds=1)
|
|||
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(
|
||||
|
|
|
@ -10,7 +10,7 @@ Author: Markus Stenberg <fingon@iki.fi>
|
|||
|
||||
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'
|
||||
|
|
|
@ -8,7 +8,9 @@ import logging
|
|||
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 setup(hass, config):
|
|||
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)
|
||||
|
|
|
@ -6,12 +6,12 @@ Component to interface with various switches that can be controlled remotely.
|
|||
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
|
||||
switches = platform_devices_from_config(config, DOMAIN, hass, logger)
|
||||
|
||||
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])
|
||||
|
||||
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
|
||||
|
|
|
@ -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 @@ except ImportError:
|
|||
|
||||
|
||||
# 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
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -26,8 +26,7 @@ import logging
|
|||
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"
|
||||
|
|
78
homeassistant/const.py
Normal file
78
homeassistant/const.py
Normal file
|
@ -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"
|
176
homeassistant/helpers.py
Normal file
176
homeassistant/helpers.py
Normal file
|
@ -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())
|
|
@ -19,18 +19,10 @@ import requests
|
|||
|
||||
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"
|
||||
|
|
|
@ -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 @@ class OrderedSet(collections.MutableSet):
|
|||
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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue