From 7223c59e79536032af06a9b923acadc4f9d63532 Mon Sep 17 00:00:00 2001 From: Erik Montnemery Date: Thu, 7 Oct 2021 13:54:34 +0200 Subject: [PATCH] Allow resetting an MQTT number (#57161) * Allow resetting an MQTT number * Add abbreviation --- homeassistant/components/mqtt/abbreviations.py | 1 + homeassistant/components/mqtt/number.py | 11 +++++++++-- tests/components/mqtt/test_number.py | 15 +++++++++++++++ 3 files changed, 25 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/mqtt/abbreviations.py b/homeassistant/components/mqtt/abbreviations.py index dd2f631848e..f3dcca9cfd5 100644 --- a/homeassistant/components/mqtt/abbreviations.py +++ b/homeassistant/components/mqtt/abbreviations.py @@ -134,6 +134,7 @@ ABBREVIATIONS = { "pl_osc_off": "payload_oscillation_off", "pl_osc_on": "payload_oscillation_on", "pl_paus": "payload_pause", + "pl_rst": "payload_reset", "pl_rst_hum": "payload_reset_humidity", "pl_rst_mode": "payload_reset_mode", "pl_rst_pct": "payload_reset_percentage", diff --git a/homeassistant/components/mqtt/number.py b/homeassistant/components/mqtt/number.py index 866f93fd674..d7bce567976 100644 --- a/homeassistant/components/mqtt/number.py +++ b/homeassistant/components/mqtt/number.py @@ -35,10 +35,12 @@ _LOGGER = logging.getLogger(__name__) CONF_MIN = "min" CONF_MAX = "max" +CONF_PAYLOAD_RESET = "payload_reset" CONF_STEP = "step" DEFAULT_NAME = "MQTT Number" DEFAULT_OPTIMISTIC = False +DEFAULT_PAYLOAD_RESET = "None" MQTT_NUMBER_ATTRIBUTES_BLOCKED = frozenset( { @@ -64,6 +66,7 @@ PLATFORM_SCHEMA = vol.All( vol.Optional(CONF_MIN, default=DEFAULT_MIN_VALUE): vol.Coerce(float), vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, vol.Optional(CONF_OPTIMISTIC, default=DEFAULT_OPTIMISTIC): cv.boolean, + vol.Optional(CONF_PAYLOAD_RESET, default=DEFAULT_PAYLOAD_RESET): cv.string, vol.Optional(CONF_STEP, default=DEFAULT_STEP): vol.All( vol.Coerce(float), vol.Range(min=1e-3) ), @@ -138,7 +141,9 @@ class MqttNumber(MqttEntity, NumberEntity, RestoreEntity): if value_template is not None: payload = value_template.async_render_with_possible_json_value(payload) try: - if payload.isnumeric(): + if payload == self._config[CONF_PAYLOAD_RESET]: + num_value = None + elif payload.isnumeric(): num_value = int(payload) else: num_value = float(payload) @@ -146,7 +151,9 @@ class MqttNumber(MqttEntity, NumberEntity, RestoreEntity): _LOGGER.warning("Payload '%s' is not a Number", msg.payload) return - if num_value < self.min_value or num_value > self.max_value: + if num_value is not None and ( + num_value < self.min_value or num_value > self.max_value + ): _LOGGER.error( "Invalid value for %s: %s (range %s - %s)", self.entity_id, diff --git a/tests/components/mqtt/test_number.py b/tests/components/mqtt/test_number.py index 37693340308..b0989c59ca2 100644 --- a/tests/components/mqtt/test_number.py +++ b/tests/components/mqtt/test_number.py @@ -66,6 +66,7 @@ async def test_run_number_setup(hass, mqtt_mock): "state_topic": topic, "command_topic": topic, "name": "Test Number", + "payload_reset": "reset!", } }, ) @@ -85,6 +86,13 @@ async def test_run_number_setup(hass, mqtt_mock): state = hass.states.get("number.test_number") assert state.state == "20.5" + async_fire_mqtt_message(hass, topic, "reset!") + + await hass.async_block_till_done() + + state = hass.states.get("number.test_number") + assert state.state == "unknown" + async def test_value_template(hass, mqtt_mock): """Test that it fetches the given payload with a template.""" @@ -118,6 +126,13 @@ async def test_value_template(hass, mqtt_mock): state = hass.states.get("number.test_number") assert state.state == "20.5" + async_fire_mqtt_message(hass, topic, '{"val":null}') + + await hass.async_block_till_done() + + state = hass.states.get("number.test_number") + assert state.state == "unknown" + async def test_run_number_service_optimistic(hass, mqtt_mock): """Test that set_value service works in optimistic mode."""