More robust geofence checking

This commit is contained in:
Paulus Schoutsen 2015-10-02 08:16:53 -07:00
parent 42b80868d4
commit 9bdfa89b7c
7 changed files with 44 additions and 36 deletions

View file

@ -36,17 +36,13 @@ def trigger(hass, config, action):
def zone_automation_listener(entity, from_s, to_s):
""" Listens for state changes and calls action. """
if from_s and None in (from_s.attributes.get(ATTR_LATITUDE),
from_s.attributes.get(ATTR_LONGITUDE)):
return
if None in (to_s.attributes.get(ATTR_LATITUDE),
from_s.attributes.get(ATTR_LONGITUDE)) or \
None in (to_s.attributes.get(ATTR_LATITUDE),
to_s.attributes.get(ATTR_LONGITUDE)):
return
from_zone = _in_zone(hass, from_s) if from_s else None
to_zone = _in_zone(hass, to_s)
from_match = from_zone and from_zone.entity_id == zone_entity_id
to_match = to_zone and to_zone.entity_id == zone_entity_id
from_match = _in_zone(hass, zone_entity_id, from_s) if from_s else None
to_match = _in_zone(hass, zone_entity_id, to_s)
if event == EVENT_ENTER and not from_match and to_match or \
event == EVENT_LEAVE and from_match and not to_match:
@ -71,22 +67,19 @@ def if_action(hass, config):
def if_in_zone():
""" Test if condition. """
state = hass.states.get(entity_id)
if not state or None in (state.attributes.get(ATTR_LATITUDE),
state.attributes.get(ATTR_LONGITUDE)):
return
cur_zone = _in_zone(hass, state)
return cur_zone and cur_zone.entity_id == zone_entity_id
return _in_zone(hass, zone_entity_id, hass.states.get(entity_id))
return if_in_zone
def _in_zone(hass, state):
def _in_zone(hass, zone_entity_id, state):
""" Check if state is in zone. """
return zone.in_zone(
hass, state.attributes.get(ATTR_LATITUDE),
if not state or None in (state.attributes.get(ATTR_LATITUDE),
state.attributes.get(ATTR_LONGITUDE)):
return False
zone_state = hass.states.get(zone_entity_id)
return zone_state and zone.in_zone(
zone_state, state.attributes.get(ATTR_LATITUDE),
state.attributes.get(ATTR_LONGITUDE),
state.attributes.get(ATTR_GPS_ACCURACY, 0))

View file

@ -364,7 +364,8 @@ class Device(Entity):
elif self.location_name:
self._state = self.location_name
elif self.gps is not None:
zone_state = zone.in_zone(self.hass, self.gps[0], self.gps[1])
zone_state = zone.active_zone(self.hass, self.gps[0], self.gps[1],
self.gps_accuracy)
if zone_state is None:
self._state = STATE_NOT_HOME
elif zone_state.entity_id == zone.ENTITY_ID_HOME:

View file

@ -1,2 +1,2 @@
""" DO NOT MODIFY. Auto-generated by build_frontend script """
VERSION = "8d460d7298e41397b4f94ef103b2a067"
VERSION = "c4722afa376379bc4457d54bb9a38cee"

File diff suppressed because one or more lines are too long

@ -1 +1 @@
Subproject commit 4dba97292744a32146e35e36031dbca59eb62733
Subproject commit fa8d63f9ac5ef7b0533d800d2fdb8c0c92d56e12

View file

@ -44,8 +44,8 @@ ATTR_ICON = 'icon'
ICON_HOME = 'home'
def in_zone(hass, latitude, longitude, radius=0):
""" Find the zone for given latitude, longitude. """
def active_zone(hass, latitude, longitude, radius=0):
""" Find the active zone for given latitude, longitude. """
# Sort entity IDs so that we are deterministic if equal distance to 2 zones
zones = (hass.states.get(entity_id) for entity_id
in sorted(hass.states.entity_ids(DOMAIN)))
@ -54,18 +54,32 @@ def in_zone(hass, latitude, longitude, radius=0):
closest = None
for zone in zones:
zone_dist = distance(latitude, longitude,
zone.attributes[ATTR_LATITUDE],
zone.attributes[ATTR_LONGITUDE])
zone_dist = distance(
latitude, longitude,
zone.attributes[ATTR_LATITUDE], zone.attributes[ATTR_LONGITUDE])
if zone_dist - radius < zone.attributes[ATTR_RADIUS] and \
(closest is None or zone_dist < min_dist):
within_zone = zone_dist - radius < zone.attributes[ATTR_RADIUS]
closer_zone = closest is None or zone_dist < min_dist
smaller_zone = (zone_dist == min_dist and
zone.attributes[ATTR_RADIUS] <
closest.attributes[ATTR_RADIUS])
if within_zone and (closer_zone or smaller_zone):
min_dist = zone_dist
closest = zone
return closest
def in_zone(zone, latitude, longitude, radius=0):
""" Test if given latitude, longitude is in given zone. """
zone_dist = distance(
latitude, longitude,
zone.attributes[ATTR_LATITUDE], zone.attributes[ATTR_LONGITUDE])
return zone_dist - radius < zone.attributes[ATTR_RADIUS]
def setup(hass, config):
""" Setup zone. """
entities = set()

View file

@ -31,6 +31,6 @@ def detect_location_info():
return LocationInfo(**data)
def distance(lon1, lat1, lon2, lat2):
def distance(lat1, lon1, lat2, lon2):
""" Calculate the distance in meters between two points. """
return vincenty((lon1, lat1), (lon2, lat2)) * 1000
return vincenty((lat1, lon1), (lat2, lon2)) * 1000