Skip to content

Commit

Permalink
[mqtt] Interpet incoming NaN as UNDEF for NumberValues
Browse files Browse the repository at this point in the history
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 <cody@cutrer.us>
  • Loading branch information
ccutrer committed Nov 20, 2023
1 parent ab0ea34 commit 83571e2
Show file tree
Hide file tree
Showing 4 changed files with 33 additions and 11 deletions.
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,31 @@ 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 (config.postCommand && newState instanceof Command newCommand) {
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 @@ -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

0 comments on commit 83571e2

Please sign in to comment.