Battery attribute & accuracy filter (#24277)
* Extract const to a const file, Add battery as tracker attribute, add accuracy filter option * Update homeassistant/components/traccar/device_tracker.py Co-Authored-By: Otto Winter <otto@otto-winter.com> * Update homeassistant/components/traccar/device_tracker.py Co-Authored-By: Otto Winter <otto@otto-winter.com> * Update homeassistant/components/traccar/device_tracker.py Use [] syntax for keys that are in the validated data. Co-Authored-By: Otto Winter <otto@otto-winter.com> * Fix indentation
This commit is contained in:
parent
08eca4a237
commit
ddeb6b6baa
3 changed files with 68 additions and 36 deletions
|
@ -631,6 +631,7 @@ omit =
|
||||||
homeassistant/components/tplink/switch.py
|
homeassistant/components/tplink/switch.py
|
||||||
homeassistant/components/tplink_lte/*
|
homeassistant/components/tplink_lte/*
|
||||||
homeassistant/components/traccar/device_tracker.py
|
homeassistant/components/traccar/device_tracker.py
|
||||||
|
homeassistant/components/traccar/const.py
|
||||||
homeassistant/components/trackr/device_tracker.py
|
homeassistant/components/trackr/device_tracker.py
|
||||||
homeassistant/components/tradfri/*
|
homeassistant/components/tradfri/*
|
||||||
homeassistant/components/tradfri/light.py
|
homeassistant/components/tradfri/light.py
|
||||||
|
|
31
homeassistant/components/traccar/const.py
Normal file
31
homeassistant/components/traccar/const.py
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
"""Constants for Traccar integration."""
|
||||||
|
|
||||||
|
CONF_MAX_ACCURACY = 'max_accuracy'
|
||||||
|
CONF_SKIP_ACCURACY_ON = 'skip_accuracy_filter_on'
|
||||||
|
|
||||||
|
ATTR_ADDRESS = 'address'
|
||||||
|
ATTR_CATEGORY = 'category'
|
||||||
|
ATTR_GEOFENCE = 'geofence'
|
||||||
|
ATTR_MOTION = 'motion'
|
||||||
|
ATTR_SPEED = 'speed'
|
||||||
|
ATTR_TRACKER = 'tracker'
|
||||||
|
ATTR_TRACCAR_ID = 'traccar_id'
|
||||||
|
ATTR_STATUS = 'status'
|
||||||
|
|
||||||
|
EVENT_DEVICE_MOVING = 'device_moving'
|
||||||
|
EVENT_COMMAND_RESULT = 'command_result'
|
||||||
|
EVENT_DEVICE_FUEL_DROP = 'device_fuel_drop'
|
||||||
|
EVENT_GEOFENCE_ENTER = 'geofence_enter'
|
||||||
|
EVENT_DEVICE_OFFLINE = 'device_offline'
|
||||||
|
EVENT_DRIVER_CHANGED = 'driver_changed'
|
||||||
|
EVENT_GEOFENCE_EXIT = 'geofence_exit'
|
||||||
|
EVENT_DEVICE_OVERSPEED = 'device_overspeed'
|
||||||
|
EVENT_DEVICE_ONLINE = 'device_online'
|
||||||
|
EVENT_DEVICE_STOPPED = 'device_stopped'
|
||||||
|
EVENT_MAINTENANCE = 'maintenance'
|
||||||
|
EVENT_ALARM = 'alarm'
|
||||||
|
EVENT_TEXT_MESSAGE = 'text_message'
|
||||||
|
EVENT_DEVICE_UNKNOWN = 'device_unknown'
|
||||||
|
EVENT_IGNITION_OFF = 'ignition_off'
|
||||||
|
EVENT_IGNITION_ON = 'ignition_on'
|
||||||
|
EVENT_ALL_EVENTS = 'all_events'
|
|
@ -7,44 +7,25 @@ import voluptuous as vol
|
||||||
from homeassistant.components.device_tracker import PLATFORM_SCHEMA
|
from homeassistant.components.device_tracker import PLATFORM_SCHEMA
|
||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
CONF_HOST, CONF_PORT, CONF_SSL, CONF_VERIFY_SSL,
|
CONF_HOST, CONF_PORT, CONF_SSL, CONF_VERIFY_SSL,
|
||||||
CONF_PASSWORD, CONF_USERNAME, ATTR_BATTERY_LEVEL,
|
CONF_PASSWORD, CONF_USERNAME, CONF_SCAN_INTERVAL,
|
||||||
CONF_SCAN_INTERVAL, CONF_MONITORED_CONDITIONS,
|
CONF_MONITORED_CONDITIONS, CONF_EVENT)
|
||||||
CONF_EVENT)
|
|
||||||
import homeassistant.helpers.config_validation as cv
|
import homeassistant.helpers.config_validation as cv
|
||||||
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
||||||
from homeassistant.helpers.event import async_track_time_interval
|
from homeassistant.helpers.event import async_track_time_interval
|
||||||
from homeassistant.util import slugify
|
from homeassistant.util import slugify
|
||||||
|
from .const import (
|
||||||
|
ATTR_ADDRESS, ATTR_CATEGORY, ATTR_GEOFENCE,
|
||||||
|
ATTR_MOTION, ATTR_SPEED, ATTR_TRACKER, ATTR_TRACCAR_ID, ATTR_STATUS,
|
||||||
|
EVENT_DEVICE_MOVING, EVENT_COMMAND_RESULT, EVENT_DEVICE_FUEL_DROP,
|
||||||
|
EVENT_GEOFENCE_ENTER, EVENT_DEVICE_OFFLINE, EVENT_DRIVER_CHANGED,
|
||||||
|
EVENT_GEOFENCE_EXIT, EVENT_DEVICE_OVERSPEED, EVENT_DEVICE_ONLINE,
|
||||||
|
EVENT_DEVICE_STOPPED, EVENT_MAINTENANCE, EVENT_ALARM, EVENT_TEXT_MESSAGE,
|
||||||
|
EVENT_DEVICE_UNKNOWN, EVENT_IGNITION_OFF, EVENT_IGNITION_ON,
|
||||||
|
EVENT_ALL_EVENTS, CONF_MAX_ACCURACY, CONF_SKIP_ACCURACY_ON)
|
||||||
|
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
ATTR_ADDRESS = 'address'
|
|
||||||
ATTR_CATEGORY = 'category'
|
|
||||||
ATTR_GEOFENCE = 'geofence'
|
|
||||||
ATTR_MOTION = 'motion'
|
|
||||||
ATTR_SPEED = 'speed'
|
|
||||||
ATTR_TRACKER = 'tracker'
|
|
||||||
ATTR_TRACCAR_ID = 'traccar_id'
|
|
||||||
ATTR_STATUS = 'status'
|
|
||||||
|
|
||||||
EVENT_DEVICE_MOVING = 'device_moving'
|
|
||||||
EVENT_COMMAND_RESULT = 'command_result'
|
|
||||||
EVENT_DEVICE_FUEL_DROP = 'device_fuel_drop'
|
|
||||||
EVENT_GEOFENCE_ENTER = 'geofence_enter'
|
|
||||||
EVENT_DEVICE_OFFLINE = 'device_offline'
|
|
||||||
EVENT_DRIVER_CHANGED = 'driver_changed'
|
|
||||||
EVENT_GEOFENCE_EXIT = 'geofence_exit'
|
|
||||||
EVENT_DEVICE_OVERSPEED = 'device_overspeed'
|
|
||||||
EVENT_DEVICE_ONLINE = 'device_online'
|
|
||||||
EVENT_DEVICE_STOPPED = 'device_stopped'
|
|
||||||
EVENT_MAINTENANCE = 'maintenance'
|
|
||||||
EVENT_ALARM = 'alarm'
|
|
||||||
EVENT_TEXT_MESSAGE = 'text_message'
|
|
||||||
EVENT_DEVICE_UNKNOWN = 'device_unknown'
|
|
||||||
EVENT_IGNITION_OFF = 'ignition_off'
|
|
||||||
EVENT_IGNITION_ON = 'ignition_on'
|
|
||||||
EVENT_ALL_EVENTS = 'all_events'
|
|
||||||
|
|
||||||
DEFAULT_SCAN_INTERVAL = timedelta(seconds=30)
|
DEFAULT_SCAN_INTERVAL = timedelta(seconds=30)
|
||||||
SCAN_INTERVAL = DEFAULT_SCAN_INTERVAL
|
SCAN_INTERVAL = DEFAULT_SCAN_INTERVAL
|
||||||
|
|
||||||
|
@ -55,6 +36,10 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
|
||||||
vol.Optional(CONF_PORT, default=8082): cv.port,
|
vol.Optional(CONF_PORT, default=8082): cv.port,
|
||||||
vol.Optional(CONF_SSL, default=False): cv.boolean,
|
vol.Optional(CONF_SSL, default=False): cv.boolean,
|
||||||
vol.Optional(CONF_VERIFY_SSL, default=True): cv.boolean,
|
vol.Optional(CONF_VERIFY_SSL, default=True): cv.boolean,
|
||||||
|
vol.Required(CONF_MAX_ACCURACY, default=0): vol.All(vol.Coerce(int),
|
||||||
|
vol.Range(min=0)),
|
||||||
|
vol.Optional(CONF_SKIP_ACCURACY_ON,
|
||||||
|
default=[]): vol.All(cv.ensure_list, [cv.string]),
|
||||||
vol.Optional(CONF_MONITORED_CONDITIONS,
|
vol.Optional(CONF_MONITORED_CONDITIONS,
|
||||||
default=[]): vol.All(cv.ensure_list, [cv.string]),
|
default=[]): vol.All(cv.ensure_list, [cv.string]),
|
||||||
vol.Optional(CONF_EVENT,
|
vol.Optional(CONF_EVENT,
|
||||||
|
@ -91,6 +76,7 @@ async def async_setup_scanner(hass, config, async_see, discovery_info=None):
|
||||||
scanner = TraccarScanner(
|
scanner = TraccarScanner(
|
||||||
api, hass, async_see,
|
api, hass, async_see,
|
||||||
config.get(CONF_SCAN_INTERVAL, SCAN_INTERVAL),
|
config.get(CONF_SCAN_INTERVAL, SCAN_INTERVAL),
|
||||||
|
config[CONF_MAX_ACCURACY], config[CONF_SKIP_ACCURACY_ON],
|
||||||
config[CONF_MONITORED_CONDITIONS], config[CONF_EVENT])
|
config[CONF_MONITORED_CONDITIONS], config[CONF_EVENT])
|
||||||
|
|
||||||
return await scanner.async_init()
|
return await scanner.async_init()
|
||||||
|
@ -99,9 +85,8 @@ async def async_setup_scanner(hass, config, async_see, discovery_info=None):
|
||||||
class TraccarScanner:
|
class TraccarScanner:
|
||||||
"""Define an object to retrieve Traccar data."""
|
"""Define an object to retrieve Traccar data."""
|
||||||
|
|
||||||
def __init__(self, api, hass, async_see, scan_interval,
|
def __init__(self, api, hass, async_see, scan_interval, max_accuracy,
|
||||||
custom_attributes,
|
skip_accuracy_on, custom_attributes, event_types):
|
||||||
event_types):
|
|
||||||
"""Initialize."""
|
"""Initialize."""
|
||||||
from stringcase import camelcase
|
from stringcase import camelcase
|
||||||
self._event_types = {camelcase(evt): evt for evt in event_types}
|
self._event_types = {camelcase(evt): evt for evt in event_types}
|
||||||
|
@ -111,6 +96,8 @@ class TraccarScanner:
|
||||||
self._api = api
|
self._api = api
|
||||||
self.connected = False
|
self.connected = False
|
||||||
self._hass = hass
|
self._hass = hass
|
||||||
|
self._max_accuracy = max_accuracy
|
||||||
|
self._skip_accuracy_on = skip_accuracy_on
|
||||||
|
|
||||||
async def async_init(self):
|
async def async_init(self):
|
||||||
"""Further initialize connection to Traccar."""
|
"""Further initialize connection to Traccar."""
|
||||||
|
@ -148,6 +135,8 @@ class TraccarScanner:
|
||||||
device_info = self._api.device_info[device_unique_id]
|
device_info = self._api.device_info[device_unique_id]
|
||||||
device = None
|
device = None
|
||||||
attr = {}
|
attr = {}
|
||||||
|
skip_accuracy_filter = False
|
||||||
|
|
||||||
attr[ATTR_TRACKER] = 'traccar'
|
attr[ATTR_TRACKER] = 'traccar'
|
||||||
if device_info.get('address') is not None:
|
if device_info.get('address') is not None:
|
||||||
attr[ATTR_ADDRESS] = device_info['address']
|
attr[ATTR_ADDRESS] = device_info['address']
|
||||||
|
@ -157,8 +146,6 @@ class TraccarScanner:
|
||||||
attr[ATTR_CATEGORY] = device_info['category']
|
attr[ATTR_CATEGORY] = device_info['category']
|
||||||
if device_info.get('speed') is not None:
|
if device_info.get('speed') is not None:
|
||||||
attr[ATTR_SPEED] = device_info['speed']
|
attr[ATTR_SPEED] = device_info['speed']
|
||||||
if device_info.get('battery') is not None:
|
|
||||||
attr[ATTR_BATTERY_LEVEL] = device_info['battery']
|
|
||||||
if device_info.get('motion') is not None:
|
if device_info.get('motion') is not None:
|
||||||
attr[ATTR_MOTION] = device_info['motion']
|
attr[ATTR_MOTION] = device_info['motion']
|
||||||
if device_info.get('traccar_id') is not None:
|
if device_info.get('traccar_id') is not None:
|
||||||
|
@ -172,11 +159,24 @@ class TraccarScanner:
|
||||||
for custom_attr in self._custom_attributes:
|
for custom_attr in self._custom_attributes:
|
||||||
if device_info.get(custom_attr) is not None:
|
if device_info.get(custom_attr) is not None:
|
||||||
attr[custom_attr] = device_info[custom_attr]
|
attr[custom_attr] = device_info[custom_attr]
|
||||||
|
if custom_attr in self._skip_accuracy_on:
|
||||||
|
skip_accuracy_filter = True
|
||||||
|
|
||||||
|
accuracy = 0.0
|
||||||
|
if device_info.get('accuracy') is not None:
|
||||||
|
accuracy = device_info['accuracy']
|
||||||
|
if (not skip_accuracy_filter and self._max_accuracy > 0 and
|
||||||
|
accuracy > self._max_accuracy):
|
||||||
|
_LOGGER.debug('Excluded position by accuracy filter: %f (%s)',
|
||||||
|
accuracy, attr[ATTR_TRACCAR_ID])
|
||||||
|
continue
|
||||||
|
|
||||||
await self._async_see(
|
await self._async_see(
|
||||||
dev_id=slugify(device_info['device_id']),
|
dev_id=slugify(device_info['device_id']),
|
||||||
gps=(device_info.get('latitude'),
|
gps=(device_info.get('latitude'),
|
||||||
device_info.get('longitude')),
|
device_info.get('longitude')),
|
||||||
gps_accuracy=(device_info.get('accuracy')),
|
gps_accuracy=accuracy,
|
||||||
|
battery=device_info.get('battery'),
|
||||||
attributes=attr)
|
attributes=attr)
|
||||||
|
|
||||||
async def import_events(self):
|
async def import_events(self):
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue