mirror of
https://github.com/openhab/openhab-addons.git
synced 2025-01-25 14:55:55 +01:00
[mqtt.homeassistant] support availability_templates (#13397)
Signed-off-by: Cody Cutrer <cody@cutrer.us>
This commit is contained in:
parent
b6ddb6bb0a
commit
8656ba501a
@ -291,12 +291,13 @@ public abstract class AbstractMQTTThingHandler extends BaseThingHandler
|
||||
addAvailabilityTopic(availability_topic, payload_available, payload_not_available, null, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
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");
|
||||
ChannelGroupUID groupUID = new ChannelGroupUID(getThing().getUID(), "availability");
|
||||
ChannelUID channelUID = new ChannelUID(groupUID, UIDUtils.encode(topic));
|
||||
ChannelState state = new ChannelState(ChannelConfigBuilder.create().withStateTopic(topic).build(),
|
||||
channelUID, value, new ChannelStateUpdateListener() {
|
||||
|
@ -13,6 +13,7 @@
|
||||
package org.openhab.binding.mqtt.generic;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* Interface to keep track of the availability of device using an availability topic or messages received
|
||||
@ -33,6 +34,23 @@ public interface AvailabilityTracker {
|
||||
*/
|
||||
public void addAvailabilityTopic(String availability_topic, String payload_available, String payload_not_available);
|
||||
|
||||
/**
|
||||
* Adds an availability topic to determine the availability of a device.
|
||||
* <p>
|
||||
* Availability topics are usually set by the device as LWT.
|
||||
*
|
||||
* @param availability_topic The MQTT topic where availability is published to.
|
||||
* @param payload_available The value for the topic to indicate the device is online.
|
||||
* @param payload_not_available The value for the topic to indicate the device is offline.
|
||||
* @param transformation_pattern A transformation pattern to process the value before comparing to
|
||||
* payload_available/payload_not_available.
|
||||
* @param transformationServiceProvider The service provider to obtain the transformation service (required only if
|
||||
* transformation_pattern is not null).
|
||||
*/
|
||||
public void addAvailabilityTopic(String availability_topic, String payload_available, String payload_not_available,
|
||||
@Nullable String transformation_pattern,
|
||||
@Nullable TransformationServiceProvider transformationServiceProvider);
|
||||
|
||||
public void removeAvailabilityTopic(String availability_topic);
|
||||
|
||||
public void clearAllAvailabilityTopics();
|
||||
|
@ -48,6 +48,8 @@ import org.openhab.core.thing.type.ChannelGroupTypeUID;
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public abstract class AbstractComponent<C extends AbstractChannelConfiguration> {
|
||||
private static final String JINJA_PREFIX = "JINJA:";
|
||||
|
||||
// Component location fields
|
||||
private final ComponentConfiguration componentConfiguration;
|
||||
protected final ChannelGroupTypeUID channelGroupTypeUID;
|
||||
@ -88,9 +90,13 @@ public abstract class AbstractComponent<C extends AbstractChannelConfiguration>
|
||||
|
||||
String availabilityTopic = this.channelConfiguration.getAvailabilityTopic();
|
||||
if (availabilityTopic != null) {
|
||||
String availabilityTemplate = this.channelConfiguration.getAvailabilityTemplate();
|
||||
if (availabilityTemplate != null) {
|
||||
availabilityTemplate = JINJA_PREFIX + availabilityTemplate;
|
||||
}
|
||||
componentConfiguration.getTracker().addAvailabilityTopic(availabilityTopic,
|
||||
this.channelConfiguration.getPayloadAvailable(),
|
||||
this.channelConfiguration.getPayloadNotAvailable());
|
||||
this.channelConfiguration.getPayloadAvailable(), this.channelConfiguration.getPayloadNotAvailable(),
|
||||
availabilityTemplate, componentConfiguration.getTransformationServiceProvider());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -52,6 +52,8 @@ public abstract class AbstractChannelConfiguration {
|
||||
protected String payloadAvailable = "online";
|
||||
@SerializedName("payload_not_available")
|
||||
protected String payloadNotAvailable = "offline";
|
||||
@SerializedName("availability_template")
|
||||
protected @Nullable String availabilityTemplate;
|
||||
|
||||
/**
|
||||
* A list of MQTT topics subscribed to receive availability (online/offline) updates. Must not be used together with
|
||||
@ -161,6 +163,11 @@ public abstract class AbstractChannelConfiguration {
|
||||
return payloadNotAvailable;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getAvailabilityTemplate() {
|
||||
return availabilityTemplate;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Device getDevice() {
|
||||
return device;
|
||||
|
@ -12,6 +12,8 @@
|
||||
*/
|
||||
package org.openhab.binding.mqtt.homeassistant.internal.config.dto;
|
||||
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
/**
|
||||
@ -25,6 +27,8 @@ public class Availability {
|
||||
protected String payloadAvailable = "online";
|
||||
@SerializedName("payload_not_available")
|
||||
protected String payloadNotAvailable = "offline";
|
||||
@SerializedName("value_template")
|
||||
protected @Nullable String valueTemplate;
|
||||
protected String topic;
|
||||
|
||||
public String getPayloadAvailable() {
|
||||
@ -38,4 +42,8 @@ public class Availability {
|
||||
public String getTopic() {
|
||||
return topic;
|
||||
}
|
||||
|
||||
public @Nullable String getValueTemplate() {
|
||||
return valueTemplate;
|
||||
}
|
||||
}
|
||||
|
@ -15,9 +15,11 @@ package org.openhab.binding.mqtt.homeassistant.internal.component;
|
||||
import static org.hamcrest.CoreMatchers.instanceOf;
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyBoolean;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.doAnswer;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.times;
|
||||
@ -47,6 +49,7 @@ import org.openhab.binding.mqtt.homeassistant.internal.HandlerConfiguration;
|
||||
import org.openhab.binding.mqtt.homeassistant.internal.config.dto.AbstractChannelConfiguration;
|
||||
import org.openhab.binding.mqtt.homeassistant.internal.handler.HomeAssistantThingHandler;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingStatusInfo;
|
||||
import org.openhab.core.thing.binding.ThingHandlerCallback;
|
||||
import org.openhab.core.types.State;
|
||||
|
||||
@ -71,6 +74,12 @@ public abstract class AbstractComponentTests extends AbstractHomeAssistantTests
|
||||
config.put(HandlerConfiguration.PROPERTY_BASETOPIC, HandlerConfiguration.DEFAULT_BASETOPIC);
|
||||
config.put(HandlerConfiguration.PROPERTY_TOPICS, getConfigTopics());
|
||||
|
||||
// Plumb thing status updates through
|
||||
doAnswer(invocation -> {
|
||||
((Thing) invocation.getArgument(0)).setStatusInfo((ThingStatusInfo) invocation.getArgument(1));
|
||||
return null;
|
||||
}).when(callbackMock).statusUpdated(any(Thing.class), any(ThingStatusInfo.class));
|
||||
|
||||
when(callbackMock.getBridge(eq(BRIDGE_UID))).thenReturn(bridgeThing);
|
||||
|
||||
thingHandler = new LatchThingHandler(haThing, channelTypeProvider, transformationServiceProvider,
|
||||
|
@ -23,6 +23,7 @@ import org.openhab.binding.mqtt.generic.values.NumberValue;
|
||||
import org.openhab.binding.mqtt.generic.values.TextValue;
|
||||
import org.openhab.core.library.types.QuantityType;
|
||||
import org.openhab.core.library.unit.Units;
|
||||
import org.openhab.core.thing.ThingStatus;
|
||||
import org.openhab.core.types.UnDefType;
|
||||
|
||||
/**
|
||||
@ -40,11 +41,8 @@ public class SensorTests extends AbstractComponentTests {
|
||||
// @formatter:off
|
||||
var component = discoverComponent(configTopicToMqtt(CONFIG_TOPIC),
|
||||
"{ " +
|
||||
" \"availability\": [ " +
|
||||
" { " +
|
||||
" \"topic\": \"zigbee2mqtt/bridge/state\" " +
|
||||
" } " +
|
||||
" ], " +
|
||||
" \"availability_topic\": \"zigbee2mqtt/bridge/state\", " +
|
||||
" \"availability_template\": \"{{value_json.state}}\", " +
|
||||
" \"device\": { " +
|
||||
" \"identifiers\": [ " +
|
||||
" \"zigbee2mqtt_0x0000000000000000\" " +
|
||||
@ -70,6 +68,8 @@ public class SensorTests extends AbstractComponentTests {
|
||||
assertChannel(component, Sensor.SENSOR_CHANNEL_ID, "zigbee2mqtt/sensor/state", "", "sensor1",
|
||||
NumberValue.class);
|
||||
|
||||
publishMessage("zigbee2mqtt/bridge/state", "{ \"state\": \"online\" }");
|
||||
assertThat(haThing.getStatus(), is(ThingStatus.ONLINE));
|
||||
publishMessage("zigbee2mqtt/sensor/state", "10");
|
||||
assertState(component, Sensor.SENSOR_CHANNEL_ID, new QuantityType<>(10, Units.WATT));
|
||||
publishMessage("zigbee2mqtt/sensor/state", "20");
|
||||
@ -77,7 +77,10 @@ public class SensorTests extends AbstractComponentTests {
|
||||
assertThat(component.getChannel(Sensor.SENSOR_CHANNEL_ID).getState().getCache().createStateDescription(true)
|
||||
.build().getPattern(), is("%s %unit%"));
|
||||
|
||||
waitForAssert(() -> assertState(component, Sensor.SENSOR_CHANNEL_ID, UnDefType.UNDEF), 10000, 200);
|
||||
waitForAssert(() -> assertState(component, Sensor.SENSOR_CHANNEL_ID, UnDefType.UNDEF), 5000, 200);
|
||||
|
||||
publishMessage("zigbee2mqtt/bridge/state", "{ \"state\": \"offline\" }");
|
||||
assertThat(haThing.getStatus(), is(ThingStatus.OFFLINE));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
Loading…
Reference in New Issue
Block a user