From ee21bc5d7f92b928abc8cfa5f56fb971e82090fa Mon Sep 17 00:00:00 2001 From: Jan Bouwhuis Date: Wed, 4 Jan 2023 15:21:07 +0100 Subject: [PATCH] Allow MQTT device_class or state_class to be set as `None` (#85106) * Allow MQTT device_class to be set as `None` * Add test * Also allow sensor state_class to be `None` --- homeassistant/components/mqtt/binary_sensor.py | 2 +- homeassistant/components/mqtt/button.py | 4 ++-- homeassistant/components/mqtt/cover.py | 2 +- homeassistant/components/mqtt/number.py | 2 +- homeassistant/components/mqtt/sensor.py | 4 ++-- homeassistant/components/mqtt/switch.py | 2 +- homeassistant/components/mqtt/update.py | 2 +- tests/components/mqtt/test_sensor.py | 14 ++++++++++++++ 8 files changed, 23 insertions(+), 9 deletions(-) diff --git a/homeassistant/components/mqtt/binary_sensor.py b/homeassistant/components/mqtt/binary_sensor.py index f604bbbdd64..5ed9fdfb76f 100644 --- a/homeassistant/components/mqtt/binary_sensor.py +++ b/homeassistant/components/mqtt/binary_sensor.py @@ -59,7 +59,7 @@ CONF_EXPIRE_AFTER = "expire_after" PLATFORM_SCHEMA_MODERN = MQTT_RO_SCHEMA.extend( { - vol.Optional(CONF_DEVICE_CLASS): DEVICE_CLASSES_SCHEMA, + vol.Optional(CONF_DEVICE_CLASS): vol.Any(DEVICE_CLASSES_SCHEMA, None), vol.Optional(CONF_EXPIRE_AFTER): cv.positive_int, vol.Optional(CONF_FORCE_UPDATE, default=DEFAULT_FORCE_UPDATE): cv.boolean, vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, diff --git a/homeassistant/components/mqtt/button.py b/homeassistant/components/mqtt/button.py index 3188aa2ee0f..d50a06a46d8 100644 --- a/homeassistant/components/mqtt/button.py +++ b/homeassistant/components/mqtt/button.py @@ -6,7 +6,7 @@ import functools import voluptuous as vol from homeassistant.components import button -from homeassistant.components.button import ButtonEntity +from homeassistant.components.button import DEVICE_CLASSES_SCHEMA, ButtonEntity from homeassistant.config_entries import ConfigEntry from homeassistant.const import CONF_DEVICE_CLASS, CONF_NAME from homeassistant.core import HomeAssistant @@ -39,7 +39,7 @@ PLATFORM_SCHEMA_MODERN = MQTT_BASE_SCHEMA.extend( { vol.Optional(CONF_COMMAND_TEMPLATE): cv.template, vol.Required(CONF_COMMAND_TOPIC): valid_publish_topic, - vol.Optional(CONF_DEVICE_CLASS): button.DEVICE_CLASSES_SCHEMA, + vol.Optional(CONF_DEVICE_CLASS): vol.Any(DEVICE_CLASSES_SCHEMA, None), vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, vol.Optional(CONF_PAYLOAD_PRESS, default=DEFAULT_PAYLOAD_PRESS): cv.string, vol.Optional(CONF_RETAIN, default=DEFAULT_RETAIN): cv.boolean, diff --git a/homeassistant/components/mqtt/cover.py b/homeassistant/components/mqtt/cover.py index 4770e6e57c9..f0733af8bc3 100644 --- a/homeassistant/components/mqtt/cover.py +++ b/homeassistant/components/mqtt/cover.py @@ -161,7 +161,7 @@ def validate_options(config: ConfigType) -> ConfigType: _PLATFORM_SCHEMA_BASE = MQTT_BASE_SCHEMA.extend( { vol.Optional(CONF_COMMAND_TOPIC): valid_publish_topic, - vol.Optional(CONF_DEVICE_CLASS): DEVICE_CLASSES_SCHEMA, + vol.Optional(CONF_DEVICE_CLASS): vol.Any(DEVICE_CLASSES_SCHEMA, None), vol.Optional(CONF_GET_POSITION_TOPIC): valid_subscribe_topic, vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, vol.Optional(CONF_OPTIMISTIC, default=DEFAULT_OPTIMISTIC): cv.boolean, diff --git a/homeassistant/components/mqtt/number.py b/homeassistant/components/mqtt/number.py index 1cd37342d75..cef9f47f0d9 100644 --- a/homeassistant/components/mqtt/number.py +++ b/homeassistant/components/mqtt/number.py @@ -86,7 +86,7 @@ def validate_config(config: ConfigType) -> ConfigType: _PLATFORM_SCHEMA_BASE = MQTT_RW_SCHEMA.extend( { vol.Optional(CONF_COMMAND_TEMPLATE): cv.template, - vol.Optional(CONF_DEVICE_CLASS): DEVICE_CLASSES_SCHEMA, + vol.Optional(CONF_DEVICE_CLASS): vol.Any(DEVICE_CLASSES_SCHEMA, None), 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), diff --git a/homeassistant/components/mqtt/sensor.py b/homeassistant/components/mqtt/sensor.py index f05082849fc..dbb414921b5 100644 --- a/homeassistant/components/mqtt/sensor.py +++ b/homeassistant/components/mqtt/sensor.py @@ -98,13 +98,13 @@ def validate_options(conf: ConfigType) -> ConfigType: _PLATFORM_SCHEMA_BASE = MQTT_RO_SCHEMA.extend( { - vol.Optional(CONF_DEVICE_CLASS): DEVICE_CLASSES_SCHEMA, + vol.Optional(CONF_DEVICE_CLASS): vol.Any(DEVICE_CLASSES_SCHEMA, None), vol.Optional(CONF_EXPIRE_AFTER): cv.positive_int, vol.Optional(CONF_FORCE_UPDATE, default=DEFAULT_FORCE_UPDATE): cv.boolean, vol.Optional(CONF_LAST_RESET_TOPIC): valid_subscribe_topic, vol.Optional(CONF_LAST_RESET_VALUE_TEMPLATE): cv.template, vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, - vol.Optional(CONF_STATE_CLASS): STATE_CLASSES_SCHEMA, + vol.Optional(CONF_STATE_CLASS): vol.Any(STATE_CLASSES_SCHEMA, None), vol.Optional(CONF_UNIT_OF_MEASUREMENT): cv.string, } ).extend(MQTT_ENTITY_COMMON_SCHEMA.schema) diff --git a/homeassistant/components/mqtt/switch.py b/homeassistant/components/mqtt/switch.py index 800c8e7dd91..f3fcf30c7ea 100644 --- a/homeassistant/components/mqtt/switch.py +++ b/homeassistant/components/mqtt/switch.py @@ -60,7 +60,7 @@ PLATFORM_SCHEMA_MODERN = MQTT_RW_SCHEMA.extend( vol.Optional(CONF_STATE_OFF): cv.string, vol.Optional(CONF_STATE_ON): cv.string, vol.Optional(CONF_VALUE_TEMPLATE): cv.template, - vol.Optional(CONF_DEVICE_CLASS): DEVICE_CLASSES_SCHEMA, + vol.Optional(CONF_DEVICE_CLASS): vol.Any(DEVICE_CLASSES_SCHEMA, None), } ).extend(MQTT_ENTITY_COMMON_SCHEMA.schema) diff --git a/homeassistant/components/mqtt/update.py b/homeassistant/components/mqtt/update.py index 12d7723da3b..9ee0690b120 100644 --- a/homeassistant/components/mqtt/update.py +++ b/homeassistant/components/mqtt/update.py @@ -54,7 +54,7 @@ CONF_TITLE = "title" PLATFORM_SCHEMA_MODERN = MQTT_RO_SCHEMA.extend( { vol.Optional(CONF_COMMAND_TOPIC): valid_publish_topic, - vol.Optional(CONF_DEVICE_CLASS): DEVICE_CLASSES_SCHEMA, + vol.Optional(CONF_DEVICE_CLASS): vol.Any(DEVICE_CLASSES_SCHEMA, None), vol.Optional(CONF_ENTITY_PICTURE): cv.string, vol.Optional(CONF_LATEST_VERSION_TEMPLATE): cv.template, vol.Optional(CONF_LATEST_VERSION_TOPIC): valid_subscribe_topic, diff --git a/tests/components/mqtt/test_sensor.py b/tests/components/mqtt/test_sensor.py index 6fdc1beedf7..d807140962a 100644 --- a/tests/components/mqtt/test_sensor.py +++ b/tests/components/mqtt/test_sensor.py @@ -689,6 +689,11 @@ async def test_valid_device_class(hass, mqtt_mock_entry_with_yaml_config): "device_class": "temperature", }, {"name": "Test 2", "state_topic": "test-topic"}, + { + "name": "Test 3", + "state_topic": "test-topic", + "device_class": None, + }, ] } }, @@ -700,6 +705,8 @@ async def test_valid_device_class(hass, mqtt_mock_entry_with_yaml_config): assert state.attributes["device_class"] == "temperature" state = hass.states.get("sensor.test_2") assert "device_class" not in state.attributes + state = hass.states.get("sensor.test_3") + assert "device_class" not in state.attributes async def test_invalid_state_class(hass, mqtt_mock_entry_no_yaml_config): @@ -738,6 +745,11 @@ async def test_valid_state_class(hass, mqtt_mock_entry_with_yaml_config): "state_class": "measurement", }, {"name": "Test 2", "state_topic": "test-topic"}, + { + "name": "Test 3", + "state_topic": "test-topic", + "state_class": None, + }, ] } }, @@ -749,6 +761,8 @@ async def test_valid_state_class(hass, mqtt_mock_entry_with_yaml_config): assert state.attributes["state_class"] == "measurement" state = hass.states.get("sensor.test_2") assert "state_class" not in state.attributes + state = hass.states.get("sensor.test_3") + assert "state_class" not in state.attributes async def test_setting_attribute_via_mqtt_json_message(