More robust geofence checking
This commit is contained in:
parent
42b80868d4
commit
9bdfa89b7c
7 changed files with 44 additions and 36 deletions
|
@ -36,17 +36,13 @@ def trigger(hass, config, action):
|
||||||
def zone_automation_listener(entity, from_s, to_s):
|
def zone_automation_listener(entity, from_s, to_s):
|
||||||
""" Listens for state changes and calls action. """
|
""" Listens for state changes and calls action. """
|
||||||
if from_s and None in (from_s.attributes.get(ATTR_LATITUDE),
|
if from_s and None in (from_s.attributes.get(ATTR_LATITUDE),
|
||||||
from_s.attributes.get(ATTR_LONGITUDE)):
|
from_s.attributes.get(ATTR_LONGITUDE)) or \
|
||||||
return
|
None in (to_s.attributes.get(ATTR_LATITUDE),
|
||||||
|
|
||||||
if None in (to_s.attributes.get(ATTR_LATITUDE),
|
|
||||||
to_s.attributes.get(ATTR_LONGITUDE)):
|
to_s.attributes.get(ATTR_LONGITUDE)):
|
||||||
return
|
return
|
||||||
|
|
||||||
from_zone = _in_zone(hass, from_s) if from_s else None
|
from_match = _in_zone(hass, zone_entity_id, from_s) if from_s else None
|
||||||
to_zone = _in_zone(hass, to_s)
|
to_match = _in_zone(hass, zone_entity_id, 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
|
|
||||||
|
|
||||||
if event == EVENT_ENTER and not from_match and to_match or \
|
if event == EVENT_ENTER and not from_match and to_match or \
|
||||||
event == EVENT_LEAVE and from_match and not to_match:
|
event == EVENT_LEAVE and from_match and not to_match:
|
||||||
|
@ -71,22 +67,19 @@ def if_action(hass, config):
|
||||||
|
|
||||||
def if_in_zone():
|
def if_in_zone():
|
||||||
""" Test if condition. """
|
""" Test if condition. """
|
||||||
state = hass.states.get(entity_id)
|
return _in_zone(hass, zone_entity_id, 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 if_in_zone
|
return if_in_zone
|
||||||
|
|
||||||
|
|
||||||
def _in_zone(hass, state):
|
def _in_zone(hass, zone_entity_id, state):
|
||||||
""" Check if state is in zone. """
|
""" Check if state is in zone. """
|
||||||
return zone.in_zone(
|
if not state or None in (state.attributes.get(ATTR_LATITUDE),
|
||||||
hass, 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_LONGITUDE),
|
||||||
state.attributes.get(ATTR_GPS_ACCURACY, 0))
|
state.attributes.get(ATTR_GPS_ACCURACY, 0))
|
||||||
|
|
|
@ -364,7 +364,8 @@ class Device(Entity):
|
||||||
elif self.location_name:
|
elif self.location_name:
|
||||||
self._state = self.location_name
|
self._state = self.location_name
|
||||||
elif self.gps is not None:
|
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:
|
if zone_state is None:
|
||||||
self._state = STATE_NOT_HOME
|
self._state = STATE_NOT_HOME
|
||||||
elif zone_state.entity_id == zone.ENTITY_ID_HOME:
|
elif zone_state.entity_id == zone.ENTITY_ID_HOME:
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
""" DO NOT MODIFY. Auto-generated by build_frontend script """
|
""" 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
|
|
@ -44,8 +44,8 @@ ATTR_ICON = 'icon'
|
||||||
ICON_HOME = 'home'
|
ICON_HOME = 'home'
|
||||||
|
|
||||||
|
|
||||||
def in_zone(hass, latitude, longitude, radius=0):
|
def active_zone(hass, latitude, longitude, radius=0):
|
||||||
""" Find the zone for given latitude, longitude. """
|
""" Find the active zone for given latitude, longitude. """
|
||||||
# Sort entity IDs so that we are deterministic if equal distance to 2 zones
|
# Sort entity IDs so that we are deterministic if equal distance to 2 zones
|
||||||
zones = (hass.states.get(entity_id) for entity_id
|
zones = (hass.states.get(entity_id) for entity_id
|
||||||
in sorted(hass.states.entity_ids(DOMAIN)))
|
in sorted(hass.states.entity_ids(DOMAIN)))
|
||||||
|
@ -54,18 +54,32 @@ def in_zone(hass, latitude, longitude, radius=0):
|
||||||
closest = None
|
closest = None
|
||||||
|
|
||||||
for zone in zones:
|
for zone in zones:
|
||||||
zone_dist = distance(latitude, longitude,
|
zone_dist = distance(
|
||||||
zone.attributes[ATTR_LATITUDE],
|
latitude, longitude,
|
||||||
zone.attributes[ATTR_LONGITUDE])
|
zone.attributes[ATTR_LATITUDE], zone.attributes[ATTR_LONGITUDE])
|
||||||
|
|
||||||
if zone_dist - radius < zone.attributes[ATTR_RADIUS] and \
|
within_zone = zone_dist - radius < zone.attributes[ATTR_RADIUS]
|
||||||
(closest is None or zone_dist < min_dist):
|
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
|
min_dist = zone_dist
|
||||||
closest = zone
|
closest = zone
|
||||||
|
|
||||||
return closest
|
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):
|
def setup(hass, config):
|
||||||
""" Setup zone. """
|
""" Setup zone. """
|
||||||
entities = set()
|
entities = set()
|
||||||
|
|
|
@ -31,6 +31,6 @@ def detect_location_info():
|
||||||
return LocationInfo(**data)
|
return LocationInfo(**data)
|
||||||
|
|
||||||
|
|
||||||
def distance(lon1, lat1, lon2, lat2):
|
def distance(lat1, lon1, lat2, lon2):
|
||||||
""" Calculate the distance in meters between two points. """
|
""" Calculate the distance in meters between two points. """
|
||||||
return vincenty((lon1, lat1), (lon2, lat2)) * 1000
|
return vincenty((lat1, lon1), (lat2, lon2)) * 1000
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue