Add GPS accuracy check for a location update or an event update
Add tests related to this Great thanks to @pavoni for his support on this fix
This commit is contained in:
parent
e755731588
commit
c04555d7b1
2 changed files with 77 additions and 4 deletions
|
@ -28,10 +28,14 @@ _LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
LOCK = threading.Lock()
|
LOCK = threading.Lock()
|
||||||
|
|
||||||
|
CONF_MAX_GPS_ACCURACY = 'max_gps_accuracy'
|
||||||
|
|
||||||
|
|
||||||
def setup_scanner(hass, config, see):
|
def setup_scanner(hass, config, see):
|
||||||
""" Set up an OwnTracks tracker. """
|
""" Set up an OwnTracks tracker. """
|
||||||
|
|
||||||
|
max_gps_accuracy = config.get(CONF_MAX_GPS_ACCURACY)
|
||||||
|
|
||||||
def owntracks_location_update(topic, payload, qos):
|
def owntracks_location_update(topic, payload, qos):
|
||||||
""" MQTT message received. """
|
""" MQTT message received. """
|
||||||
|
|
||||||
|
@ -45,7 +49,9 @@ def setup_scanner(hass, config, see):
|
||||||
'Unable to parse payload as JSON: %s', payload)
|
'Unable to parse payload as JSON: %s', payload)
|
||||||
return
|
return
|
||||||
|
|
||||||
if not isinstance(data, dict) or data.get('_type') != 'location':
|
if (not isinstance(data, dict) or data.get('_type') != 'location') or (
|
||||||
|
'acc' in data and max_gps_accuracy is not None and data[
|
||||||
|
'acc'] > max_gps_accuracy):
|
||||||
return
|
return
|
||||||
|
|
||||||
dev_id, kwargs = _parse_see_args(topic, data)
|
dev_id, kwargs = _parse_see_args(topic, data)
|
||||||
|
@ -124,12 +130,20 @@ def setup_scanner(hass, config, see):
|
||||||
kwargs['location_name'] = new_region
|
kwargs['location_name'] = new_region
|
||||||
_set_gps_from_zone(kwargs, zone)
|
_set_gps_from_zone(kwargs, zone)
|
||||||
_LOGGER.info("Exit to %s", new_region)
|
_LOGGER.info("Exit to %s", new_region)
|
||||||
|
see(**kwargs)
|
||||||
|
see_beacons(dev_id, kwargs)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
_LOGGER.info("Exit to GPS")
|
_LOGGER.info("Exit to GPS")
|
||||||
|
# Check for GPS accuracy
|
||||||
|
if not ('acc' in data and
|
||||||
|
max_gps_accuracy is not None and
|
||||||
|
data['acc'] > max_gps_accuracy):
|
||||||
|
|
||||||
see(**kwargs)
|
see(**kwargs)
|
||||||
see_beacons(dev_id, kwargs)
|
see_beacons(dev_id, kwargs)
|
||||||
|
else:
|
||||||
|
_LOGGER.info("Inaccurate GPS reported")
|
||||||
|
|
||||||
beacons = MOBILE_BEACONS_ACTIVE[dev_id]
|
beacons = MOBILE_BEACONS_ACTIVE[dev_id]
|
||||||
if location in beacons:
|
if location in beacons:
|
||||||
|
|
|
@ -30,6 +30,8 @@ DEVICE_TRACKER_STATE = "device_tracker.{}_{}".format(USER, DEVICE)
|
||||||
IBEACON_DEVICE = 'keys'
|
IBEACON_DEVICE = 'keys'
|
||||||
REGION_TRACKER_STATE = "device_tracker.beacon_{}".format(IBEACON_DEVICE)
|
REGION_TRACKER_STATE = "device_tracker.beacon_{}".format(IBEACON_DEVICE)
|
||||||
|
|
||||||
|
CONF_MAX_GPS_ACCURACY = 'max_gps_accuracy'
|
||||||
|
|
||||||
LOCATION_MESSAGE = {
|
LOCATION_MESSAGE = {
|
||||||
'batt': 92,
|
'batt': 92,
|
||||||
'cog': 248,
|
'cog': 248,
|
||||||
|
@ -45,6 +47,21 @@ LOCATION_MESSAGE = {
|
||||||
'tst': 1,
|
'tst': 1,
|
||||||
'vel': 0}
|
'vel': 0}
|
||||||
|
|
||||||
|
LOCATION_MESSAGE_INACCURATE = {
|
||||||
|
'batt': 92,
|
||||||
|
'cog': 248,
|
||||||
|
'tid': 'user',
|
||||||
|
'lon': 2.0,
|
||||||
|
't': 'u',
|
||||||
|
'alt': 27,
|
||||||
|
'acc': 2000,
|
||||||
|
'p': 101.3977584838867,
|
||||||
|
'vac': 4,
|
||||||
|
'lat': 6.0,
|
||||||
|
'_type': 'location',
|
||||||
|
'tst': 1,
|
||||||
|
'vel': 0}
|
||||||
|
|
||||||
REGION_ENTER_MESSAGE = {
|
REGION_ENTER_MESSAGE = {
|
||||||
'lon': 1.0,
|
'lon': 1.0,
|
||||||
'event': 'enter',
|
'event': 'enter',
|
||||||
|
@ -70,6 +87,18 @@ REGION_LEAVE_MESSAGE = {
|
||||||
'lat': 2.0,
|
'lat': 2.0,
|
||||||
'_type': 'transition'}
|
'_type': 'transition'}
|
||||||
|
|
||||||
|
REGION_LEAVE_INACCURATE_MESSAGE = {
|
||||||
|
'lon': 10.0,
|
||||||
|
'event': 'leave',
|
||||||
|
'tid': 'user',
|
||||||
|
'desc': 'inner',
|
||||||
|
'wtst': 1,
|
||||||
|
't': 'b',
|
||||||
|
'acc': 2000,
|
||||||
|
'tst': 2,
|
||||||
|
'lat': 20.0,
|
||||||
|
'_type': 'transition'}
|
||||||
|
|
||||||
|
|
||||||
class TestDeviceTrackerOwnTracks(unittest.TestCase):
|
class TestDeviceTrackerOwnTracks(unittest.TestCase):
|
||||||
""" Test the Template sensor. """
|
""" Test the Template sensor. """
|
||||||
|
@ -80,7 +109,8 @@ class TestDeviceTrackerOwnTracks(unittest.TestCase):
|
||||||
mock_mqtt_component(self.hass)
|
mock_mqtt_component(self.hass)
|
||||||
self.assertTrue(device_tracker.setup(self.hass, {
|
self.assertTrue(device_tracker.setup(self.hass, {
|
||||||
device_tracker.DOMAIN: {
|
device_tracker.DOMAIN: {
|
||||||
CONF_PLATFORM: 'owntracks'
|
CONF_PLATFORM: 'owntracks',
|
||||||
|
CONF_MAX_GPS_ACCURACY: 200
|
||||||
}}))
|
}}))
|
||||||
|
|
||||||
self.hass.states.set(
|
self.hass.states.set(
|
||||||
|
@ -146,6 +176,10 @@ class TestDeviceTrackerOwnTracks(unittest.TestCase):
|
||||||
state = self.hass.states.get(DEVICE_TRACKER_STATE)
|
state = self.hass.states.get(DEVICE_TRACKER_STATE)
|
||||||
self.assertEqual(state.attributes.get('latitude'), latitude)
|
self.assertEqual(state.attributes.get('latitude'), latitude)
|
||||||
|
|
||||||
|
def assert_location_longitude(self, longitude):
|
||||||
|
state = self.hass.states.get(DEVICE_TRACKER_STATE)
|
||||||
|
self.assertEqual(state.attributes.get('longitude'), longitude)
|
||||||
|
|
||||||
def assert_location_accuracy(self, accuracy):
|
def assert_location_accuracy(self, accuracy):
|
||||||
state = self.hass.states.get(DEVICE_TRACKER_STATE)
|
state = self.hass.states.get(DEVICE_TRACKER_STATE)
|
||||||
self.assertEqual(state.attributes.get('gps_accuracy'), accuracy)
|
self.assertEqual(state.attributes.get('gps_accuracy'), accuracy)
|
||||||
|
@ -169,6 +203,13 @@ class TestDeviceTrackerOwnTracks(unittest.TestCase):
|
||||||
self.assert_location_accuracy(60.0)
|
self.assert_location_accuracy(60.0)
|
||||||
self.assert_location_state('outer')
|
self.assert_location_state('outer')
|
||||||
|
|
||||||
|
def test_location_inaccurate_gps(self):
|
||||||
|
self.send_message(LOCATION_TOPIC, LOCATION_MESSAGE)
|
||||||
|
self.send_message(LOCATION_TOPIC, LOCATION_MESSAGE_INACCURATE)
|
||||||
|
|
||||||
|
self.assert_location_latitude(2.0)
|
||||||
|
self.assert_location_longitude(1.0)
|
||||||
|
|
||||||
def test_event_entry_exit(self):
|
def test_event_entry_exit(self):
|
||||||
self.send_message(EVENT_TOPIC, REGION_ENTER_MESSAGE)
|
self.send_message(EVENT_TOPIC, REGION_ENTER_MESSAGE)
|
||||||
|
|
||||||
|
@ -194,6 +235,24 @@ class TestDeviceTrackerOwnTracks(unittest.TestCase):
|
||||||
# Left clean zone state
|
# Left clean zone state
|
||||||
self.assertFalse(owntracks.REGIONS_ENTERED[USER])
|
self.assertFalse(owntracks.REGIONS_ENTERED[USER])
|
||||||
|
|
||||||
|
def test_event_entry_exit_inaccurate(self):
|
||||||
|
self.send_message(EVENT_TOPIC, REGION_ENTER_MESSAGE)
|
||||||
|
|
||||||
|
# Enter uses the zone's gps co-ords
|
||||||
|
self.assert_location_latitude(2.1)
|
||||||
|
self.assert_location_accuracy(10.0)
|
||||||
|
self.assert_location_state('inner')
|
||||||
|
|
||||||
|
self.send_message(EVENT_TOPIC, REGION_LEAVE_INACCURATE_MESSAGE)
|
||||||
|
|
||||||
|
# Exit doesn't use inaccurate gps
|
||||||
|
self.assert_location_latitude(2.1)
|
||||||
|
self.assert_location_accuracy(10.0)
|
||||||
|
self.assert_location_state('inner')
|
||||||
|
|
||||||
|
# But does exit region correctly
|
||||||
|
self.assertFalse(owntracks.REGIONS_ENTERED[USER])
|
||||||
|
|
||||||
def test_event_exit_outside_zone_sets_away(self):
|
def test_event_exit_outside_zone_sets_away(self):
|
||||||
self.send_message(EVENT_TOPIC, REGION_ENTER_MESSAGE)
|
self.send_message(EVENT_TOPIC, REGION_ENTER_MESSAGE)
|
||||||
self.assert_location_state('inner')
|
self.assert_location_state('inner')
|
||||||
|
|
Loading…
Add table
Reference in a new issue