[mqtt.homeassistant] Improve Cover support (#15875)
* [mqtt.homeassistant] improve Cover support * Add support for covers that report position * Handle when command and state values for OPEN/CLOSE/STOP differ (as they do by default) * Expose the full cover state, since it can have tell you if the cover is moving or not * Handle covers that have a position only, but not a state * add constants to clarify up/down values * Be sure to parse percents from strings in RollshutterValue --------- Signed-off-by: Cody Cutrer <cody@cutrer.us>
This commit is contained in:
@@ -36,9 +36,46 @@ import org.openhab.core.types.Command;
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class RollershutterValue extends Value {
|
||||
private final @Nullable String upString;
|
||||
private final @Nullable String downString;
|
||||
private final String stopString;
|
||||
// openHAB interprets open rollershutters as 0, and closed as 100
|
||||
private static final String UP_VALUE = "0";
|
||||
private static final String DOWN_VALUE = "100";
|
||||
// other devices may interpret it the opposite, so we need to be able
|
||||
// to invert it
|
||||
private static final String INVERTED_UP_VALUE = DOWN_VALUE;
|
||||
private static final String INVERTED_DOWN_VALUE = UP_VALUE;
|
||||
|
||||
private final @Nullable String upCommandString;
|
||||
private final @Nullable String downCommandString;
|
||||
private final @Nullable String stopCommandString;
|
||||
private final @Nullable String upStateString;
|
||||
private final @Nullable String downStateString;
|
||||
private final boolean inverted;
|
||||
private final boolean transformExtentsToString;
|
||||
|
||||
/**
|
||||
* Creates a new rollershutter value.
|
||||
*
|
||||
* @param upCommandString The UP command string.
|
||||
* @param downCommandString The DOWN command string.
|
||||
* @param stopCommandString The STOP command string.
|
||||
* @param upStateString The UP value string. This will be compared to MQTT messages.
|
||||
* @param downStateString The DOWN value string. This will be compared to MQTT messages.
|
||||
* @param inverted Whether to invert 0-100/100-0
|
||||
* @param transformExtentsToString Whether 0/100 will be sent as UP/DOWN
|
||||
*/
|
||||
public RollershutterValue(@Nullable String upCommandString, @Nullable String downCommandString,
|
||||
@Nullable String stopCommandString, @Nullable String upStateString, @Nullable String downStateString,
|
||||
boolean inverted, boolean transformExtentsToString) {
|
||||
super(CoreItemFactory.ROLLERSHUTTER,
|
||||
List.of(UpDownType.class, StopMoveType.class, PercentType.class, StringType.class));
|
||||
this.upCommandString = upCommandString;
|
||||
this.downCommandString = downCommandString;
|
||||
this.stopCommandString = stopCommandString;
|
||||
this.upStateString = upStateString;
|
||||
this.downStateString = downStateString;
|
||||
this.inverted = inverted;
|
||||
this.transformExtentsToString = transformExtentsToString;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new rollershutter value.
|
||||
@@ -48,17 +85,13 @@ public class RollershutterValue extends Value {
|
||||
* @param stopString The STOP value string. This will be compared to MQTT messages.
|
||||
*/
|
||||
public RollershutterValue(@Nullable String upString, @Nullable String downString, @Nullable String stopString) {
|
||||
super(CoreItemFactory.ROLLERSHUTTER,
|
||||
List.of(UpDownType.class, StopMoveType.class, PercentType.class, StringType.class));
|
||||
this.upString = upString;
|
||||
this.downString = downString;
|
||||
this.stopString = stopString == null ? StopMoveType.STOP.name() : stopString;
|
||||
this(upString, downString, stopString, upString, downString, false, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Command parseCommand(Command command) throws IllegalArgumentException {
|
||||
private Command parseType(Command command, @Nullable String upString, @Nullable String downString)
|
||||
throws IllegalArgumentException {
|
||||
if (command instanceof StopMoveType) {
|
||||
if (command == StopMoveType.STOP) {
|
||||
if (command == StopMoveType.STOP && stopCommandString != null) {
|
||||
return command;
|
||||
} else {
|
||||
throw new IllegalArgumentException(command.toString() + " is not a valid command for MQTT.");
|
||||
@@ -68,12 +101,14 @@ public class RollershutterValue extends Value {
|
||||
if (upString != null) {
|
||||
return command;
|
||||
} else {
|
||||
// Do not handle inversion here. See parseCommand below
|
||||
return PercentType.ZERO;
|
||||
}
|
||||
} else {
|
||||
if (downString != null) {
|
||||
return command;
|
||||
} else {
|
||||
// Do not handle inversion here. See parseCommand below
|
||||
return PercentType.HUNDRED;
|
||||
}
|
||||
}
|
||||
@@ -85,43 +120,70 @@ public class RollershutterValue extends Value {
|
||||
return UpDownType.UP;
|
||||
} else if (updatedValue.equals(downString)) {
|
||||
return UpDownType.DOWN;
|
||||
} else if (updatedValue.equals(stopString)) {
|
||||
} else if (updatedValue.equals(stopCommandString)) {
|
||||
return StopMoveType.STOP;
|
||||
} else {
|
||||
return PercentType.valueOf(updatedValue);
|
||||
}
|
||||
}
|
||||
throw new IllegalStateException("Cannot call parseCommand() with " + command.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Command parseCommand(Command command) throws IllegalArgumentException {
|
||||
// Do not handle inversion in this code path. parseCommand might be called
|
||||
// multiple times when sending a command TO an MQTT topic. The inversion is
|
||||
// handled _only_ in getMQTTpublishValue
|
||||
return parseType(command, upCommandString, downCommandString);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Command parseMessage(Command command) throws IllegalArgumentException {
|
||||
command = parseType(command, upStateString, downStateString);
|
||||
if (inverted && command instanceof PercentType percentType) {
|
||||
return new PercentType(100 - percentType.intValue());
|
||||
}
|
||||
return command;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMQTTpublishValue(Command command, @Nullable String pattern) {
|
||||
final String upString = this.upString;
|
||||
final String downString = this.downString;
|
||||
final String stopString = this.stopString;
|
||||
return getMQTTpublishValue(command, transformExtentsToString);
|
||||
}
|
||||
|
||||
public String getMQTTpublishValue(Command command, boolean transformExtentsToString) {
|
||||
final String upCommandString = this.upCommandString;
|
||||
final String downCommandString = this.downCommandString;
|
||||
final String stopCommandString = this.stopCommandString;
|
||||
if (command == UpDownType.UP) {
|
||||
if (upString != null) {
|
||||
return upString;
|
||||
if (upCommandString != null) {
|
||||
return upCommandString;
|
||||
} else {
|
||||
return ((UpDownType) command).name();
|
||||
return (inverted ? INVERTED_UP_VALUE : UP_VALUE);
|
||||
}
|
||||
} else if (command == UpDownType.DOWN) {
|
||||
if (downString != null) {
|
||||
return downString;
|
||||
if (downCommandString != null) {
|
||||
return downCommandString;
|
||||
} else {
|
||||
return ((UpDownType) command).name();
|
||||
return (inverted ? INVERTED_DOWN_VALUE : DOWN_VALUE);
|
||||
}
|
||||
} else if (command == StopMoveType.STOP) {
|
||||
if (stopString != null) {
|
||||
return stopString;
|
||||
if (stopCommandString != null) {
|
||||
return stopCommandString;
|
||||
} else {
|
||||
return ((StopMoveType) command).name();
|
||||
}
|
||||
} else if (command instanceof PercentType percentage) {
|
||||
if (command.equals(PercentType.HUNDRED) && downString != null) {
|
||||
return downString;
|
||||
} else if (command.equals(PercentType.ZERO) && upString != null) {
|
||||
return upString;
|
||||
if (transformExtentsToString && command.equals(PercentType.HUNDRED) && downCommandString != null) {
|
||||
return downCommandString;
|
||||
} else if (transformExtentsToString && command.equals(PercentType.ZERO) && upCommandString != null) {
|
||||
return upCommandString;
|
||||
} else {
|
||||
return String.valueOf(percentage.intValue());
|
||||
int value = percentage.intValue();
|
||||
if (inverted) {
|
||||
value = 100 - value;
|
||||
}
|
||||
return String.valueOf(value);
|
||||
}
|
||||
} else {
|
||||
throw new IllegalArgumentException("Invalid command type for Rollershutter item");
|
||||
|
||||
@@ -227,6 +227,39 @@ public class ValueTests {
|
||||
// Test formatting 0/100
|
||||
assertThat(v.getMQTTpublishValue(PercentType.ZERO, null), is("fancyON"));
|
||||
assertThat(v.getMQTTpublishValue(PercentType.HUNDRED, null), is("fancyOff"));
|
||||
|
||||
// Test parsing from MQTT
|
||||
assertThat(v.parseMessage(new StringType("fancyON")), is(UpDownType.UP));
|
||||
assertThat(v.parseMessage(new StringType("fancyOff")), is(UpDownType.DOWN));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void rollershutterUpdateWithDiscreteCommandAndStateStrings() {
|
||||
RollershutterValue v = new RollershutterValue("OPEN", "CLOSE", "STOP", "open", "closed", false, true);
|
||||
// Test with UP/DOWN/STOP command
|
||||
assertThat(v.parseCommand(UpDownType.UP), is(UpDownType.UP));
|
||||
assertThat(v.getMQTTpublishValue(UpDownType.UP, null), is("OPEN"));
|
||||
assertThat(v.parseCommand(UpDownType.DOWN), is(UpDownType.DOWN));
|
||||
assertThat(v.getMQTTpublishValue(UpDownType.DOWN, null), is("CLOSE"));
|
||||
assertThat(v.parseCommand(StopMoveType.STOP), is(StopMoveType.STOP));
|
||||
assertThat(v.getMQTTpublishValue(StopMoveType.STOP, null), is("STOP"));
|
||||
|
||||
// Test with custom string
|
||||
assertThat(v.parseCommand(new StringType("OPEN")), is(UpDownType.UP));
|
||||
assertThat(v.parseCommand(new StringType("CLOSE")), is(UpDownType.DOWN));
|
||||
|
||||
// Test with exact percent
|
||||
Command command = new PercentType(27);
|
||||
assertThat(v.parseCommand((Command) command), is(command));
|
||||
assertThat(v.getMQTTpublishValue(command, null), is("27"));
|
||||
|
||||
// Test formatting 0/100
|
||||
assertThat(v.getMQTTpublishValue(PercentType.ZERO, null), is("OPEN"));
|
||||
assertThat(v.getMQTTpublishValue(PercentType.HUNDRED, null), is("CLOSE"));
|
||||
|
||||
// Test parsing from MQTT
|
||||
assertThat(v.parseMessage(new StringType("open")), is(UpDownType.UP));
|
||||
assertThat(v.parseMessage(new StringType("closed")), is(UpDownType.DOWN));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
Reference in New Issue
Block a user