From a3bd8caba97f65552189c2bd7278d8a5b93f2e5b Mon Sep 17 00:00:00 2001 From: jimtng <2554958+jimtng@users.noreply.github.com> Date: Sun, 6 Feb 2022 19:30:06 +1000 Subject: [PATCH] [mqtt.generic] Support transformationPattern for thing's availabilityTopic (#12167) * [mqtt.generic] Support transformationPattern for thing's availability payload * [mqtt] Remove org.apache.commons.lang3.StringUtils dependency Signed-off-by: Jimmy Tanagra --- .../org.openhab.binding.mqtt.generic/README.md | 1 + .../mqtt/generic/AbstractMQTTThingHandler.java | 9 +++++++++ .../binding/mqtt/generic/ChannelState.java | 17 +++++++++++++++++ .../handler/GenericMQTTThingHandler.java | 18 ++++-------------- .../handler/GenericThingConfiguration.java | 5 +++++ .../resources/OH-INF/thing/generic-thing.xml | 13 +++++++++++++ 6 files changed, 49 insertions(+), 14 deletions(-) diff --git a/bundles/org.openhab.binding.mqtt.generic/README.md b/bundles/org.openhab.binding.mqtt.generic/README.md index eb679a04b..359f934a9 100644 --- a/bundles/org.openhab.binding.mqtt.generic/README.md +++ b/bundles/org.openhab.binding.mqtt.generic/README.md @@ -58,6 +58,7 @@ The following optional parameters can be set for the Thing: * __availabilityTopic__: The MQTT topic that represents the availability of the thing. This can be the thing's LWT topic. * __payloadAvailable__: Payload of the `Availability Topic`, when the device is available. Default: `ON`. * __payloadNotAvailable__: Payload of the `Availability Topic`, when the device is *not* available. Default: `OFF`. +* __transformationPattern__: An optional transformation pattern like [JSONPath](https://goessner.net/articles/JsonPath/index.html#e2) that is applied to the incoming availability payload. Transformations can be chained by separating them with the mathematical intersection character "∩". The result of the transformations is then checked against `payloadAvailable` and `payloadNotAvailable`. ## Supported Channels diff --git a/bundles/org.openhab.binding.mqtt.generic/src/main/java/org/openhab/binding/mqtt/generic/AbstractMQTTThingHandler.java b/bundles/org.openhab.binding.mqtt.generic/src/main/java/org/openhab/binding/mqtt/generic/AbstractMQTTThingHandler.java index c53a00e0f..e7ff415f4 100644 --- a/bundles/org.openhab.binding.mqtt.generic/src/main/java/org/openhab/binding/mqtt/generic/AbstractMQTTThingHandler.java +++ b/bundles/org.openhab.binding.mqtt.generic/src/main/java/org/openhab/binding/mqtt/generic/AbstractMQTTThingHandler.java @@ -289,6 +289,12 @@ public abstract class AbstractMQTTThingHandler extends BaseThingHandler @Override public void addAvailabilityTopic(String availability_topic, String payload_available, String payload_not_available) { + addAvailabilityTopic(availability_topic, payload_available, payload_not_available, null, null); + } + + public void addAvailabilityTopic(String availability_topic, String payload_available, String payload_not_available, + @Nullable String transformation_pattern, + @Nullable TransformationServiceProvider transformationServiceProvider) { availabilityStates.computeIfAbsent(availability_topic, topic -> { Value value = new OnOffValue(payload_available, payload_not_available); ChannelGroupUID groupUID = new ChannelGroupUID(getThing().getUID(), "availablility"); @@ -308,6 +314,9 @@ public abstract class AbstractMQTTThingHandler extends BaseThingHandler public void postChannelCommand(ChannelUID channelUID, Command value) { } }); + if (transformation_pattern != null && transformationServiceProvider != null) { + state.addTransformation(transformation_pattern, transformationServiceProvider); + } MqttBrokerConnection connection = getConnection(); if (connection != null) { state.start(connection, scheduler, 0); 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 fb2a0213d..8b1ea428a 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 @@ -20,6 +20,7 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; +import java.util.stream.Stream; import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; @@ -94,6 +95,10 @@ public class ChannelState implements MqttMessageSubscriber { transformationsIn.add(transformation); } + public void addTransformation(String transformation, TransformationServiceProvider transformationServiceProvider) { + parseTransformation(transformation, transformationServiceProvider).forEach(t -> addTransformation(t)); + } + /** * Add a transformation that is applied for each value to be published. * The transformations are executed in order. @@ -104,6 +109,18 @@ public class ChannelState implements MqttMessageSubscriber { transformationsOut.add(transformation); } + public void addTransformationOut(String transformation, + TransformationServiceProvider transformationServiceProvider) { + parseTransformation(transformation, transformationServiceProvider).forEach(t -> addTransformationOut(t)); + } + + public static Stream parseTransformation(String transformation, + TransformationServiceProvider transformationServiceProvider) { + String[] transformations = transformation.split("∩"); + return Stream.of(transformations).filter(t -> !t.isBlank()) + .map(t -> new ChannelStateTransformation(t, transformationServiceProvider)); + } + /** * Clear transformations */ diff --git a/bundles/org.openhab.binding.mqtt.generic/src/main/java/org/openhab/binding/mqtt/generic/internal/handler/GenericMQTTThingHandler.java b/bundles/org.openhab.binding.mqtt.generic/src/main/java/org/openhab/binding/mqtt/generic/internal/handler/GenericMQTTThingHandler.java index 0baa72040..23e6c67ee 100644 --- a/bundles/org.openhab.binding.mqtt.generic/src/main/java/org/openhab/binding/mqtt/generic/internal/handler/GenericMQTTThingHandler.java +++ b/bundles/org.openhab.binding.mqtt.generic/src/main/java/org/openhab/binding/mqtt/generic/internal/handler/GenericMQTTThingHandler.java @@ -19,15 +19,12 @@ import java.util.Map; import java.util.Optional; import java.util.concurrent.CompletableFuture; import java.util.stream.Collectors; -import java.util.stream.Stream; -import org.apache.commons.lang3.StringUtils; import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; import org.openhab.binding.mqtt.generic.AbstractMQTTThingHandler; import org.openhab.binding.mqtt.generic.ChannelConfig; import org.openhab.binding.mqtt.generic.ChannelState; -import org.openhab.binding.mqtt.generic.ChannelStateTransformation; import org.openhab.binding.mqtt.generic.ChannelStateUpdateListener; import org.openhab.binding.mqtt.generic.MqttChannelStateDescriptionProvider; import org.openhab.binding.mqtt.generic.TransformationServiceProvider; @@ -126,19 +123,11 @@ public class GenericMQTTThingHandler extends AbstractMQTTThingHandler implements */ protected ChannelState createChannelState(ChannelConfig channelConfig, ChannelUID channelUID, Value valueState) { ChannelState state = new ChannelState(channelConfig, channelUID, valueState, this); - String[] transformations; // Incoming value transformations - transformations = channelConfig.transformationPattern.split("∩"); - Stream.of(transformations).filter(StringUtils::isNotBlank) - .map(t -> new ChannelStateTransformation(t, transformationServiceProvider)) - .forEach(t -> state.addTransformation(t)); - + state.addTransformation(channelConfig.transformationPattern, transformationServiceProvider); // Outgoing value transformations - transformations = channelConfig.transformationPatternOut.split("∩"); - Stream.of(transformations).filter(StringUtils::isNotBlank) - .map(t -> new ChannelStateTransformation(t, transformationServiceProvider)) - .forEach(t -> state.addTransformationOut(t)); + state.addTransformationOut(channelConfig.transformationPatternOut, transformationServiceProvider); return state; } @@ -195,7 +184,8 @@ public class GenericMQTTThingHandler extends AbstractMQTTThingHandler implements String availabilityTopic = config.availabilityTopic; if (availabilityTopic != null) { - addAvailabilityTopic(availabilityTopic, config.payloadAvailable, config.payloadNotAvailable); + addAvailabilityTopic(availabilityTopic, config.payloadAvailable, config.payloadNotAvailable, + config.transformationPattern, transformationServiceProvider); } else { clearAllAvailabilityTopics(); } diff --git a/bundles/org.openhab.binding.mqtt.generic/src/main/java/org/openhab/binding/mqtt/generic/internal/handler/GenericThingConfiguration.java b/bundles/org.openhab.binding.mqtt.generic/src/main/java/org/openhab/binding/mqtt/generic/internal/handler/GenericThingConfiguration.java index a8b3a67e4..16d06a956 100644 --- a/bundles/org.openhab.binding.mqtt.generic/src/main/java/org/openhab/binding/mqtt/generic/internal/handler/GenericThingConfiguration.java +++ b/bundles/org.openhab.binding.mqtt.generic/src/main/java/org/openhab/binding/mqtt/generic/internal/handler/GenericThingConfiguration.java @@ -38,4 +38,9 @@ public class GenericThingConfiguration { * payload for the availability topic when the device is *not* available. */ public String payloadNotAvailable = OnOffType.OFF.toString(); + + /** + * transformation pattern for the availability payload + */ + public @Nullable String transformationPattern; } diff --git a/bundles/org.openhab.binding.mqtt.generic/src/main/resources/OH-INF/thing/generic-thing.xml b/bundles/org.openhab.binding.mqtt.generic/src/main/resources/OH-INF/thing/generic-thing.xml index edba18012..3b5c731b5 100644 --- a/bundles/org.openhab.binding.mqtt.generic/src/main/resources/OH-INF/thing/generic-thing.xml +++ b/bundles/org.openhab.binding.mqtt.generic/src/main/resources/OH-INF/thing/generic-thing.xml @@ -30,6 +30,19 @@ Payload of the 'Availability Topic', when the device is *not* available. Default: 'OFF' true + + + + + + true +