mirror of
https://github.com/home-assistant/core.git
synced 2025-07-15 09:17:10 +00:00
Migrate mqtt tracker and arwn sensor to async / cleanup owntrack (#6373)
* Migrate mqtt tracker and arwn sensor to async / cleanup owntrack * Fix tests / lint
This commit is contained in:
parent
55f8ec8866
commit
ed9e93c29f
@ -4,11 +4,13 @@ Support for tracking MQTT enabled devices.
|
|||||||
For more details about this platform, please refer to the documentation at
|
For more details about this platform, please refer to the documentation at
|
||||||
https://home-assistant.io/components/device_tracker.mqtt/
|
https://home-assistant.io/components/device_tracker.mqtt/
|
||||||
"""
|
"""
|
||||||
|
import asyncio
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
|
|
||||||
import homeassistant.components.mqtt as mqtt
|
import homeassistant.components.mqtt as mqtt
|
||||||
|
from homeassistant.core import callback
|
||||||
from homeassistant.const import CONF_DEVICES
|
from homeassistant.const import CONF_DEVICES
|
||||||
from homeassistant.components.mqtt import CONF_QOS
|
from homeassistant.components.mqtt import CONF_QOS
|
||||||
from homeassistant.components.device_tracker import PLATFORM_SCHEMA
|
from homeassistant.components.device_tracker import PLATFORM_SCHEMA
|
||||||
@ -23,19 +25,23 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(mqtt.SCHEMA_BASE).extend({
|
|||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
def setup_scanner(hass, config, see, discovery_info=None):
|
@asyncio.coroutine
|
||||||
|
def async_setup_scanner(hass, config, async_see, discovery_info=None):
|
||||||
"""Setup the MQTT tracker."""
|
"""Setup the MQTT tracker."""
|
||||||
devices = config[CONF_DEVICES]
|
devices = config[CONF_DEVICES]
|
||||||
qos = config[CONF_QOS]
|
qos = config[CONF_QOS]
|
||||||
|
|
||||||
dev_id_lookup = {}
|
dev_id_lookup = {}
|
||||||
|
|
||||||
def device_tracker_message_received(topic, payload, qos):
|
@callback
|
||||||
|
def async_tracker_message_received(topic, payload, qos):
|
||||||
"""MQTT message received."""
|
"""MQTT message received."""
|
||||||
see(dev_id=dev_id_lookup[topic], location_name=payload)
|
hass.async_add_job(
|
||||||
|
async_see(dev_id=dev_id_lookup[topic], location_name=payload))
|
||||||
|
|
||||||
for dev_id, topic in devices.items():
|
for dev_id, topic in devices.items():
|
||||||
dev_id_lookup[topic] = dev_id
|
dev_id_lookup[topic] = dev_id
|
||||||
mqtt.subscribe(hass, topic, device_tracker_message_received, qos)
|
yield from mqtt.async_subscribe(
|
||||||
|
hass, topic, async_tracker_message_received, qos)
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
@ -55,7 +55,6 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
|
|||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
@callback
|
|
||||||
def get_cipher():
|
def get_cipher():
|
||||||
"""Return decryption function and length of key.
|
"""Return decryption function and length of key.
|
||||||
|
|
||||||
@ -81,7 +80,6 @@ def async_setup_scanner(hass, config, async_see, discovery_info=None):
|
|||||||
mobile_beacons_active = defaultdict(list)
|
mobile_beacons_active = defaultdict(list)
|
||||||
regions_entered = defaultdict(list)
|
regions_entered = defaultdict(list)
|
||||||
|
|
||||||
@callback
|
|
||||||
def decrypt_payload(topic, ciphertext):
|
def decrypt_payload(topic, ciphertext):
|
||||||
"""Decrypt encrypted payload."""
|
"""Decrypt encrypted payload."""
|
||||||
try:
|
try:
|
||||||
@ -119,7 +117,6 @@ def async_setup_scanner(hass, config, async_see, discovery_info=None):
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
# pylint: disable=too-many-return-statements
|
# pylint: disable=too-many-return-statements
|
||||||
@callback
|
|
||||||
def validate_payload(topic, payload, data_type):
|
def validate_payload(topic, payload, data_type):
|
||||||
"""Validate the OwnTracks payload."""
|
"""Validate the OwnTracks payload."""
|
||||||
try:
|
try:
|
||||||
@ -201,7 +198,6 @@ def async_setup_scanner(hass, config, async_see, discovery_info=None):
|
|||||||
|
|
||||||
dev_id, kwargs = _parse_see_args(topic, data)
|
dev_id, kwargs = _parse_see_args(topic, data)
|
||||||
|
|
||||||
@callback
|
|
||||||
def enter_event():
|
def enter_event():
|
||||||
"""Execute enter event."""
|
"""Execute enter event."""
|
||||||
zone = hass.states.get("zone.{}".format(slugify(location)))
|
zone = hass.states.get("zone.{}".format(slugify(location)))
|
||||||
@ -222,7 +218,6 @@ def async_setup_scanner(hass, config, async_see, discovery_info=None):
|
|||||||
hass.async_add_job(async_see(**kwargs))
|
hass.async_add_job(async_see(**kwargs))
|
||||||
async_see_beacons(dev_id, kwargs)
|
async_see_beacons(dev_id, kwargs)
|
||||||
|
|
||||||
@callback
|
|
||||||
def leave_event():
|
def leave_event():
|
||||||
"""Execute leave event."""
|
"""Execute leave event."""
|
||||||
regions = regions_entered[dev_id]
|
regions = regions_entered[dev_id]
|
||||||
@ -336,7 +331,6 @@ def async_setup_scanner(hass, config, async_see, discovery_info=None):
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
@callback
|
|
||||||
def parse_topic(topic, pretty=False):
|
def parse_topic(topic, pretty=False):
|
||||||
"""Parse an MQTT topic owntracks/user/dev, return (user, dev) tuple.
|
"""Parse an MQTT topic owntracks/user/dev, return (user, dev) tuple.
|
||||||
|
|
||||||
@ -353,7 +347,6 @@ def parse_topic(topic, pretty=False):
|
|||||||
return (host_name, dev_id)
|
return (host_name, dev_id)
|
||||||
|
|
||||||
|
|
||||||
@callback
|
|
||||||
def _parse_see_args(topic, data):
|
def _parse_see_args(topic, data):
|
||||||
"""Parse the OwnTracks location parameters, into the format see expects.
|
"""Parse the OwnTracks location parameters, into the format see expects.
|
||||||
|
|
||||||
@ -372,7 +365,6 @@ def _parse_see_args(topic, data):
|
|||||||
return dev_id, kwargs
|
return dev_id, kwargs
|
||||||
|
|
||||||
|
|
||||||
@callback
|
|
||||||
def _set_gps_from_zone(kwargs, location, zone):
|
def _set_gps_from_zone(kwargs, location, zone):
|
||||||
"""Set the see parameters from the zone parameters.
|
"""Set the see parameters from the zone parameters.
|
||||||
|
|
||||||
|
@ -4,11 +4,13 @@ Support for collecting data from the ARWN project.
|
|||||||
For more details about this platform, please refer to the documentation at
|
For more details about this platform, please refer to the documentation at
|
||||||
https://home-assistant.io/components/sensor.arwn/
|
https://home-assistant.io/components/sensor.arwn/
|
||||||
"""
|
"""
|
||||||
|
import asyncio
|
||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
import homeassistant.components.mqtt as mqtt
|
import homeassistant.components.mqtt as mqtt
|
||||||
from homeassistant.const import (TEMP_FAHRENHEIT, TEMP_CELSIUS)
|
from homeassistant.core import callback
|
||||||
|
from homeassistant.const import TEMP_FAHRENHEIT, TEMP_CELSIUS
|
||||||
from homeassistant.helpers.entity import Entity
|
from homeassistant.helpers.entity import Entity
|
||||||
from homeassistant.util import slugify
|
from homeassistant.util import slugify
|
||||||
|
|
||||||
@ -17,13 +19,15 @@ _LOGGER = logging.getLogger(__name__)
|
|||||||
DEPENDENCIES = ['mqtt']
|
DEPENDENCIES = ['mqtt']
|
||||||
DOMAIN = 'arwn'
|
DOMAIN = 'arwn'
|
||||||
|
|
||||||
SENSORS = {}
|
DATA_ARWN = 'arwn'
|
||||||
|
|
||||||
TOPIC = 'arwn/#'
|
TOPIC = 'arwn/#'
|
||||||
|
|
||||||
|
|
||||||
def discover_sensors(topic, payload):
|
def discover_sensors(topic, payload):
|
||||||
"""Given a topic, dynamically create the right sensor type."""
|
"""Given a topic, dynamically create the right sensor type.
|
||||||
|
|
||||||
|
Async friendly.
|
||||||
|
"""
|
||||||
parts = topic.split('/')
|
parts = topic.split('/')
|
||||||
unit = payload.get('units', '')
|
unit = payload.get('units', '')
|
||||||
domain = parts[1]
|
domain = parts[1]
|
||||||
@ -47,9 +51,11 @@ def _slug(name):
|
|||||||
return 'sensor.arwn_{}'.format(slugify(name))
|
return 'sensor.arwn_{}'.format(slugify(name))
|
||||||
|
|
||||||
|
|
||||||
def setup_platform(hass, config, add_devices, discovery_info=None):
|
@asyncio.coroutine
|
||||||
|
def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
|
||||||
"""Set up the ARWN platform."""
|
"""Set up the ARWN platform."""
|
||||||
def sensor_event_received(topic, payload, qos):
|
@callback
|
||||||
|
def async_sensor_event_received(topic, payload, qos):
|
||||||
"""Process events as sensors.
|
"""Process events as sensors.
|
||||||
|
|
||||||
When a new event on our topic (arwn/#) is received we map it
|
When a new event on our topic (arwn/#) is received we map it
|
||||||
@ -67,6 +73,10 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
|
|||||||
if not sensors:
|
if not sensors:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
store = hass.data.get(DATA_ARWN)
|
||||||
|
if store is None:
|
||||||
|
store = hass.data[DATA_ARWN] = {}
|
||||||
|
|
||||||
if isinstance(sensors, ArwnSensor):
|
if isinstance(sensors, ArwnSensor):
|
||||||
sensors = (sensors, )
|
sensors = (sensors, )
|
||||||
|
|
||||||
@ -74,18 +84,18 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
|
|||||||
del event['timestamp']
|
del event['timestamp']
|
||||||
|
|
||||||
for sensor in sensors:
|
for sensor in sensors:
|
||||||
if sensor.name not in SENSORS:
|
if sensor.name not in store:
|
||||||
sensor.hass = hass
|
sensor.hass = hass
|
||||||
sensor.set_event(event)
|
sensor.set_event(event)
|
||||||
SENSORS[sensor.name] = sensor
|
store[sensor.name] = sensor
|
||||||
_LOGGER.debug("Registering new sensor %(name)s => %(event)s",
|
_LOGGER.debug("Registering new sensor %(name)s => %(event)s",
|
||||||
dict(name=sensor.name, event=event))
|
dict(name=sensor.name, event=event))
|
||||||
add_devices((sensor,))
|
async_add_devices((sensor,), True)
|
||||||
else:
|
else:
|
||||||
SENSORS[sensor.name].set_event(event)
|
store[sensor.name].set_event(event)
|
||||||
SENSORS[sensor.name].update_ha_state()
|
|
||||||
|
|
||||||
mqtt.subscribe(hass, TOPIC, sensor_event_received, 0)
|
yield from mqtt.async_subscribe(
|
||||||
|
hass, TOPIC, async_sensor_event_received, 0)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
"""The tests for the MQTT device tracker platform."""
|
"""The tests for the MQTT device tracker platform."""
|
||||||
|
import asyncio
|
||||||
import unittest
|
import unittest
|
||||||
from unittest.mock import patch
|
from unittest.mock import patch
|
||||||
import logging
|
import logging
|
||||||
@ -33,12 +34,13 @@ class TestComponentsDeviceTrackerMQTT(unittest.TestCase):
|
|||||||
def test_ensure_device_tracker_platform_validation(self): \
|
def test_ensure_device_tracker_platform_validation(self): \
|
||||||
# pylint: disable=invalid-name
|
# pylint: disable=invalid-name
|
||||||
"""Test if platform validation was done."""
|
"""Test if platform validation was done."""
|
||||||
|
@asyncio.coroutine
|
||||||
def mock_setup_scanner(hass, config, see, discovery_info=None):
|
def mock_setup_scanner(hass, config, see, discovery_info=None):
|
||||||
"""Check that Qos was added by validation."""
|
"""Check that Qos was added by validation."""
|
||||||
self.assertTrue('qos' in config)
|
self.assertTrue('qos' in config)
|
||||||
|
|
||||||
with patch('homeassistant.components.device_tracker.mqtt.'
|
with patch('homeassistant.components.device_tracker.mqtt.'
|
||||||
'setup_scanner', autospec=True,
|
'async_setup_scanner', autospec=True,
|
||||||
side_effect=mock_setup_scanner) as mock_sp:
|
side_effect=mock_setup_scanner) as mock_sp:
|
||||||
|
|
||||||
dev_id = 'paulus'
|
dev_id = 'paulus'
|
||||||
|
Loading…
x
Reference in New Issue
Block a user