From 83571e24031e4bdef443bfefa0be864d2cf1b94c Mon Sep 17 00:00:00 2001 From: Cody Cutrer Date: Tue, 14 Nov 2023 08:24:17 -0700 Subject: [PATCH] [mqtt] Interpet incoming NaN as UNDEF for NumberValues Since DecimalType and QuantityType don't support NaN, but when you're linking to a topic that the device is using floating point, NaN might happen. Signed-off-by: Cody Cutrer --- .../binding/mqtt/generic/ChannelState.java | 21 +++++++++++-------- .../mqtt/generic/values/NumberValue.java | 16 +++++++++++++- .../binding/mqtt/generic/values/Value.java | 3 ++- .../mqtt/generic/values/ValueTests.java | 4 ++++ 4 files changed, 33 insertions(+), 11 deletions(-) diff --git a/bundles/org.openhab.binding.mqtt.generic/src/main/java/org/openhab/binding/mqtt/generic/ChannelState.java b/bundles/org.openhab.binding.mqtt.generic/src/main/java/org/openhab/binding/mqtt/generic/ChannelState.java index 607253f17bd82..e127eae2b41af 100644 --- a/bundles/org.openhab.binding.mqtt.generic/src/main/java/org/openhab/binding/mqtt/generic/ChannelState.java +++ b/bundles/org.openhab.binding.mqtt.generic/src/main/java/org/openhab/binding/mqtt/generic/ChannelState.java @@ -32,6 +32,7 @@ import org.openhab.core.thing.ChannelUID; import org.openhab.core.types.Command; import org.openhab.core.types.State; +import org.openhab.core.types.Type; import org.openhab.core.types.TypeParser; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -198,10 +199,10 @@ public void processMessage(String topic, byte[] payload) { return; } - Command parsedCommand; + Type parsedType; // Map the string to a command, update the cached value and post the command to the framework try { - parsedCommand = cachedValue.parseMessage(command); + parsedType = cachedValue.parseMessage(command); } catch (IllegalArgumentException | IllegalStateException e) { logger.warn("Command '{}' from channel '{}' not supported by type '{}': {}", strValue, channelUID, cachedValue.getClass().getSimpleName(), e.getMessage()); @@ -209,18 +210,20 @@ public void processMessage(String topic, byte[] payload) { return; } - // things that are only Commands _must_ be posted as a command (like STOP) - if (!(parsedCommand instanceof State)) { - channelStateUpdateListener.postChannelCommand(channelUID, parsedCommand); + if (parsedType instanceof State parsedState) { + cachedValue.update(parsedState); + } else { + // things that are only Commands _must_ be posted as a command (like STOP) + channelStateUpdateListener.postChannelCommand(channelUID, (Command) parsedType); receivedOrTimeout(); return; } - cachedValue.update((State) parsedCommand); - if (config.postCommand) { - channelStateUpdateListener.postChannelCommand(channelUID, (Command) cachedValue.getChannelState()); + State newState = cachedValue.getChannelState(); + if (config.postCommand && newState instanceof Command newCommand) { + channelStateUpdateListener.postChannelCommand(channelUID, newCommand); } else { - channelStateUpdateListener.updateChannelState(channelUID, cachedValue.getChannelState()); + channelStateUpdateListener.updateChannelState(channelUID, newState); } receivedOrTimeout(); } diff --git a/bundles/org.openhab.binding.mqtt.generic/src/main/java/org/openhab/binding/mqtt/generic/values/NumberValue.java b/bundles/org.openhab.binding.mqtt.generic/src/main/java/org/openhab/binding/mqtt/generic/values/NumberValue.java index f65dd125e4036..453d41764cb1f 100644 --- a/bundles/org.openhab.binding.mqtt.generic/src/main/java/org/openhab/binding/mqtt/generic/values/NumberValue.java +++ b/bundles/org.openhab.binding.mqtt.generic/src/main/java/org/openhab/binding/mqtt/generic/values/NumberValue.java @@ -23,10 +23,13 @@ import org.openhab.core.library.types.DecimalType; import org.openhab.core.library.types.IncreaseDecreaseType; import org.openhab.core.library.types.QuantityType; +import org.openhab.core.library.types.StringType; import org.openhab.core.library.types.UpDownType; import org.openhab.core.library.unit.Units; import org.openhab.core.types.Command; import org.openhab.core.types.StateDescriptionFragmentBuilder; +import org.openhab.core.types.Type; +import org.openhab.core.types.UnDefType; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -43,6 +46,8 @@ */ @NonNullByDefault public class NumberValue extends Value { + private static final String NAN = "NaN"; + private final Logger logger = LoggerFactory.getLogger(NumberValue.class); private final @Nullable BigDecimal min; private final @Nullable BigDecimal max; @@ -51,7 +56,8 @@ public class NumberValue extends Value { public NumberValue(@Nullable BigDecimal min, @Nullable BigDecimal max, @Nullable BigDecimal step, @Nullable Unit unit) { - super(CoreItemFactory.NUMBER, List.of(QuantityType.class, IncreaseDecreaseType.class, UpDownType.class)); + super(CoreItemFactory.NUMBER, + List.of(QuantityType.class, IncreaseDecreaseType.class, UpDownType.class, StringType.class)); this.min = min; this.max = max; this.step = step == null ? BigDecimal.ONE : step; @@ -112,6 +118,14 @@ public Command parseCommand(Command command) throws IllegalArgumentException { } } + @Override + public Type parseMessage(Command command) throws IllegalArgumentException { + if (command instanceof StringType && command.toString().equalsIgnoreCase(NAN)) { + return UnDefType.UNDEF; + } + return parseCommand(command); + } + private BigDecimal getOldValue() { BigDecimal val = BigDecimal.ZERO; if (state instanceof DecimalType decimalCommand) { diff --git a/bundles/org.openhab.binding.mqtt.generic/src/main/java/org/openhab/binding/mqtt/generic/values/Value.java b/bundles/org.openhab.binding.mqtt.generic/src/main/java/org/openhab/binding/mqtt/generic/values/Value.java index e5f672da28336..76839cf514704 100644 --- a/bundles/org.openhab.binding.mqtt.generic/src/main/java/org/openhab/binding/mqtt/generic/values/Value.java +++ b/bundles/org.openhab.binding.mqtt.generic/src/main/java/org/openhab/binding/mqtt/generic/values/Value.java @@ -27,6 +27,7 @@ import org.openhab.core.types.CommandDescriptionBuilder; import org.openhab.core.types.State; import org.openhab.core.types.StateDescriptionFragmentBuilder; +import org.openhab.core.types.Type; import org.openhab.core.types.UnDefType; /** @@ -145,7 +146,7 @@ public void update(State newState) throws IllegalArgumentException { * @param command The command to parse. * @exception IllegalArgumentException Thrown if for example a text is assigned to a number type. */ - public Command parseMessage(Command command) throws IllegalArgumentException { + public Type parseMessage(Command command) throws IllegalArgumentException { return parseCommand(command); } diff --git a/bundles/org.openhab.binding.mqtt.generic/src/test/java/org/openhab/binding/mqtt/generic/values/ValueTests.java b/bundles/org.openhab.binding.mqtt.generic/src/test/java/org/openhab/binding/mqtt/generic/values/ValueTests.java index 4f52814bb91f8..5d9de8bb8476b 100644 --- a/bundles/org.openhab.binding.mqtt.generic/src/test/java/org/openhab/binding/mqtt/generic/values/ValueTests.java +++ b/bundles/org.openhab.binding.mqtt.generic/src/test/java/org/openhab/binding/mqtt/generic/values/ValueTests.java @@ -37,6 +37,7 @@ import org.openhab.core.types.Command; import org.openhab.core.types.State; import org.openhab.core.types.TypeParser; +import org.openhab.core.types.UnDefType; /** * Test cases for the value classes. They should throw exceptions if the wrong command type is used @@ -175,6 +176,9 @@ public void numberUpdate() { command = v.parseCommand(new QuantityType<>("20")); assertThat(command, is(new QuantityType<>(20, Units.WATT))); assertThat(v.getMQTTpublishValue(command, null), is("20")); + + assertThat(v.parseMessage(new StringType("NaN")), is(UnDefType.UNDEF)); + assertThat(v.parseMessage(new StringType("nan")), is(UnDefType.UNDEF)); } @Test