diff --git a/bundles/org.openhab.binding.mqtt.generic/src/main/java/org/openhab/binding/mqtt/generic/ChannelConfig.java b/bundles/org.openhab.binding.mqtt.generic/src/main/java/org/openhab/binding/mqtt/generic/ChannelConfig.java index da9117e0dd35a..78cb1a3534fa8 100644 --- a/bundles/org.openhab.binding.mqtt.generic/src/main/java/org/openhab/binding/mqtt/generic/ChannelConfig.java +++ b/bundles/org.openhab.binding.mqtt.generic/src/main/java/org/openhab/binding/mqtt/generic/ChannelConfig.java @@ -35,7 +35,9 @@ public class ChannelConfig { /** * If true, the channel state is not updated on a new message. - * Instead a postCommand() call is performed. + * Instead a postCommand() call is performed. If the message is + * not possible to send as a command (i.e. UNDEF), it will ignore + * this. */ public boolean postCommand = false; public @Nullable Integer qos; 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..869e6c0eccfd8 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,23 @@ 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 the user explicitly wants a command sent, not an update, do that. But + // we have to check that the state is even possible to send as a command + // (i.e. not UNDEF) + 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/main/resources/OH-INF/config/number-channel-config.xml b/bundles/org.openhab.binding.mqtt.generic/src/main/resources/OH-INF/config/number-channel-config.xml index be146d14c5813..abd7ac5693779 100644 --- a/bundles/org.openhab.binding.mqtt.generic/src/main/resources/OH-INF/config/number-channel-config.xml +++ b/bundles/org.openhab.binding.mqtt.generic/src/main/resources/OH-INF/config/number-channel-config.xml @@ -74,7 +74,7 @@ If the received MQTT value should not only update the state of linked items, but command them, enable - this option. + this option. Note that if the value is NaN (interpreted as UNDEF), it can only update; commands are not possible. false true diff --git a/bundles/org.openhab.binding.mqtt.generic/src/main/resources/OH-INF/i18n/mqtt.properties b/bundles/org.openhab.binding.mqtt.generic/src/main/resources/OH-INF/i18n/mqtt.properties index e3e20d452cfdd..f02c9b5dc50dd 100644 --- a/bundles/org.openhab.binding.mqtt.generic/src/main/resources/OH-INF/i18n/mqtt.properties +++ b/bundles/org.openhab.binding.mqtt.generic/src/main/resources/OH-INF/i18n/mqtt.properties @@ -109,7 +109,7 @@ thing-type.config.mqtt.number_channel.max.description = This configuration repre thing-type.config.mqtt.number_channel.min.label = Absolute Minimum thing-type.config.mqtt.number_channel.min.description = This configuration represents the minimum of the allowed range. For a percentage channel that equals zero percent. thing-type.config.mqtt.number_channel.postCommand.label = Is Command -thing-type.config.mqtt.number_channel.postCommand.description = If the received MQTT value should not only update the state of linked items, but command them, enable this option. +thing-type.config.mqtt.number_channel.postCommand.description = If the received MQTT value should not only update the state of linked items, but command them, enable this option. Note that if the value is NaN (interpreted as UNDEF), it can only update; commands are not possible. thing-type.config.mqtt.number_channel.qos.label = QoS thing-type.config.mqtt.number_channel.qos.description = MQTT QoS of this channel (0, 1, 2). Default is QoS of the broker connection. thing-type.config.mqtt.number_channel.qos.option.0 = At most once (best effort delivery "fire and forget") 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