diff --git a/homeassistant/components/mqtt/const.py b/homeassistant/components/mqtt/const.py index f7fa93a36d0..0cb81dc9f74 100644 --- a/homeassistant/components/mqtt/const.py +++ b/homeassistant/components/mqtt/const.py @@ -27,6 +27,7 @@ CONF_TRANSPORT = "transport" CONF_WS_PATH = "ws_path" CONF_WS_HEADERS = "ws_headers" CONF_WILL_MESSAGE = "will_message" +CONF_PAYLOAD_RESET = "payload_reset" CONF_CERTIFICATE = "certificate" CONF_CLIENT_KEY = "client_key" diff --git a/homeassistant/components/mqtt/device_tracker.py b/homeassistant/components/mqtt/device_tracker.py index 26dc016e07e..92f213f4bdf 100644 --- a/homeassistant/components/mqtt/device_tracker.py +++ b/homeassistant/components/mqtt/device_tracker.py @@ -29,7 +29,7 @@ from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType from . import subscription from .config import MQTT_RO_SCHEMA -from .const import CONF_QOS, CONF_STATE_TOPIC +from .const import CONF_PAYLOAD_RESET, CONF_QOS, CONF_STATE_TOPIC from .debug_info import log_messages from .mixins import ( MQTT_ENTITY_COMMON_SCHEMA, @@ -44,6 +44,7 @@ CONF_PAYLOAD_HOME = "payload_home" CONF_PAYLOAD_NOT_HOME = "payload_not_home" CONF_SOURCE_TYPE = "source_type" +DEFAULT_PAYLOAD_RESET = "None" DEFAULT_SOURCE_TYPE = SourceType.GPS PLATFORM_SCHEMA_MODERN = MQTT_RO_SCHEMA.extend( @@ -51,6 +52,7 @@ PLATFORM_SCHEMA_MODERN = MQTT_RO_SCHEMA.extend( vol.Optional(CONF_NAME): cv.string, vol.Optional(CONF_PAYLOAD_HOME, default=STATE_HOME): cv.string, vol.Optional(CONF_PAYLOAD_NOT_HOME, default=STATE_NOT_HOME): cv.string, + vol.Optional(CONF_PAYLOAD_RESET, default=DEFAULT_PAYLOAD_RESET): cv.string, vol.Optional(CONF_SOURCE_TYPE, default=DEFAULT_SOURCE_TYPE): vol.In( SOURCE_TYPES ), @@ -127,6 +129,8 @@ class MqttDeviceTracker(MqttEntity, TrackerEntity): self._location_name = STATE_HOME elif payload == self._config[CONF_PAYLOAD_NOT_HOME]: self._location_name = STATE_NOT_HOME + elif payload == self._config[CONF_PAYLOAD_RESET]: + self._location_name = None else: assert isinstance(msg.payload, str) self._location_name = msg.payload diff --git a/homeassistant/components/mqtt/number.py b/homeassistant/components/mqtt/number.py index 6d56354368e..8f33eea2c64 100644 --- a/homeassistant/components/mqtt/number.py +++ b/homeassistant/components/mqtt/number.py @@ -36,6 +36,7 @@ from .const import ( CONF_COMMAND_TEMPLATE, CONF_COMMAND_TOPIC, CONF_ENCODING, + CONF_PAYLOAD_RESET, CONF_QOS, CONF_RETAIN, CONF_STATE_TOPIC, @@ -60,7 +61,6 @@ _LOGGER = logging.getLogger(__name__) CONF_MIN = "min" CONF_MAX = "max" -CONF_PAYLOAD_RESET = "payload_reset" CONF_STEP = "step" DEFAULT_NAME = "MQTT Number" diff --git a/tests/components/mqtt/test_device_tracker.py b/tests/components/mqtt/test_device_tracker.py index 6db5811afd4..ee43fe7da6a 100644 --- a/tests/components/mqtt/test_device_tracker.py +++ b/tests/components/mqtt/test_device_tracker.py @@ -429,6 +429,122 @@ async def test_setting_device_tracker_location_via_lat_lon_message( assert state.state == STATE_UNKNOWN +async def test_setting_device_tracker_location_via_reset_message( + hass, mqtt_mock_entry_no_yaml_config, caplog +): + """Test the automatic inference of zones via MQTT via reset.""" + await mqtt_mock_entry_no_yaml_config() + async_fire_mqtt_message( + hass, + "homeassistant/device_tracker/bla/config", + "{ " + '"name": "test", ' + '"state_topic": "test-topic", ' + '"json_attributes_topic": "attributes-topic" ' + "}", + ) + + hass.states.async_set( + "zone.school", + "zoning", + { + "latitude": 30.0, + "longitude": -100.0, + "radius": 100, + "friendly_name": "School", + }, + ) + + await hass.async_block_till_done() + + state = hass.states.get("device_tracker.test") + assert state.attributes["source_type"] == "gps" + + assert state.state == STATE_UNKNOWN + + hass.config.latitude = 32.87336 + hass.config.longitude = -117.22743 + + # test reset and gps attributes + async_fire_mqtt_message( + hass, + "attributes-topic", + '{"latitude":32.87336,"longitude": -117.22743, "gps_accuracy":1.5}', + ) + async_fire_mqtt_message(hass, "test-topic", "None") + + state = hass.states.get("device_tracker.test") + assert state.attributes["latitude"] == 32.87336 + assert state.attributes["longitude"] == -117.22743 + assert state.attributes["gps_accuracy"] == 1.5 + assert state.attributes["source_type"] == "gps" + assert state.state == STATE_HOME + + # test manual state override + async_fire_mqtt_message(hass, "test-topic", "Work") + + state = hass.states.get("device_tracker.test") + assert state.state == "Work" + + # test reset + async_fire_mqtt_message(hass, "test-topic", "None") + + state = hass.states.get("device_tracker.test") + assert state.state == STATE_HOME + + # test reset inferring correct school area + async_fire_mqtt_message( + hass, + "attributes-topic", + '{"latitude":30.0,"longitude":-100.0,"gps_accuracy":1.5}', + ) + + state = hass.states.get("device_tracker.test") + assert state.state == "School" + + +async def test_setting_device_tracker_location_via_abbr_reset_message( + hass, mqtt_mock_entry_no_yaml_config, caplog +): + """Test the setting of reset via abbreviated names and custom payloads via MQTT.""" + await mqtt_mock_entry_no_yaml_config() + async_fire_mqtt_message( + hass, + "homeassistant/device_tracker/bla/config", + "{ " + '"name": "test", ' + '"state_topic": "test-topic", ' + '"json_attributes_topic": "attributes-topic", ' + '"pl_rst": "reset" ' + "}", + ) + + await hass.async_block_till_done() + + state = hass.states.get("device_tracker.test") + assert state.attributes["source_type"] == "gps" + + assert state.state == STATE_UNKNOWN + + hass.config.latitude = 32.87336 + hass.config.longitude = -117.22743 + + # test custom reset payload and gps attributes + async_fire_mqtt_message( + hass, + "attributes-topic", + '{"latitude":32.87336,"longitude": -117.22743, "gps_accuracy":1.5}', + ) + async_fire_mqtt_message(hass, "test-topic", "reset") + + state = hass.states.get("device_tracker.test") + assert state.attributes["latitude"] == 32.87336 + assert state.attributes["longitude"] == -117.22743 + assert state.attributes["gps_accuracy"] == 1.5 + assert state.attributes["source_type"] == "gps" + assert state.state == STATE_HOME + + async def test_setting_blocked_attribute_via_mqtt_json_message( hass, mqtt_mock_entry_no_yaml_config ):