public @Nullable String stop;
public @Nullable String onState;
public @Nullable String offState;
+ public @Nullable String nullValue;
public int onBrightness = 10;
public String colorMode = ColorMode.HSB.toString();
@Override
public Type parseMessage(Command command) throws IllegalArgumentException {
- if (command instanceof StringType
- && (command.toString().equalsIgnoreCase(NAN) || command.toString().equalsIgnoreCase(NEGATIVE_NAN))) {
- return UnDefType.UNDEF;
+ if (command instanceof StringType) {
+ if (command.toString().equalsIgnoreCase(NAN) || command.toString().equalsIgnoreCase(NEGATIVE_NAN)) {
+ return UnDefType.UNDEF;
+ } else if (command.toString().isEmpty()) {
+ return UnDefType.NULL;
+ }
}
return parseCommand(command);
}
import org.openhab.core.library.types.StringType;
import org.openhab.core.library.types.UpDownType;
import org.openhab.core.types.Command;
+import org.openhab.core.types.Type;
+import org.openhab.core.types.UnDefType;
/**
* Implements a rollershutter value.
}
@Override
- public Command parseMessage(Command command) throws IllegalArgumentException {
+ public Type parseMessage(Command command) throws IllegalArgumentException {
+ if (command instanceof StringType string && string.toString().isEmpty()) {
+ return UnDefType.NULL;
+ }
command = parseType(command, upStateString, downStateString);
if (inverted && command instanceof PercentType percentType) {
return new PercentType(100 - percentType.intValue());
import org.openhab.core.types.State;
import org.openhab.core.types.StateDescriptionFragmentBuilder;
import org.openhab.core.types.StateOption;
+import org.openhab.core.types.UnDefType;
/**
* Implements a text/string value. Allows to restrict the incoming value to a set of states.
private final @Nullable Set<String> states;
private final @Nullable Set<String> commands;
+ protected @Nullable String nullValue = null;
+
/**
* Create a string value with a limited number of allowed states and commands.
*
this.commands = null;
}
+ public void setNullValue(@Nullable String nullValue) {
+ this.nullValue = nullValue;
+ }
+
@Override
public StringType parseCommand(Command command) throws IllegalArgumentException {
final Set<String> commands = this.commands;
@Override
public State parseMessage(Command command) throws IllegalArgumentException {
+ if (command instanceof StringType string && string.toString().equals(nullValue)) {
+ return UnDefType.NULL;
+ }
+
final Set<String> states = this.states;
String valueStr = command.toString();
if (states != null && !states.contains(valueStr)) {
import org.openhab.core.library.types.DecimalType;
import org.openhab.core.library.types.PercentType;
import org.openhab.core.library.types.RawType;
+import org.openhab.core.library.types.StringType;
import org.openhab.core.types.Command;
import org.openhab.core.types.CommandDescriptionBuilder;
import org.openhab.core.types.State;
* @exception IllegalArgumentException Thrown if for example a text is assigned to a number type.
*/
public Type parseMessage(Command command) throws IllegalArgumentException {
+ if (command instanceof StringType string && string.toString().isEmpty()) {
+ return UnDefType.NULL;
+ }
return parseCommand(command);
}
Value value;
switch (channelTypeID) {
case MqttBindingConstants.STRING:
- value = config.allowedStates.isBlank() ? new TextValue()
+ TextValue textValue = config.allowedStates.isBlank() ? new TextValue()
: new TextValue(config.allowedStates.split(","));
+ textValue.setNullValue(config.nullValue);
+ value = textValue;
break;
case MqttBindingConstants.DATETIME:
value = new DateTimeValue();
<default>false</default>
<advanced>true</advanced>
</parameter>
+ <parameter name="nullValue" type="text">
+ <label>NULL Value</label>
+ <description>If the received MQTT value matches this, treat it as NULL.</description>
+ <advanced>true</advanced>
+ </parameter>
<parameter name="allowedStates" type="text">
<label>Allowed States</label>
thing-type.config.mqtt.string_channel.transformationPattern.description = Applies transformations to an incoming MQTT topic value. A transformation example for a received JSON would be "JSONPATH:$.device.status.temperature" for a json {device: {status: { temperature: 23.2 }}}. You can chain transformations by separating them with the intersection character ∩.
thing-type.config.mqtt.string_channel.transformationPatternOut.label = Outgoing Value Transformation
thing-type.config.mqtt.string_channel.transformationPatternOut.description = Applies a transformation before publishing a MQTT topic value. Transformations are specialised in extracting a value, but some transformations like the MAP one could be useful.
+thing-type.config.mqtt.string_channel.nullValue.label = NULL Value
+thing-type.config.mqtt.string_channel.nullValue.description = If the received MQTT value matches this, treat it as NULL.
thing-type.config.mqtt.switch_channel.commandTopic.label = MQTT Command Topic
thing-type.config.mqtt.switch_channel.commandTopic.description = An MQTT topic that this thing will send a command to. If not set, this will be a read-only switch.
thing-type.config.mqtt.switch_channel.formatBeforePublish.label = Outgoing Value Format
assertThat(hsb.getBrightness().intValue(), is(0));
hsb = (HSBType) v.parseCommand(p(v, "1"));
assertThat(hsb.getBrightness().intValue(), is(1));
+
+ assertThat(v.parseMessage(new StringType("")), is(UnDefType.NULL));
}
@Test
// Test custom formatting
assertThat(v.getMQTTpublishValue(OnOffType.OFF, "=%s"), is("=fancyOff"));
assertThat(v.getMQTTpublishValue(OnOffType.ON, "=%s"), is("=fancyON"));
+
+ assertThat(v.parseMessage(new StringType("")), is(UnDefType.NULL));
}
@Test
// Test basic formatting
assertThat(v.getMQTTpublishValue(OpenClosedType.CLOSED, null), is("fancyOff"));
assertThat(v.getMQTTpublishValue(OpenClosedType.OPEN, null), is("fancyON"));
+
+ assertThat(v.parseMessage(new StringType("")), is(UnDefType.NULL));
}
@Test
assertThat(v.parseMessage(new StringType("nan")), is(UnDefType.UNDEF));
assertThat(v.parseMessage(new StringType("-NaN")), is(UnDefType.UNDEF));
assertThat(v.parseMessage(new StringType("-nan")), is(UnDefType.UNDEF));
+
+ assertThat(v.parseMessage(new StringType("")), is(UnDefType.NULL));
}
@Test
// Test parsing from MQTT
assertThat(v.parseMessage(new StringType("fancyON")), is(UpDownType.UP));
assertThat(v.parseMessage(new StringType("fancyOff")), is(UpDownType.DOWN));
+
+ assertThat(v.parseMessage(new StringType("")), is(UnDefType.NULL));
}
@Test
command = v.parseCommand(new DecimalType(i));
assertThat(v.getMQTTpublishValue(command, null), is("" + i));
}
+
+ assertThat(v.parseMessage(new StringType("")), is(UnDefType.NULL));
}
@Test
null);
assertThrows(IllegalArgumentException.class, () -> v.parseCommand(new DecimalType(9.0)));
}
+
+ @Test
+ public void textUpdate() {
+ TextValue v = new TextValue();
+
+ assertThat(v.parseMessage(new StringType("")), is(new StringType("")));
+ assertThat(v.parseMessage(new StringType("NULL")), is(new StringType("NULL")));
+
+ v.setNullValue("");
+ assertThat(v.parseMessage(new StringType("")), is(UnDefType.NULL));
+ assertThat(v.parseMessage(new StringType("NULL")), is(new StringType("NULL")));
+
+ v.setNullValue("NULL");
+ assertThat(v.parseMessage(new StringType("NULL")), is(UnDefType.NULL));
+ assertThat(v.parseMessage(new StringType("")), is(new StringType("")));
+ }
}