Changed source priority for Person (#21479)
* Added gps accuracy to Person * Corrected GPS accuracy for Person * Added priority of sources to Person * Fixed formatting * Removed rounding of coordinates. * Added test for source priority. Changed test for rounding of coordinates. * Improved code style * Code style cleanup * Code style cleanup * Code style cleanup * Code style cleanup * Code style cleanup * Lint * Lint
This commit is contained in:
parent
070320a24a
commit
4a45510c88
2 changed files with 74 additions and 19 deletions
|
@ -8,10 +8,11 @@ import voluptuous as vol
|
||||||
|
|
||||||
from homeassistant.components import websocket_api
|
from homeassistant.components import websocket_api
|
||||||
from homeassistant.components.device_tracker import (
|
from homeassistant.components.device_tracker import (
|
||||||
DOMAIN as DEVICE_TRACKER_DOMAIN)
|
DOMAIN as DEVICE_TRACKER_DOMAIN, ATTR_SOURCE_TYPE, SOURCE_TYPE_GPS)
|
||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
ATTR_ID, ATTR_LATITUDE, ATTR_LONGITUDE, CONF_ID, CONF_NAME,
|
ATTR_ID, ATTR_LATITUDE, ATTR_LONGITUDE, ATTR_GPS_ACCURACY,
|
||||||
EVENT_HOMEASSISTANT_START, STATE_UNKNOWN, STATE_UNAVAILABLE)
|
CONF_ID, CONF_NAME, EVENT_HOMEASSISTANT_START,
|
||||||
|
STATE_UNKNOWN, STATE_UNAVAILABLE, STATE_HOME, STATE_NOT_HOME)
|
||||||
from homeassistant.core import callback, Event
|
from homeassistant.core import callback, Event
|
||||||
from homeassistant.auth import EVENT_USER_REMOVED
|
from homeassistant.auth import EVENT_USER_REMOVED
|
||||||
import homeassistant.helpers.config_validation as cv
|
import homeassistant.helpers.config_validation as cv
|
||||||
|
@ -285,6 +286,7 @@ class Person(RestoreEntity):
|
||||||
self._editable = editable
|
self._editable = editable
|
||||||
self._latitude = None
|
self._latitude = None
|
||||||
self._longitude = None
|
self._longitude = None
|
||||||
|
self._gps_accuracy = None
|
||||||
self._source = None
|
self._source = None
|
||||||
self._state = None
|
self._state = None
|
||||||
self._unsub_track_device = None
|
self._unsub_track_device = None
|
||||||
|
@ -315,9 +317,11 @@ class Person(RestoreEntity):
|
||||||
ATTR_ID: self.unique_id,
|
ATTR_ID: self.unique_id,
|
||||||
}
|
}
|
||||||
if self._latitude is not None:
|
if self._latitude is not None:
|
||||||
data[ATTR_LATITUDE] = round(self._latitude, 5)
|
data[ATTR_LATITUDE] = self._latitude
|
||||||
if self._longitude is not None:
|
if self._longitude is not None:
|
||||||
data[ATTR_LONGITUDE] = round(self._longitude, 5)
|
data[ATTR_LONGITUDE] = self._longitude
|
||||||
|
if self._gps_accuracy is not None:
|
||||||
|
data[ATTR_GPS_ACCURACY] = self._gps_accuracy
|
||||||
if self._source is not None:
|
if self._source is not None:
|
||||||
data[ATTR_SOURCE] = self._source
|
data[ATTR_SOURCE] = self._source
|
||||||
user_id = self._config.get(CONF_USER_ID)
|
user_id = self._config.get(CONF_USER_ID)
|
||||||
|
@ -373,18 +377,34 @@ class Person(RestoreEntity):
|
||||||
"""Handle the device tracker state changes."""
|
"""Handle the device tracker state changes."""
|
||||||
self._update_state()
|
self._update_state()
|
||||||
|
|
||||||
|
def _get_latest(self, prev, curr):
|
||||||
|
return curr \
|
||||||
|
if prev is None or curr.last_updated > prev.last_updated \
|
||||||
|
else prev
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
def _update_state(self):
|
def _update_state(self):
|
||||||
"""Update the state."""
|
"""Update the state."""
|
||||||
latest = None
|
latest_home = latest_not_home = latest_gps = latest = None
|
||||||
for entity_id in self._config.get(CONF_DEVICE_TRACKERS, []):
|
for entity_id in self._config.get(CONF_DEVICE_TRACKERS, []):
|
||||||
state = self.hass.states.get(entity_id)
|
state = self.hass.states.get(entity_id)
|
||||||
|
|
||||||
if not state or state.state in IGNORE_STATES:
|
if not state or state.state in IGNORE_STATES:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if latest is None or state.last_updated > latest.last_updated:
|
if state.attributes.get(ATTR_SOURCE_TYPE) == SOURCE_TYPE_GPS:
|
||||||
latest = state
|
latest_gps = self._get_latest(latest_gps, state)
|
||||||
|
elif state.state == STATE_HOME:
|
||||||
|
latest_home = self._get_latest(latest_home, state)
|
||||||
|
elif state.state == STATE_NOT_HOME:
|
||||||
|
latest_not_home = self._get_latest(latest_not_home, state)
|
||||||
|
|
||||||
|
if latest_home:
|
||||||
|
latest = latest_home
|
||||||
|
elif latest_gps:
|
||||||
|
latest = latest_gps
|
||||||
|
else:
|
||||||
|
latest = latest_not_home
|
||||||
|
|
||||||
if latest:
|
if latest:
|
||||||
self._parse_source_state(latest)
|
self._parse_source_state(latest)
|
||||||
|
@ -393,6 +413,7 @@ class Person(RestoreEntity):
|
||||||
self._source = None
|
self._source = None
|
||||||
self._latitude = None
|
self._latitude = None
|
||||||
self._longitude = None
|
self._longitude = None
|
||||||
|
self._gps_accuracy = None
|
||||||
|
|
||||||
self.async_schedule_update_ha_state()
|
self.async_schedule_update_ha_state()
|
||||||
|
|
||||||
|
@ -406,6 +427,7 @@ class Person(RestoreEntity):
|
||||||
self._source = state.entity_id
|
self._source = state.entity_id
|
||||||
self._latitude = state.attributes.get(ATTR_LATITUDE)
|
self._latitude = state.attributes.get(ATTR_LATITUDE)
|
||||||
self._longitude = state.attributes.get(ATTR_LONGITUDE)
|
self._longitude = state.attributes.get(ATTR_LONGITUDE)
|
||||||
|
self._gps_accuracy = state.attributes.get(ATTR_GPS_ACCURACY)
|
||||||
|
|
||||||
|
|
||||||
@websocket_api.websocket_command({
|
@websocket_api.websocket_command({
|
||||||
|
|
|
@ -4,8 +4,10 @@ from unittest.mock import Mock
|
||||||
from homeassistant.components.person import (
|
from homeassistant.components.person import (
|
||||||
ATTR_SOURCE, ATTR_USER_ID, DOMAIN, PersonManager)
|
ATTR_SOURCE, ATTR_USER_ID, DOMAIN, PersonManager)
|
||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
ATTR_ID, ATTR_LATITUDE, ATTR_LONGITUDE, STATE_UNKNOWN,
|
ATTR_ID, ATTR_LATITUDE, ATTR_LONGITUDE, ATTR_GPS_ACCURACY,
|
||||||
EVENT_HOMEASSISTANT_START)
|
STATE_UNKNOWN, EVENT_HOMEASSISTANT_START)
|
||||||
|
from homeassistant.components.device_tracker import (
|
||||||
|
ATTR_SOURCE_TYPE, SOURCE_TYPE_GPS, SOURCE_TYPE_ROUTER)
|
||||||
from homeassistant.core import CoreState, State
|
from homeassistant.core import CoreState, State
|
||||||
from homeassistant.setup import async_setup_component
|
from homeassistant.setup import async_setup_component
|
||||||
|
|
||||||
|
@ -134,15 +136,18 @@ async def test_setup_tracker(hass, hass_admin_user):
|
||||||
assert state.attributes.get(ATTR_USER_ID) == user_id
|
assert state.attributes.get(ATTR_USER_ID) == user_id
|
||||||
|
|
||||||
hass.states.async_set(
|
hass.states.async_set(
|
||||||
DEVICE_TRACKER, 'not_home',
|
DEVICE_TRACKER, 'not_home', {
|
||||||
{ATTR_LATITUDE: 10.123456, ATTR_LONGITUDE: 11.123456})
|
ATTR_LATITUDE: 10.123456,
|
||||||
|
ATTR_LONGITUDE: 11.123456,
|
||||||
|
ATTR_GPS_ACCURACY: 10})
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
state = hass.states.get('person.tracked_person')
|
state = hass.states.get('person.tracked_person')
|
||||||
assert state.state == 'not_home'
|
assert state.state == 'not_home'
|
||||||
assert state.attributes.get(ATTR_ID) == '1234'
|
assert state.attributes.get(ATTR_ID) == '1234'
|
||||||
assert state.attributes.get(ATTR_LATITUDE) == 10.12346
|
assert state.attributes.get(ATTR_LATITUDE) == 10.123456
|
||||||
assert state.attributes.get(ATTR_LONGITUDE) == 11.12346
|
assert state.attributes.get(ATTR_LONGITUDE) == 11.123456
|
||||||
|
assert state.attributes.get(ATTR_GPS_ACCURACY) == 10
|
||||||
assert state.attributes.get(ATTR_SOURCE) == DEVICE_TRACKER
|
assert state.attributes.get(ATTR_SOURCE) == DEVICE_TRACKER
|
||||||
assert state.attributes.get(ATTR_USER_ID) == user_id
|
assert state.attributes.get(ATTR_USER_ID) == user_id
|
||||||
|
|
||||||
|
@ -166,7 +171,8 @@ async def test_setup_two_trackers(hass, hass_admin_user):
|
||||||
|
|
||||||
hass.bus.async_fire(EVENT_HOMEASSISTANT_START)
|
hass.bus.async_fire(EVENT_HOMEASSISTANT_START)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
hass.states.async_set(DEVICE_TRACKER, 'home')
|
hass.states.async_set(
|
||||||
|
DEVICE_TRACKER, 'home', {ATTR_SOURCE_TYPE: SOURCE_TYPE_ROUTER})
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
state = hass.states.get('person.tracked_person')
|
state = hass.states.get('person.tracked_person')
|
||||||
|
@ -174,22 +180,49 @@ async def test_setup_two_trackers(hass, hass_admin_user):
|
||||||
assert state.attributes.get(ATTR_ID) == '1234'
|
assert state.attributes.get(ATTR_ID) == '1234'
|
||||||
assert state.attributes.get(ATTR_LATITUDE) is None
|
assert state.attributes.get(ATTR_LATITUDE) is None
|
||||||
assert state.attributes.get(ATTR_LONGITUDE) is None
|
assert state.attributes.get(ATTR_LONGITUDE) is None
|
||||||
|
assert state.attributes.get(ATTR_GPS_ACCURACY) is None
|
||||||
assert state.attributes.get(ATTR_SOURCE) == DEVICE_TRACKER
|
assert state.attributes.get(ATTR_SOURCE) == DEVICE_TRACKER
|
||||||
assert state.attributes.get(ATTR_USER_ID) == user_id
|
assert state.attributes.get(ATTR_USER_ID) == user_id
|
||||||
|
|
||||||
hass.states.async_set(
|
hass.states.async_set(
|
||||||
DEVICE_TRACKER_2, 'not_home',
|
DEVICE_TRACKER_2, 'not_home', {
|
||||||
{ATTR_LATITUDE: 12.123456, ATTR_LONGITUDE: 13.123456})
|
ATTR_LATITUDE: 12.123456,
|
||||||
|
ATTR_LONGITUDE: 13.123456,
|
||||||
|
ATTR_GPS_ACCURACY: 12,
|
||||||
|
ATTR_SOURCE_TYPE: SOURCE_TYPE_GPS})
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
hass.states.async_set(
|
||||||
|
DEVICE_TRACKER, 'not_home', {ATTR_SOURCE_TYPE: SOURCE_TYPE_ROUTER})
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
state = hass.states.get('person.tracked_person')
|
state = hass.states.get('person.tracked_person')
|
||||||
assert state.state == 'not_home'
|
assert state.state == 'not_home'
|
||||||
assert state.attributes.get(ATTR_ID) == '1234'
|
assert state.attributes.get(ATTR_ID) == '1234'
|
||||||
assert state.attributes.get(ATTR_LATITUDE) == 12.12346
|
assert state.attributes.get(ATTR_LATITUDE) == 12.123456
|
||||||
assert state.attributes.get(ATTR_LONGITUDE) == 13.12346
|
assert state.attributes.get(ATTR_LONGITUDE) == 13.123456
|
||||||
|
assert state.attributes.get(ATTR_GPS_ACCURACY) == 12
|
||||||
assert state.attributes.get(ATTR_SOURCE) == DEVICE_TRACKER_2
|
assert state.attributes.get(ATTR_SOURCE) == DEVICE_TRACKER_2
|
||||||
assert state.attributes.get(ATTR_USER_ID) == user_id
|
assert state.attributes.get(ATTR_USER_ID) == user_id
|
||||||
|
|
||||||
|
hass.states.async_set(
|
||||||
|
DEVICE_TRACKER_2, 'zone1', {ATTR_SOURCE_TYPE: SOURCE_TYPE_GPS})
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
state = hass.states.get('person.tracked_person')
|
||||||
|
assert state.state == 'zone1'
|
||||||
|
assert state.attributes.get(ATTR_SOURCE) == DEVICE_TRACKER_2
|
||||||
|
|
||||||
|
hass.states.async_set(
|
||||||
|
DEVICE_TRACKER, 'home', {ATTR_SOURCE_TYPE: SOURCE_TYPE_ROUTER})
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
hass.states.async_set(
|
||||||
|
DEVICE_TRACKER_2, 'zone2', {ATTR_SOURCE_TYPE: SOURCE_TYPE_GPS})
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
state = hass.states.get('person.tracked_person')
|
||||||
|
assert state.state == 'home'
|
||||||
|
assert state.attributes.get(ATTR_SOURCE) == DEVICE_TRACKER
|
||||||
|
|
||||||
|
|
||||||
async def test_ignore_unavailable_states(hass, hass_admin_user):
|
async def test_ignore_unavailable_states(hass, hass_admin_user):
|
||||||
"""Test set up person with two device trackers, one unavailable."""
|
"""Test set up person with two device trackers, one unavailable."""
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue