Skip to content

Commit

Permalink
[mqtt.homeassistant] sensors with a state_class are numeric (#13398)
Browse files Browse the repository at this point in the history
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 <cody@cutrer.us>
  • Loading branch information
ccutrer authored Sep 18, 2022
1 parent 2fd2e51 commit a2b6dd7
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand All @@ -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();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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<String> getConfigTopics() {
return Set.of(CONFIG_TOPIC);
Expand Down

0 comments on commit a2b6dd7

Please sign in to comment.