diff --git a/bundles/org.openhab.binding.mqtt.generic/README.md b/bundles/org.openhab.binding.mqtt.generic/README.md index 46aae9e0eeac7..8aa4f81913e18 100644 --- a/bundles/org.openhab.binding.mqtt.generic/README.md +++ b/bundles/org.openhab.binding.mqtt.generic/README.md @@ -199,6 +199,7 @@ The channel expects values on the corresponding MQTT topic to be in this format - **on**: An optional string (like "Open") that is recognized as `UP` state. - **off**: An optional string (like "Close") that is recognized as `DOWN` state. - **stop**: An optional string (like "Stop") that is recognized as `STOP` state. +- **stopCommandTopic**: An optional topic to send `STOP` commands to. If not set, `STOP` commands are sent to the main **commandTopic**. Internally `UP` is converted to 0%, `DOWN` to 100%. If strings are defined for these values, they are used for sending commands to the broker, too. 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 d3adf2677861a..b907052019c88 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 @@ -32,6 +32,7 @@ public class ChannelConfig { /** This is either a state topic or a trigger topic, depending on {@link #trigger}. */ public String stateTopic = ""; public String commandTopic = ""; + public String stopCommandTopic = ""; /** * If true, the channel state is not updated on a new message. diff --git a/bundles/org.openhab.binding.mqtt.generic/src/main/java/org/openhab/binding/mqtt/generic/ChannelConfigBuilder.java b/bundles/org.openhab.binding.mqtt.generic/src/main/java/org/openhab/binding/mqtt/generic/ChannelConfigBuilder.java index 9c4fe483669d6..8df35ecb57aef 100644 --- a/bundles/org.openhab.binding.mqtt.generic/src/main/java/org/openhab/binding/mqtt/generic/ChannelConfigBuilder.java +++ b/bundles/org.openhab.binding.mqtt.generic/src/main/java/org/openhab/binding/mqtt/generic/ChannelConfigBuilder.java @@ -59,6 +59,13 @@ public ChannelConfigBuilder withCommandTopic(@Nullable String topic) { return this; } + public ChannelConfigBuilder withStopCommandTopic(@Nullable String topic) { + if (topic != null) { + config.stopCommandTopic = topic; + } + return this; + } + public ChannelConfigBuilder withRetain(boolean retain) { config.retained = retain; return this; 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 832f94397e13a..06ea08fbdbc53 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 @@ -30,6 +30,7 @@ import org.openhab.core.io.transport.mqtt.MqttMessageSubscriber; import org.openhab.core.library.types.DecimalType; import org.openhab.core.library.types.QuantityType; +import org.openhab.core.library.types.StopMoveType; import org.openhab.core.library.types.StringType; import org.openhab.core.thing.ChannelUID; import org.openhab.core.types.Command; @@ -420,7 +421,13 @@ public CompletableFuture publishValue(Command command) { int qos = (config.qos != null) ? config.qos : connection.getQos(); - return connection.publish(config.commandTopic, commandString.getBytes(), qos, config.retained); + String commandTopic; + if (command.equals(StopMoveType.STOP) && !config.stopCommandTopic.isEmpty()) { + commandTopic = config.stopCommandTopic; + } else { + commandTopic = config.commandTopic; + } + return connection.publish(commandTopic, commandString.getBytes(), qos, config.retained); } /** diff --git a/bundles/org.openhab.binding.mqtt.generic/src/main/resources/OH-INF/config/rollershutter-channel-config.xml b/bundles/org.openhab.binding.mqtt.generic/src/main/resources/OH-INF/config/rollershutter-channel-config.xml index b87161d70a3bc..25f78a194b1cd 100644 --- a/bundles/org.openhab.binding.mqtt.generic/src/main/resources/OH-INF/config/rollershutter-channel-config.xml +++ b/bundles/org.openhab.binding.mqtt.generic/src/main/resources/OH-INF/config/rollershutter-channel-config.xml @@ -22,6 +22,11 @@ An MQTT topic that this thing will send a command to. If not set, this will be a read-only rollershutter. + + + An MQTT topic that this thing will send a STOP command to. If not set, it will send STOP commands to the + main commandTopic. + Arrays.equals(p, "STOP".getBytes())), anyInt(), + eq(false)); + + c.stop().get(); + verify(connectionMock).unsubscribe(eq("state"), eq(c)); + } + + @Test + public void publishStopSeparateTopicTest() throws Exception { + ChannelConfig config = ChannelConfigBuilder.create("state", "command").withStopCommandTopic("stopCommand") + .build(); + config.stop = "STOP"; + ChannelState c = spy(new ChannelState(config, channelUIDMock, textValue, channelStateUpdateListenerMock)); + + c.start(connectionMock, scheduler, 0).get(50, TimeUnit.MILLISECONDS); + verify(connectionMock).subscribe(eq("state"), eq(c)); + + c.publishValue(StopMoveType.STOP).get(); + verify(connectionMock).publish(eq("stopCommand"), argThat(p -> Arrays.equals(p, "STOP".getBytes())), anyInt(), + eq(false)); + + c.stop().get(); + verify(connectionMock).unsubscribe(eq("state"), eq(c)); + } + @Test public void receiveWildcardTest() throws Exception { ChannelState c = spy(new ChannelState(ChannelConfigBuilder.create("state/+/topic", "command").build(),