diff --git a/homeassistant/components/mqtt/abbreviations.py b/homeassistant/components/mqtt/abbreviations.py index 6f2eeeeedd0..758e978bb46 100644 --- a/homeassistant/components/mqtt/abbreviations.py +++ b/homeassistant/components/mqtt/abbreviations.py @@ -99,6 +99,7 @@ ABBREVIATIONS = { "min_mirs": "min_mireds", "max_temp": "max_temp", "min_temp": "min_temp", + "mode": "mode", "mode_cmd_tpl": "mode_command_template", "mode_cmd_t": "mode_command_topic", "mode_stat_t": "mode_state_topic", diff --git a/homeassistant/components/mqtt/number.py b/homeassistant/components/mqtt/number.py index 4e9f237431a..eeac406f668 100644 --- a/homeassistant/components/mqtt/number.py +++ b/homeassistant/components/mqtt/number.py @@ -13,11 +13,13 @@ from homeassistant.components.number import ( DEFAULT_STEP, DEVICE_CLASSES_SCHEMA, NumberDeviceClass, + NumberMode, RestoreNumber, ) from homeassistant.config_entries import ConfigEntry from homeassistant.const import ( CONF_DEVICE_CLASS, + CONF_MODE, CONF_NAME, CONF_OPTIMISTIC, CONF_UNIT_OF_MEASUREMENT, @@ -83,6 +85,7 @@ _PLATFORM_SCHEMA_BASE = MQTT_RW_SCHEMA.extend( vol.Optional(CONF_DEVICE_CLASS): DEVICE_CLASSES_SCHEMA, vol.Optional(CONF_MAX, default=DEFAULT_MAX_VALUE): vol.Coerce(float), vol.Optional(CONF_MIN, default=DEFAULT_MIN_VALUE): vol.Coerce(float), + vol.Optional(CONF_MODE, default=NumberMode.AUTO): vol.Coerce(NumberMode), 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, @@ -276,6 +279,11 @@ class MqttNumber(MqttEntity, RestoreNumber): """Return the current value.""" return self._current_number + @property + def mode(self) -> NumberMode: + """Return the mode of the entity.""" + return self._config[CONF_MODE] + async def async_set_native_value(self, value: float) -> None: """Update the current value.""" current_number = value diff --git a/tests/components/mqtt/test_number.py b/tests/components/mqtt/test_number.py index 458f1f740e1..603984cffad 100644 --- a/tests/components/mqtt/test_number.py +++ b/tests/components/mqtt/test_number.py @@ -5,7 +5,7 @@ from unittest.mock import patch import pytest -from homeassistant.components import number +from homeassistant.components import mqtt, number from homeassistant.components.mqtt.number import ( CONF_MAX, CONF_MIN, @@ -24,6 +24,7 @@ from homeassistant.const import ( ATTR_ASSUMED_STATE, ATTR_DEVICE_CLASS, ATTR_ENTITY_ID, + ATTR_MODE, ATTR_UNIT_OF_MEASUREMENT, TEMP_FAHRENHEIT, Platform, @@ -702,6 +703,77 @@ async def test_invalid_min_max_attributes(hass, caplog, mqtt_mock_entry_no_yaml_ assert f"'{CONF_MAX}' must be > '{CONF_MIN}'" in caplog.text +async def test_default_mode(hass, mqtt_mock_entry_with_yaml_config): + """Test default mode.""" + topic = "test/number" + await async_setup_component( + hass, + mqtt.DOMAIN, + { + mqtt.DOMAIN: { + number.DOMAIN: { + "state_topic": topic, + "command_topic": topic, + "name": "Test Number", + } + } + }, + ) + await hass.async_block_till_done() + await mqtt_mock_entry_with_yaml_config() + + state = hass.states.get("number.test_number") + assert state.attributes.get(ATTR_MODE) == "auto" + + +@pytest.mark.parametrize("mode", ("auto", "box", "slider")) +async def test_mode(hass, mqtt_mock_entry_with_yaml_config, mode): + """Test mode.""" + topic = "test/number" + await async_setup_component( + hass, + mqtt.DOMAIN, + { + mqtt.DOMAIN: { + number.DOMAIN: { + "state_topic": topic, + "command_topic": topic, + "name": "Test Number", + "mode": mode, + } + } + }, + ) + await hass.async_block_till_done() + await mqtt_mock_entry_with_yaml_config() + + state = hass.states.get("number.test_number") + assert state.attributes.get(ATTR_MODE) == mode + + +@pytest.mark.parametrize("mode,valid", [("bleh", False), ("auto", True)]) +async def test_invalid_mode(hass, mode, valid): + """Test invalid mode.""" + topic = "test/number" + assert ( + await async_setup_component( + hass, + mqtt.DOMAIN, + { + mqtt.DOMAIN: { + number.DOMAIN: { + "state_topic": topic, + "command_topic": topic, + "name": "Test Number", + "mode": mode, + } + } + }, + ) + is valid + ) + + async def test_mqtt_payload_not_a_number_warning( hass, caplog, mqtt_mock_entry_with_yaml_config ):