Add consider_home and source_type to device_tracker.see service (#12849)

* Add consider_home and source_type to device_tracker.see service

* Use schema instead of manual validation

* Extend schema to validate all keys

* Fix style

* Set battery level to int
This commit is contained in:
mueslo 2018-03-09 08:57:21 +01:00 committed by Paulus Schoutsen
parent 6734c966b3
commit 3ba19c52d5
2 changed files with 43 additions and 22 deletions

View File

@ -77,11 +77,14 @@ ATTR_MAC = 'mac'
ATTR_NAME = 'name'
ATTR_SOURCE_TYPE = 'source_type'
ATTR_VENDOR = 'vendor'
ATTR_CONSIDER_HOME = 'consider_home'
SOURCE_TYPE_GPS = 'gps'
SOURCE_TYPE_ROUTER = 'router'
SOURCE_TYPE_BLUETOOTH = 'bluetooth'
SOURCE_TYPE_BLUETOOTH_LE = 'bluetooth_le'
SOURCE_TYPES = (SOURCE_TYPE_GPS, SOURCE_TYPE_ROUTER,
SOURCE_TYPE_BLUETOOTH, SOURCE_TYPE_BLUETOOTH_LE)
NEW_DEVICE_DEFAULTS_SCHEMA = vol.Any(None, vol.Schema({
vol.Optional(CONF_TRACK_NEW, default=DEFAULT_TRACK_NEW): cv.boolean,
@ -96,6 +99,19 @@ PLATFORM_SCHEMA = cv.PLATFORM_SCHEMA.extend({
vol.Optional(CONF_NEW_DEVICE_DEFAULTS,
default={}): NEW_DEVICE_DEFAULTS_SCHEMA
})
SERVICE_SEE_PAYLOAD_SCHEMA = vol.Schema(vol.All(
cv.has_at_least_one_key(ATTR_MAC, ATTR_DEV_ID), {
ATTR_MAC: cv.string,
ATTR_DEV_ID: cv.string,
ATTR_HOST_NAME: cv.string,
ATTR_LOCATION_NAME: cv.string,
ATTR_GPS: cv.gps,
ATTR_GPS_ACCURACY: cv.positive_int,
ATTR_BATTERY: cv.positive_int,
ATTR_ATTRIBUTES: dict,
ATTR_SOURCE_TYPE: vol.In(SOURCE_TYPES),
ATTR_CONSIDER_HOME: cv.time_period,
}))
@bind_hass
@ -109,7 +125,7 @@ def is_on(hass: HomeAssistantType, entity_id: str = None):
def see(hass: HomeAssistantType, mac: str = None, dev_id: str = None,
host_name: str = None, location_name: str = None,
gps: GPSType = None, gps_accuracy=None,
battery=None, attributes: dict = None):
battery: int = None, attributes: dict = None):
"""Call service to notify you see device."""
data = {key: value for key, value in
((ATTR_MAC, mac),
@ -203,12 +219,10 @@ def async_setup(hass: HomeAssistantType, config: ConfigType):
@asyncio.coroutine
def async_see_service(call):
"""Service to see a device."""
args = {key: value for key, value in call.data.items() if key in
(ATTR_MAC, ATTR_DEV_ID, ATTR_HOST_NAME, ATTR_LOCATION_NAME,
ATTR_GPS, ATTR_GPS_ACCURACY, ATTR_BATTERY, ATTR_ATTRIBUTES)}
yield from tracker.async_see(**args)
yield from tracker.async_see(**call.data)
hass.services.async_register(DOMAIN, SERVICE_SEE, async_see_service)
hass.services.async_register(
DOMAIN, SERVICE_SEE, async_see_service, SERVICE_SEE_PAYLOAD_SCHEMA)
# restore
yield from tracker.async_setup_tracked_device()
@ -240,23 +254,26 @@ class DeviceTracker(object):
dev.mac)
def see(self, mac: str = None, dev_id: str = None, host_name: str = None,
location_name: str = None, gps: GPSType = None, gps_accuracy=None,
battery: str = None, attributes: dict = None,
source_type: str = SOURCE_TYPE_GPS, picture: str = None,
icon: str = None):
location_name: str = None, gps: GPSType = None,
gps_accuracy: int = None, battery: int = None,
attributes: dict = None, source_type: str = SOURCE_TYPE_GPS,
picture: str = None, icon: str = None,
consider_home: timedelta = None):
"""Notify the device tracker that you see a device."""
self.hass.add_job(
self.async_see(mac, dev_id, host_name, location_name, gps,
gps_accuracy, battery, attributes, source_type,
picture, icon)
picture, icon, consider_home)
)
@asyncio.coroutine
def async_see(self, mac: str = None, dev_id: str = None,
host_name: str = None, location_name: str = None,
gps: GPSType = None, gps_accuracy=None, battery: str = None,
attributes: dict = None, source_type: str = SOURCE_TYPE_GPS,
picture: str = None, icon: str = None):
def async_see(
self, mac: str = None, dev_id: str = None, host_name: str = None,
location_name: str = None, gps: GPSType = None,
gps_accuracy: int = None, battery: int = None,
attributes: dict = None, source_type: str = SOURCE_TYPE_GPS,
picture: str = None, icon: str = None,
consider_home: timedelta = None):
"""Notify the device tracker that you see a device.
This method is a coroutine.
@ -275,7 +292,7 @@ class DeviceTracker(object):
if device:
yield from device.async_seen(
host_name, location_name, gps, gps_accuracy, battery,
attributes, source_type)
attributes, source_type, consider_home)
if device.track:
yield from device.async_update_ha_state()
return
@ -283,7 +300,7 @@ class DeviceTracker(object):
# If no device can be found, create it
dev_id = util.ensure_unique_string(dev_id, self.devices.keys())
device = Device(
self.hass, self.consider_home, self.track_new,
self.hass, consider_home or self.consider_home, self.track_new,
dev_id, mac, (host_name or dev_id).replace('_', ' '),
picture=picture, icon=icon,
hide_if_away=self.defaults.get(CONF_AWAY_HIDE, DEFAULT_AWAY_HIDE))
@ -384,9 +401,10 @@ class Device(Entity):
host_name = None # type: str
location_name = None # type: str
gps = None # type: GPSType
gps_accuracy = 0
gps_accuracy = 0 # type: int
last_seen = None # type: dt_util.dt.datetime
battery = None # type: str
consider_home = None # type: dt_util.dt.timedelta
battery = None # type: int
attributes = None # type: dict
vendor = None # type: str
icon = None # type: str
@ -476,14 +494,16 @@ class Device(Entity):
@asyncio.coroutine
def async_seen(self, host_name: str = None, location_name: str = None,
gps: GPSType = None, gps_accuracy=0, battery: str = None,
gps: GPSType = None, gps_accuracy=0, battery: int = None,
attributes: dict = None,
source_type: str = SOURCE_TYPE_GPS):
source_type: str = SOURCE_TYPE_GPS,
consider_home: timedelta = None):
"""Mark the device as seen."""
self.source_type = source_type
self.last_seen = dt_util.utcnow()
self.host_name = host_name
self.location_name = location_name
self.consider_home = consider_home or self.consider_home
if battery:
self.battery = battery

View File

@ -36,6 +36,7 @@ latitude = vol.All(vol.Coerce(float), vol.Range(min=-90, max=90),
msg='invalid latitude')
longitude = vol.All(vol.Coerce(float), vol.Range(min=-180, max=180),
msg='invalid longitude')
gps = vol.ExactSequence([latitude, longitude])
sun_event = vol.All(vol.Lower, vol.Any(SUN_EVENT_SUNSET, SUN_EVENT_SUNRISE))
port = vol.All(vol.Coerce(int), vol.Range(min=1, max=65535))