[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 <jcode@tanagra.id.au>
This commit is contained in:
parent
85ffbe37db
commit
a3bd8caba9
|
@ -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.
|
* __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`.
|
* __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`.
|
* __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
|
## Supported Channels
|
||||||
|
|
||||||
|
|
|
@ -289,6 +289,12 @@ public abstract class AbstractMQTTThingHandler extends BaseThingHandler
|
||||||
@Override
|
@Override
|
||||||
public void addAvailabilityTopic(String availability_topic, String payload_available,
|
public void addAvailabilityTopic(String availability_topic, String payload_available,
|
||||||
String payload_not_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 -> {
|
availabilityStates.computeIfAbsent(availability_topic, topic -> {
|
||||||
Value value = new OnOffValue(payload_available, payload_not_available);
|
Value value = new OnOffValue(payload_available, payload_not_available);
|
||||||
ChannelGroupUID groupUID = new ChannelGroupUID(getThing().getUID(), "availablility");
|
ChannelGroupUID groupUID = new ChannelGroupUID(getThing().getUID(), "availablility");
|
||||||
|
@ -308,6 +314,9 @@ public abstract class AbstractMQTTThingHandler extends BaseThingHandler
|
||||||
public void postChannelCommand(ChannelUID channelUID, Command value) {
|
public void postChannelCommand(ChannelUID channelUID, Command value) {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
if (transformation_pattern != null && transformationServiceProvider != null) {
|
||||||
|
state.addTransformation(transformation_pattern, transformationServiceProvider);
|
||||||
|
}
|
||||||
MqttBrokerConnection connection = getConnection();
|
MqttBrokerConnection connection = getConnection();
|
||||||
if (connection != null) {
|
if (connection != null) {
|
||||||
state.start(connection, scheduler, 0);
|
state.start(connection, scheduler, 0);
|
||||||
|
|
|
@ -20,6 +20,7 @@ import java.util.concurrent.CompletableFuture;
|
||||||
import java.util.concurrent.ScheduledExecutorService;
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
import java.util.concurrent.ScheduledFuture;
|
import java.util.concurrent.ScheduledFuture;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
import org.eclipse.jdt.annotation.Nullable;
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
|
@ -94,6 +95,10 @@ public class ChannelState implements MqttMessageSubscriber {
|
||||||
transformationsIn.add(transformation);
|
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.
|
* Add a transformation that is applied for each value to be published.
|
||||||
* The transformations are executed in order.
|
* The transformations are executed in order.
|
||||||
|
@ -104,6 +109,18 @@ public class ChannelState implements MqttMessageSubscriber {
|
||||||
transformationsOut.add(transformation);
|
transformationsOut.add(transformation);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void addTransformationOut(String transformation,
|
||||||
|
TransformationServiceProvider transformationServiceProvider) {
|
||||||
|
parseTransformation(transformation, transformationServiceProvider).forEach(t -> addTransformationOut(t));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Stream<ChannelStateTransformation> 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
|
* Clear transformations
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -19,15 +19,12 @@ import java.util.Map;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
import java.util.stream.Collectors;
|
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.NonNullByDefault;
|
||||||
import org.eclipse.jdt.annotation.Nullable;
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
import org.openhab.binding.mqtt.generic.AbstractMQTTThingHandler;
|
import org.openhab.binding.mqtt.generic.AbstractMQTTThingHandler;
|
||||||
import org.openhab.binding.mqtt.generic.ChannelConfig;
|
import org.openhab.binding.mqtt.generic.ChannelConfig;
|
||||||
import org.openhab.binding.mqtt.generic.ChannelState;
|
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.ChannelStateUpdateListener;
|
||||||
import org.openhab.binding.mqtt.generic.MqttChannelStateDescriptionProvider;
|
import org.openhab.binding.mqtt.generic.MqttChannelStateDescriptionProvider;
|
||||||
import org.openhab.binding.mqtt.generic.TransformationServiceProvider;
|
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) {
|
protected ChannelState createChannelState(ChannelConfig channelConfig, ChannelUID channelUID, Value valueState) {
|
||||||
ChannelState state = new ChannelState(channelConfig, channelUID, valueState, this);
|
ChannelState state = new ChannelState(channelConfig, channelUID, valueState, this);
|
||||||
String[] transformations;
|
|
||||||
|
|
||||||
// Incoming value transformations
|
// Incoming value transformations
|
||||||
transformations = channelConfig.transformationPattern.split("∩");
|
state.addTransformation(channelConfig.transformationPattern, transformationServiceProvider);
|
||||||
Stream.of(transformations).filter(StringUtils::isNotBlank)
|
|
||||||
.map(t -> new ChannelStateTransformation(t, transformationServiceProvider))
|
|
||||||
.forEach(t -> state.addTransformation(t));
|
|
||||||
|
|
||||||
// Outgoing value transformations
|
// Outgoing value transformations
|
||||||
transformations = channelConfig.transformationPatternOut.split("∩");
|
state.addTransformationOut(channelConfig.transformationPatternOut, transformationServiceProvider);
|
||||||
Stream.of(transformations).filter(StringUtils::isNotBlank)
|
|
||||||
.map(t -> new ChannelStateTransformation(t, transformationServiceProvider))
|
|
||||||
.forEach(t -> state.addTransformationOut(t));
|
|
||||||
|
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
@ -195,7 +184,8 @@ public class GenericMQTTThingHandler extends AbstractMQTTThingHandler implements
|
||||||
String availabilityTopic = config.availabilityTopic;
|
String availabilityTopic = config.availabilityTopic;
|
||||||
|
|
||||||
if (availabilityTopic != null) {
|
if (availabilityTopic != null) {
|
||||||
addAvailabilityTopic(availabilityTopic, config.payloadAvailable, config.payloadNotAvailable);
|
addAvailabilityTopic(availabilityTopic, config.payloadAvailable, config.payloadNotAvailable,
|
||||||
|
config.transformationPattern, transformationServiceProvider);
|
||||||
} else {
|
} else {
|
||||||
clearAllAvailabilityTopics();
|
clearAllAvailabilityTopics();
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,4 +38,9 @@ public class GenericThingConfiguration {
|
||||||
* payload for the availability topic when the device is *not* available.
|
* payload for the availability topic when the device is *not* available.
|
||||||
*/
|
*/
|
||||||
public String payloadNotAvailable = OnOffType.OFF.toString();
|
public String payloadNotAvailable = OnOffType.OFF.toString();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* transformation pattern for the availability payload
|
||||||
|
*/
|
||||||
|
public @Nullable String transformationPattern;
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,19 @@
|
||||||
<description>Payload of the 'Availability Topic', when the device is *not* available. Default: 'OFF'</description>
|
<description>Payload of the 'Availability Topic', when the device is *not* available. Default: 'OFF'</description>
|
||||||
<advanced>true</advanced>
|
<advanced>true</advanced>
|
||||||
</parameter>
|
</parameter>
|
||||||
|
<parameter name="transformationPattern" type="text">
|
||||||
|
<label>Availability Payload Transformations</label>
|
||||||
|
<description>
|
||||||
|
<![CDATA[
|
||||||
|
Applies transformations to the incoming availability payload.
|
||||||
|
A transformation example for a received JSON would be "JSONPATH:$.status" for
|
||||||
|
a json {status: "Online"}.
|
||||||
|
|
||||||
|
You can chain transformations by separating them with the intersection character ∩.
|
||||||
|
]]>
|
||||||
|
</description>
|
||||||
|
<advanced>true</advanced>
|
||||||
|
</parameter>
|
||||||
</config-description>
|
</config-description>
|
||||||
</thing-type>
|
</thing-type>
|
||||||
</thing:thing-descriptions>
|
</thing:thing-descriptions>
|
||||||
|
|
Loading…
Reference in New Issue