From 4e25807b7d3c330778b08527c8cdaee059c85498 Mon Sep 17 00:00:00 2001 From: Raman Gupta <7243222+raman325@users.noreply.github.com> Date: Thu, 17 Oct 2019 20:51:27 -0400 Subject: [PATCH] Add ability for MQTT device tracker to map non-default topic payloads to zones/states (#27143) * add ability for MQTT device tracker to map nondefault topic payloads to zones * update new parameter name and add abbreviation * support for payload_home, payload_not_home, and payload_custom * use constants STATE_NOT_HOME and STATE_HOME as defaults * reference state constants directly * add empty dict as default for payload_custom * change parameter name for custom mapping of payloads to non-home zones to be more descriptive * removed 'payload_other_zones' per ballobs review * remove abbreviation for 'payload_other_zones' * add tests for feature --- .../components/mqtt/abbreviations.py | 2 + .../components/mqtt/device_tracker.py | 24 ++++++- tests/components/mqtt/test_device_tracker.py | 64 ++++++++++++++++++- 3 files changed, 86 insertions(+), 4 deletions(-) diff --git a/homeassistant/components/mqtt/abbreviations.py b/homeassistant/components/mqtt/abbreviations.py index 2350dfc6634..5a5ed4555db 100644 --- a/homeassistant/components/mqtt/abbreviations.py +++ b/homeassistant/components/mqtt/abbreviations.py @@ -88,11 +88,13 @@ ABBREVIATIONS = { "pl_cls": "payload_close", "pl_disarm": "payload_disarm", "pl_hi_spd": "payload_high_speed", + "pl_home": "payload_home", "pl_lock": "payload_lock", "pl_loc": "payload_locate", "pl_lo_spd": "payload_low_speed", "pl_med_spd": "payload_medium_speed", "pl_not_avail": "payload_not_available", + "pl_not_home": "payload_not_home", "pl_off": "payload_off", "pl_off_spd": "payload_off_speed", "pl_on": "payload_on", diff --git a/homeassistant/components/mqtt/device_tracker.py b/homeassistant/components/mqtt/device_tracker.py index e9613e09a95..c9cce3ebeda 100644 --- a/homeassistant/components/mqtt/device_tracker.py +++ b/homeassistant/components/mqtt/device_tracker.py @@ -5,16 +5,23 @@ import voluptuous as vol from homeassistant.components import mqtt from homeassistant.components.device_tracker import PLATFORM_SCHEMA -from homeassistant.const import CONF_DEVICES from homeassistant.core import callback import homeassistant.helpers.config_validation as cv +from homeassistant.const import CONF_DEVICES, STATE_NOT_HOME, STATE_HOME from . import CONF_QOS _LOGGER = logging.getLogger(__name__) +CONF_PAYLOAD_HOME = "payload_home" +CONF_PAYLOAD_NOT_HOME = "payload_not_home" + PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(mqtt.SCHEMA_BASE).extend( - {vol.Required(CONF_DEVICES): {cv.string: mqtt.valid_subscribe_topic}} + { + vol.Required(CONF_DEVICES): {cv.string: mqtt.valid_subscribe_topic}, + vol.Optional(CONF_PAYLOAD_HOME, default=STATE_HOME): cv.string, + vol.Optional(CONF_PAYLOAD_NOT_HOME, default=STATE_NOT_HOME): cv.string, + } ) @@ -22,13 +29,24 @@ async def async_setup_scanner(hass, config, async_see, discovery_info=None): """Set up the MQTT tracker.""" devices = config[CONF_DEVICES] qos = config[CONF_QOS] + payload_home = config[CONF_PAYLOAD_HOME] + payload_not_home = config[CONF_PAYLOAD_NOT_HOME] for dev_id, topic in devices.items(): @callback def async_message_received(msg, dev_id=dev_id): """Handle received MQTT message.""" - hass.async_create_task(async_see(dev_id=dev_id, location_name=msg.payload)) + if msg.payload == payload_home: + location_name = STATE_HOME + elif msg.payload == payload_not_home: + location_name = STATE_NOT_HOME + else: + location_name = msg.payload + + hass.async_create_task( + async_see(dev_id=dev_id, location_name=location_name) + ) await mqtt.async_subscribe(hass, topic, async_message_received, qos) diff --git a/tests/components/mqtt/test_device_tracker.py b/tests/components/mqtt/test_device_tracker.py index caad12b3e39..14180d2dcf9 100644 --- a/tests/components/mqtt/test_device_tracker.py +++ b/tests/components/mqtt/test_device_tracker.py @@ -4,7 +4,7 @@ import pytest from homeassistant.components import device_tracker from homeassistant.components.device_tracker.const import ENTITY_ID_FORMAT -from homeassistant.const import CONF_PLATFORM +from homeassistant.const import CONF_PLATFORM, STATE_HOME, STATE_NOT_HOME from homeassistant.setup import async_setup_component from tests.common import async_fire_mqtt_message @@ -156,3 +156,65 @@ async def test_multi_level_wildcard_topic_not_matching(hass, mock_device_tracker async_fire_mqtt_message(hass, topic, location) await hass.async_block_till_done() assert hass.states.get(entity_id) is None + + +async def test_matching_custom_payload_for_home_and_not_home( + hass, mock_device_tracker_conf +): + """Test custom payload_home sets state to home and custom payload_not_home sets state to not_home.""" + dev_id = "paulus" + entity_id = ENTITY_ID_FORMAT.format(dev_id) + topic = "/location/paulus" + payload_home = "present" + payload_not_home = "not present" + + hass.config.components = set(["mqtt", "zone"]) + assert await async_setup_component( + hass, + device_tracker.DOMAIN, + { + device_tracker.DOMAIN: { + CONF_PLATFORM: "mqtt", + "devices": {dev_id: topic}, + "payload_home": payload_home, + "payload_not_home": payload_not_home, + } + }, + ) + async_fire_mqtt_message(hass, topic, payload_home) + await hass.async_block_till_done() + assert hass.states.get(entity_id).state == STATE_HOME + + async_fire_mqtt_message(hass, topic, payload_not_home) + await hass.async_block_till_done() + assert hass.states.get(entity_id).state == STATE_NOT_HOME + + +async def test_not_matching_custom_payload_for_home_and_not_home( + hass, mock_device_tracker_conf +): + """Test not matching payload does not set state to home or not_home.""" + dev_id = "paulus" + entity_id = ENTITY_ID_FORMAT.format(dev_id) + topic = "/location/paulus" + payload_home = "present" + payload_not_home = "not present" + payload_not_matching = "test" + + hass.config.components = set(["mqtt", "zone"]) + assert await async_setup_component( + hass, + device_tracker.DOMAIN, + { + device_tracker.DOMAIN: { + CONF_PLATFORM: "mqtt", + "devices": {dev_id: topic}, + "payload_home": payload_home, + "payload_not_home": payload_not_home, + } + }, + ) + async_fire_mqtt_message(hass, topic, payload_not_matching) + await hass.async_block_till_done() + assert hass.states.get(entity_id).state != STATE_HOME + assert hass.states.get(entity_id).state != STATE_NOT_HOME