From a2b6dd77b7cb11c430359b8e3d8a662549e06142 Mon Sep 17 00:00:00 2001 From: Cody Cutrer Date: Sun, 18 Sep 2022 11:46:07 -0600 Subject: [PATCH] [mqtt.homeassistant] sensors with a state_class are numeric (#13398) see reference in code comment, but a measurement sensor is assumed to be numeric, even if it doesn't have a unit Signed-off-by: Cody Cutrer --- .../internal/component/Sensor.java | 7 +++ .../internal/component/SensorTests.java | 53 +++++++++++++++++++ 2 files changed, 60 insertions(+) diff --git a/bundles/org.openhab.binding.mqtt.homeassistant/src/main/java/org/openhab/binding/mqtt/homeassistant/internal/component/Sensor.java b/bundles/org.openhab.binding.mqtt.homeassistant/src/main/java/org/openhab/binding/mqtt/homeassistant/internal/component/Sensor.java index 4b4bdcccba868..7382e0f4fd82d 100644 --- a/bundles/org.openhab.binding.mqtt.homeassistant/src/main/java/org/openhab/binding/mqtt/homeassistant/internal/component/Sensor.java +++ b/bundles/org.openhab.binding.mqtt.homeassistant/src/main/java/org/openhab/binding/mqtt/homeassistant/internal/component/Sensor.java @@ -49,6 +49,8 @@ static class ChannelConfiguration extends AbstractChannelConfiguration { protected @Nullable String unitOfMeasurement; @SerializedName("device_class") protected @Nullable String deviceClass; + @SerializedName("state_class") + protected @Nullable String stateClass; @SerializedName("force_update") protected boolean forceUpdate = false; @SerializedName("expire_after") @@ -70,9 +72,14 @@ public Sensor(ComponentFactory.ComponentConfiguration componentConfiguration) { Value value; String uom = channelConfiguration.unitOfMeasurement; + String sc = channelConfiguration.stateClass; if (uom != null && !uom.isBlank()) { value = new NumberValue(null, null, null, UnitUtils.parseUnit(uom)); + } else if (sc != null && !sc.isBlank()) { + // see state_class at https://developers.home-assistant.io/docs/core/entity/sensor#properties + // > If not None, the sensor is assumed to be numerical + value = new NumberValue(null, null, null, null); } else { value = new TextValue(); } diff --git a/bundles/org.openhab.binding.mqtt.homeassistant/src/test/java/org/openhab/binding/mqtt/homeassistant/internal/component/SensorTests.java b/bundles/org.openhab.binding.mqtt.homeassistant/src/test/java/org/openhab/binding/mqtt/homeassistant/internal/component/SensorTests.java index feffc40f18697..a92237980edd2 100644 --- a/bundles/org.openhab.binding.mqtt.homeassistant/src/test/java/org/openhab/binding/mqtt/homeassistant/internal/component/SensorTests.java +++ b/bundles/org.openhab.binding.mqtt.homeassistant/src/test/java/org/openhab/binding/mqtt/homeassistant/internal/component/SensorTests.java @@ -20,6 +20,7 @@ import org.eclipse.jdt.annotation.NonNullByDefault; import org.junit.jupiter.api.Test; import org.openhab.binding.mqtt.generic.values.NumberValue; +import org.openhab.binding.mqtt.generic.values.TextValue; import org.openhab.core.library.types.QuantityType; import org.openhab.core.library.unit.Units; import org.openhab.core.types.UnDefType; @@ -79,6 +80,58 @@ public void test() throws InterruptedException { waitForAssert(() -> assertState(component, Sensor.SENSOR_CHANNEL_ID, UnDefType.UNDEF), 10000, 200); } + @Test + public void testMeasurementStateClass() throws InterruptedException { + // @formatter:off + var component = discoverComponent(configTopicToMqtt(CONFIG_TOPIC), + "{ " + + " \"device\": { " + + " \"identifiers\": [ " + + " \"zigbee2mqtt_0x0000000000000000\" " + + " ], " + + " \"manufacturer\": \"Sensors inc\", " + + " \"model\": \"Sensor\", " + + " \"name\": \"Sensor\", " + + " \"sw_version\": \"Zigbee2MQTT 1.18.2\" " + + " }, " + + " \"name\": \"sensor1\", " + + " \"expire_after\": \"1\", " + + " \"force_update\": \"true\", " + + " \"state_class\": \"measurement\", " + + " \"state_topic\": \"zigbee2mqtt/sensor/state\", " + + " \"unique_id\": \"sn1\" " + + "}"); + // @formatter:on + + assertChannel(component, Sensor.SENSOR_CHANNEL_ID, "zigbee2mqtt/sensor/state", "", "sensor1", + NumberValue.class); + } + + @Test + public void testNonNumericSensor() throws InterruptedException { + // @formatter:off + var component = discoverComponent(configTopicToMqtt(CONFIG_TOPIC), + "{ " + + " \"device\": { " + + " \"identifiers\": [ " + + " \"zigbee2mqtt_0x0000000000000000\" " + + " ], " + + " \"manufacturer\": \"Sensors inc\", " + + " \"model\": \"Sensor\", " + + " \"name\": \"Sensor\", " + + " \"sw_version\": \"Zigbee2MQTT 1.18.2\" " + + " }, " + + " \"name\": \"sensor1\", " + + " \"expire_after\": \"1\", " + + " \"force_update\": \"true\", " + + " \"state_topic\": \"zigbee2mqtt/sensor/state\", " + + " \"unique_id\": \"sn1\" " + + "}"); + // @formatter:on + + assertChannel(component, Sensor.SENSOR_CHANNEL_ID, "zigbee2mqtt/sensor/state", "", "sensor1", TextValue.class); + } + @Override protected Set getConfigTopics() { return Set.of(CONFIG_TOPIC);