From bb97af1504bb791c77a6d923415e92dec9bd9c22 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Thu, 21 Jan 2016 23:53:57 -0800 Subject: [PATCH] Allow passive zones --- homeassistant/components/zone.py | 36 +++++---- tests/components/test_zone.py | 126 +++++++++++++++++++++++++++++++ 2 files changed, 148 insertions(+), 14 deletions(-) create mode 100644 tests/components/test_zone.py diff --git a/homeassistant/components/zone.py b/homeassistant/components/zone.py index da0341129f7..86e2cf5062e 100644 --- a/homeassistant/components/zone.py +++ b/homeassistant/components/zone.py @@ -24,6 +24,9 @@ DEFAULT_NAME = 'Unnamed zone' ATTR_RADIUS = 'radius' DEFAULT_RADIUS = 100 +ATTR_PASSIVE = 'passive' +DEFAULT_PASSIVE = False + ICON_HOME = 'mdi:home' @@ -37,6 +40,9 @@ def active_zone(hass, latitude, longitude, radius=0): closest = None for zone in zones: + if zone.attributes.get(ATTR_PASSIVE): + continue + zone_dist = distance( latitude, longitude, zone.attributes[ATTR_LATITUDE], zone.attributes[ATTR_LONGITUDE]) @@ -78,13 +84,14 @@ def setup(hass, config): longitude = entry.get(ATTR_LONGITUDE) radius = entry.get(ATTR_RADIUS, DEFAULT_RADIUS) icon = entry.get(ATTR_ICON) + passive = entry.get(ATTR_PASSIVE, DEFAULT_PASSIVE) if None in (latitude, longitude): logging.getLogger(__name__).error( 'Each zone needs a latitude and longitude.') continue - zone = Zone(hass, name, latitude, longitude, radius, icon) + zone = Zone(hass, name, latitude, longitude, radius, icon, passive) zone.entity_id = generate_entity_id(ENTITY_ID_FORMAT, name, entities) zone.update_ha_state() @@ -92,7 +99,7 @@ def setup(hass, config): if ENTITY_ID_HOME not in entities: zone = Zone(hass, hass.config.location_name, hass.config.latitude, - hass.config.longitude, DEFAULT_RADIUS, ICON_HOME) + hass.config.longitude, DEFAULT_RADIUS, ICON_HOME, False) zone.entity_id = ENTITY_ID_HOME zone.update_ha_state() @@ -101,17 +108,15 @@ def setup(hass, config): class Zone(Entity): """ Represents a Zone in Home Assistant. """ - # pylint: disable=too-many-arguments - def __init__(self, hass, name, latitude, longitude, radius, icon): + # pylint: disable=too-many-arguments, too-many-instance-attributes + def __init__(self, hass, name, latitude, longitude, radius, icon, passive): self.hass = hass self._name = name - self.latitude = latitude - self.longitude = longitude - self.radius = radius + self._latitude = latitude + self._longitude = longitude + self._radius = radius self._icon = icon - - def should_poll(self): - return False + self._passive = passive @property def name(self): @@ -128,9 +133,12 @@ class Zone(Entity): @property def state_attributes(self): - return { + data = { ATTR_HIDDEN: True, - ATTR_LATITUDE: self.latitude, - ATTR_LONGITUDE: self.longitude, - ATTR_RADIUS: self.radius, + ATTR_LATITUDE: self._latitude, + ATTR_LONGITUDE: self._longitude, + ATTR_RADIUS: self._radius, } + if self._passive: + data[ATTR_PASSIVE] = self._passive + return data diff --git a/tests/components/test_zone.py b/tests/components/test_zone.py new file mode 100644 index 00000000000..7275767d7be --- /dev/null +++ b/tests/components/test_zone.py @@ -0,0 +1,126 @@ +""" +tests.components.automation.test_location +±±±~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Tests location automation. +""" +import unittest + +from homeassistant.components import zone + +from tests.common import get_test_home_assistant + + +class TestAutomationZone(unittest.TestCase): + """ Test the event automation. """ + + def setUp(self): # pylint: disable=invalid-name + self.hass = get_test_home_assistant() + + def tearDown(self): # pylint: disable=invalid-name + """ Stop down stuff we started. """ + self.hass.stop() + + def test_setup(self): + info = { + 'name': 'Test Zone', + 'latitude': 32.880837, + 'longitude': -117.237561, + 'radius': 250, + 'passive': True + } + assert zone.setup(self.hass, { + 'zone': info + }) + + state = self.hass.states.get('zone.test_zone') + assert info['name'] == state.name + assert info['latitude'] == state.attributes['latitude'] + assert info['longitude'] == state.attributes['longitude'] + assert info['radius'] == state.attributes['radius'] + assert info['passive'] == state.attributes['passive'] + + def test_active_zone_skips_passive_zones(self): + assert zone.setup(self.hass, { + 'zone': [ + { + 'name': 'Passive Zone', + 'latitude': 32.880600, + 'longitude': -117.237561, + 'radius': 250, + 'passive': True + }, + ] + }) + + active = zone.active_zone(self.hass, 32.880600, -117.237561) + assert active is None + + assert zone.setup(self.hass, { + 'zone': [ + { + 'name': 'Active Zone', + 'latitude': 32.880800, + 'longitude': -117.237561, + 'radius': 500, + }, + ] + }) + + active = zone.active_zone(self.hass, 32.880700, -117.237561) + assert 'zone.active_zone' == active.entity_id + + def test_active_zone_prefers_smaller_zone_if_same_distance(self): + latitude = 32.880600 + longitude = -117.237561 + assert zone.setup(self.hass, { + 'zone': [ + { + 'name': 'Small Zone', + 'latitude': latitude, + 'longitude': longitude, + 'radius': 250, + }, + { + 'name': 'Big Zone', + 'latitude': latitude, + 'longitude': longitude, + 'radius': 500, + }, + ] + }) + + active = zone.active_zone(self.hass, latitude, longitude) + assert 'zone.small_zone' == active.entity_id + + assert zone.setup(self.hass, { + 'zone': [ + { + 'name': 'Smallest Zone', + 'latitude': latitude, + 'longitude': longitude, + 'radius': 50, + }, + ] + }) + + active = zone.active_zone(self.hass, latitude, longitude) + assert 'zone.smallest_zone' == active.entity_id + + def test_in_zone_works_for_passive_zones(self): + latitude = 32.880600 + longitude = -117.237561 + assert zone.setup(self.hass, { + 'zone': [ + { + 'name': 'Passive Zone', + 'latitude': latitude, + 'longitude': longitude, + 'radius': 250, + 'passive': True + }, + ] + }) + + assert zone.in_zone(self.hass.states.get('zone.passive_zone'), + latitude, longitude)