Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[mqtt] Interpet incoming NaN as UNDEF for NumberValues #15897

Merged
merged 2 commits into from
Dec 10, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -198,29 +199,34 @@ 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());
receivedOrTimeout();
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) {
ccutrer marked this conversation as resolved.
Show resolved Hide resolved
channelStateUpdateListener.postChannelCommand(channelUID, newCommand);
} else {
channelStateUpdateListener.updateChannelState(channelUID, cachedValue.getChannelState());
channelStateUpdateListener.updateChannelState(channelUID, newState);
}
receivedOrTimeout();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

/**
Expand Down Expand Up @@ -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);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@
<parameter name="postCommand" type="boolean">
<label>Is Command</label>
<description>If the received MQTT value should not only update the state of linked items, but command them, enable
this option.</description>
this option. Note that if the value is NaN (interpreted as UNDEF), it can only update; commands are not possible.</description>
<default>false</default>
<advanced>true</advanced>
</parameter>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down