mirror of
https://github.com/openhab/openhab-addons.git
synced 2025-01-10 15:11:59 +01:00
[mqtt.homeassistant] Make sensors compliant (#8591)
Signed-off-by: Jochen Klein <git@jochen.susca.de>
This commit is contained in:
parent
3abe27b224
commit
f06068a189
@ -15,6 +15,7 @@ package org.openhab.binding.mqtt.generic;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
@ -355,16 +356,16 @@ public abstract class AbstractMQTTThingHandler extends BaseThingHandler
|
||||
}
|
||||
|
||||
protected void calculateThingStatus() {
|
||||
final boolean availabilityTopicsSeen;
|
||||
final Optional<Boolean> availabilityTopicsSeen;
|
||||
|
||||
if (availabilityStates.isEmpty()) {
|
||||
availabilityTopicsSeen = true;
|
||||
availabilityTopicsSeen = Optional.empty();
|
||||
} else {
|
||||
availabilityTopicsSeen = availabilityStates.values().stream().allMatch(
|
||||
c -> c != null && OnOffType.ON.equals(c.getCache().getChannelState().as(OnOffType.class)));
|
||||
availabilityTopicsSeen = Optional.of(availabilityStates.values().stream().allMatch(
|
||||
c -> c != null && OnOffType.ON.equals(c.getCache().getChannelState().as(OnOffType.class))));
|
||||
}
|
||||
updateThingStatus(messageReceived.get(), availabilityTopicsSeen);
|
||||
}
|
||||
|
||||
protected abstract void updateThingStatus(boolean messageReceived, boolean availabilityTopicsSeen);
|
||||
protected abstract void updateThingStatus(boolean messageReceived, Optional<Boolean> availabilityTopicsSeen);
|
||||
}
|
||||
|
@ -16,6 +16,7 @@ import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
@ -186,8 +187,8 @@ public class GenericMQTTThingHandler extends AbstractMQTTThingHandler implements
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateThingStatus(boolean messageReceived, boolean availibilityTopicsSeen) {
|
||||
if (messageReceived || availibilityTopicsSeen) {
|
||||
protected void updateThingStatus(boolean messageReceived, Optional<Boolean> availibilityTopicsSeen) {
|
||||
if (availibilityTopicsSeen.orElse(true)) {
|
||||
updateStatus(ThingStatus.ONLINE, ThingStatusDetail.NONE);
|
||||
} else {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.NONE);
|
||||
|
@ -12,6 +12,8 @@
|
||||
*/
|
||||
package org.openhab.binding.mqtt.homeassistant.internal;
|
||||
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.mqtt.generic.AvailabilityTracker;
|
||||
@ -46,9 +48,10 @@ public class CFactory {
|
||||
*/
|
||||
public static @Nullable AbstractComponent<?> createComponent(ThingUID thingUID, HaID haID,
|
||||
String channelConfigurationJSON, ChannelStateUpdateListener updateListener, AvailabilityTracker tracker,
|
||||
Gson gson, TransformationServiceProvider transformationServiceProvider) {
|
||||
ScheduledExecutorService scheduler, Gson gson,
|
||||
TransformationServiceProvider transformationServiceProvider) {
|
||||
ComponentConfiguration componentConfiguration = new ComponentConfiguration(thingUID, haID,
|
||||
channelConfigurationJSON, gson, updateListener, tracker)
|
||||
channelConfigurationJSON, gson, updateListener, tracker, scheduler)
|
||||
.transformationProvider(transformationServiceProvider);
|
||||
try {
|
||||
switch (haID.component) {
|
||||
@ -86,16 +89,19 @@ public class CFactory {
|
||||
private final ChannelStateUpdateListener updateListener;
|
||||
private final AvailabilityTracker tracker;
|
||||
private final Gson gson;
|
||||
private final ScheduledExecutorService scheduler;
|
||||
private @Nullable TransformationServiceProvider transformationServiceProvider;
|
||||
|
||||
protected ComponentConfiguration(ThingUID thingUID, HaID haID, String configJSON, Gson gson,
|
||||
ChannelStateUpdateListener updateListener, AvailabilityTracker tracker) {
|
||||
ChannelStateUpdateListener updateListener, AvailabilityTracker tracker,
|
||||
ScheduledExecutorService scheduler) {
|
||||
this.thingUID = thingUID;
|
||||
this.haID = haID;
|
||||
this.configJSON = configJSON;
|
||||
this.gson = gson;
|
||||
this.updateListener = updateListener;
|
||||
this.tracker = tracker;
|
||||
this.scheduler = scheduler;
|
||||
}
|
||||
|
||||
public ComponentConfiguration transformationProvider(
|
||||
@ -133,6 +139,10 @@ public class CFactory {
|
||||
return tracker;
|
||||
}
|
||||
|
||||
public ScheduledExecutorService getScheduler() {
|
||||
return scheduler;
|
||||
}
|
||||
|
||||
public <C extends BaseChannelConfiguration> C getConfig(Class<C> clazz) {
|
||||
return BaseChannelConfiguration.fromString(configJSON, gson, clazz);
|
||||
}
|
||||
|
@ -69,19 +69,16 @@ public class ComponentAlarmControlPanel extends AbstractComponent<ComponentAlarm
|
||||
String command_topic = channelConfiguration.command_topic;
|
||||
if (command_topic != null) {
|
||||
buildChannel(switchDisarmChannelID, new TextValue(new String[] { channelConfiguration.payload_disarm }),
|
||||
channelConfiguration.name, componentConfiguration.getUpdateListener())//
|
||||
.commandTopic(command_topic, channelConfiguration.retain)//
|
||||
.build();
|
||||
channelConfiguration.name, componentConfiguration.getUpdateListener())
|
||||
.commandTopic(command_topic, channelConfiguration.retain).build();
|
||||
|
||||
buildChannel(switchArmHomeChannelID, new TextValue(new String[] { channelConfiguration.payload_arm_home }),
|
||||
channelConfiguration.name, componentConfiguration.getUpdateListener())//
|
||||
.commandTopic(command_topic, channelConfiguration.retain)//
|
||||
.build();
|
||||
channelConfiguration.name, componentConfiguration.getUpdateListener())
|
||||
.commandTopic(command_topic, channelConfiguration.retain).build();
|
||||
|
||||
buildChannel(switchArmAwayChannelID, new TextValue(new String[] { channelConfiguration.payload_arm_away }),
|
||||
channelConfiguration.name, componentConfiguration.getUpdateListener())//
|
||||
.commandTopic(command_topic, channelConfiguration.retain)//
|
||||
.build();
|
||||
channelConfiguration.name, componentConfiguration.getUpdateListener())
|
||||
.commandTopic(command_topic, channelConfiguration.retain).build();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -12,9 +12,15 @@
|
||||
*/
|
||||
package org.openhab.binding.mqtt.homeassistant.internal;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.mqtt.generic.ChannelStateUpdateListener;
|
||||
import org.openhab.binding.mqtt.generic.values.OnOffValue;
|
||||
import org.openhab.binding.mqtt.generic.values.Value;
|
||||
import org.openhab.binding.mqtt.homeassistant.internal.listener.ExpireUpdateStateListener;
|
||||
import org.openhab.binding.mqtt.homeassistant.internal.listener.OffDelayUpdateStateListener;
|
||||
|
||||
/**
|
||||
* A MQTT BinarySensor, following the https://www.home-assistant.io/components/binary_sensor.mqtt/ specification.
|
||||
@ -35,23 +41,40 @@ public class ComponentBinarySensor extends AbstractComponent<ComponentBinarySens
|
||||
|
||||
protected @Nullable String device_class;
|
||||
protected boolean force_update = false;
|
||||
protected int expire_after = 0;
|
||||
protected @Nullable Integer expire_after;
|
||||
protected @Nullable Integer off_delay;
|
||||
|
||||
protected String state_topic = "";
|
||||
protected String payload_on = "ON";
|
||||
protected String payload_off = "OFF";
|
||||
|
||||
protected @Nullable String json_attributes_topic;
|
||||
protected @Nullable String json_attributes_template;
|
||||
protected @Nullable List<String> json_attributes;
|
||||
}
|
||||
|
||||
public ComponentBinarySensor(CFactory.ComponentConfiguration componentConfiguration) {
|
||||
super(componentConfiguration, ChannelConfiguration.class);
|
||||
|
||||
if (channelConfiguration.force_update) {
|
||||
throw new UnsupportedOperationException("Component:Sensor does not support forced updates");
|
||||
OnOffValue value = new OnOffValue(channelConfiguration.payload_on, channelConfiguration.payload_off);
|
||||
|
||||
buildChannel(sensorChannelID, value, "value", getListener(componentConfiguration, value))
|
||||
.stateTopic(channelConfiguration.state_topic, channelConfiguration.value_template).build();
|
||||
}
|
||||
|
||||
private ChannelStateUpdateListener getListener(CFactory.ComponentConfiguration componentConfiguration,
|
||||
Value value) {
|
||||
ChannelStateUpdateListener updateListener = componentConfiguration.getUpdateListener();
|
||||
|
||||
if (channelConfiguration.expire_after != null) {
|
||||
updateListener = new ExpireUpdateStateListener(updateListener, channelConfiguration.expire_after, value,
|
||||
componentConfiguration.getTracker(), componentConfiguration.getScheduler());
|
||||
}
|
||||
if (channelConfiguration.off_delay != null) {
|
||||
updateListener = new OffDelayUpdateStateListener(updateListener, channelConfiguration.off_delay, value,
|
||||
componentConfiguration.getScheduler());
|
||||
}
|
||||
|
||||
buildChannel(sensorChannelID, new OnOffValue(channelConfiguration.payload_on, channelConfiguration.payload_off),
|
||||
channelConfiguration.name, componentConfiguration.getUpdateListener())//
|
||||
.stateTopic(channelConfiguration.state_topic, channelConfiguration.value_template)//
|
||||
.build();
|
||||
return updateListener;
|
||||
}
|
||||
}
|
||||
|
@ -42,8 +42,7 @@ public class ComponentCamera extends AbstractComponent<ComponentCamera.ChannelCo
|
||||
|
||||
ImageValue value = new ImageValue();
|
||||
|
||||
buildChannel(cameraChannelID, value, channelConfiguration.name, componentConfiguration.getUpdateListener())//
|
||||
.stateTopic(channelConfiguration.topic)//
|
||||
.build();
|
||||
buildChannel(cameraChannelID, value, channelConfiguration.name, componentConfiguration.getUpdateListener())
|
||||
.stateTopic(channelConfiguration.topic).build();
|
||||
}
|
||||
}
|
||||
|
@ -48,9 +48,8 @@ public class ComponentCover extends AbstractComponent<ComponentCover.ChannelConf
|
||||
RollershutterValue value = new RollershutterValue(channelConfiguration.payload_open,
|
||||
channelConfiguration.payload_close, channelConfiguration.payload_stop);
|
||||
|
||||
buildChannel(switchChannelID, value, channelConfiguration.name, componentConfiguration.getUpdateListener())//
|
||||
.stateTopic(channelConfiguration.state_topic, channelConfiguration.value_template)//
|
||||
.commandTopic(channelConfiguration.command_topic, channelConfiguration.retain)//
|
||||
.build();
|
||||
buildChannel(switchChannelID, value, channelConfiguration.name, componentConfiguration.getUpdateListener())
|
||||
.stateTopic(channelConfiguration.state_topic, channelConfiguration.value_template)
|
||||
.commandTopic(channelConfiguration.command_topic, channelConfiguration.retain).build();
|
||||
}
|
||||
}
|
||||
|
@ -45,9 +45,8 @@ public class ComponentFan extends AbstractComponent<ComponentFan.ChannelConfigur
|
||||
super(componentConfiguration, ChannelConfiguration.class);
|
||||
|
||||
OnOffValue value = new OnOffValue(channelConfiguration.payload_on, channelConfiguration.payload_off);
|
||||
buildChannel(switchChannelID, value, channelConfiguration.name, componentConfiguration.getUpdateListener())//
|
||||
.stateTopic(channelConfiguration.state_topic, channelConfiguration.value_template)//
|
||||
.commandTopic(channelConfiguration.command_topic, channelConfiguration.retain)//
|
||||
.build();
|
||||
buildChannel(switchChannelID, value, channelConfiguration.name, componentConfiguration.getUpdateListener())
|
||||
.stateTopic(channelConfiguration.state_topic, channelConfiguration.value_template)
|
||||
.commandTopic(channelConfiguration.command_topic, channelConfiguration.retain).build();
|
||||
}
|
||||
}
|
||||
|
@ -105,22 +105,18 @@ public class ComponentLight extends AbstractComponent<ComponentLight.ChannelConf
|
||||
channelConfiguration.payload_off, 100);
|
||||
|
||||
// Create three MQTT subscriptions and use this class object as update listener
|
||||
switchChannel = buildChannel(switchChannelID, value, channelConfiguration.name, this)//
|
||||
// Some lights use the value_template field for the template, most use state_value_template
|
||||
switchChannel = buildChannel(switchChannelID, value, channelConfiguration.name, this)
|
||||
.stateTopic(channelConfiguration.state_topic, channelConfiguration.state_value_template,
|
||||
channelConfiguration.value_template)//
|
||||
.commandTopic(channelConfiguration.command_topic, channelConfiguration.retain)//
|
||||
.build(false);
|
||||
channelConfiguration.value_template)
|
||||
.commandTopic(channelConfiguration.command_topic, channelConfiguration.retain).build(false);
|
||||
|
||||
colorChannel = buildChannel(colorChannelID, value, channelConfiguration.name, this)//
|
||||
.stateTopic(channelConfiguration.rgb_state_topic, channelConfiguration.rgb_value_template)//
|
||||
.commandTopic(channelConfiguration.rgb_command_topic, channelConfiguration.retain)//
|
||||
.build(false);
|
||||
colorChannel = buildChannel(colorChannelID, value, channelConfiguration.name, this)
|
||||
.stateTopic(channelConfiguration.rgb_state_topic, channelConfiguration.rgb_value_template)
|
||||
.commandTopic(channelConfiguration.rgb_command_topic, channelConfiguration.retain).build(false);
|
||||
|
||||
brightnessChannel = buildChannel(brightnessChannelID, value, channelConfiguration.name, this)//
|
||||
.stateTopic(channelConfiguration.brightness_state_topic, channelConfiguration.brightness_value_template)//
|
||||
.commandTopic(channelConfiguration.brightness_command_topic, channelConfiguration.retain)//
|
||||
.build(false);
|
||||
brightnessChannel = buildChannel(brightnessChannelID, value, channelConfiguration.name, this)
|
||||
.stateTopic(channelConfiguration.brightness_state_topic, channelConfiguration.brightness_value_template)
|
||||
.commandTopic(channelConfiguration.brightness_command_topic, channelConfiguration.retain).build(false);
|
||||
|
||||
channels.put(colorChannelID, colorChannel);
|
||||
}
|
||||
|
@ -52,9 +52,8 @@ public class ComponentLock extends AbstractComponent<ComponentLock.ChannelConfig
|
||||
|
||||
buildChannel(switchChannelID,
|
||||
new OnOffValue(channelConfiguration.payload_lock, channelConfiguration.payload_unlock),
|
||||
channelConfiguration.name, componentConfiguration.getUpdateListener())//
|
||||
.stateTopic(channelConfiguration.state_topic, channelConfiguration.value_template)//
|
||||
.commandTopic(channelConfiguration.command_topic, channelConfiguration.retain)//
|
||||
.build();
|
||||
channelConfiguration.name, componentConfiguration.getUpdateListener())
|
||||
.stateTopic(channelConfiguration.state_topic, channelConfiguration.value_template)
|
||||
.commandTopic(channelConfiguration.command_topic, channelConfiguration.retain).build();
|
||||
}
|
||||
}
|
||||
|
@ -12,14 +12,17 @@
|
||||
*/
|
||||
package org.openhab.binding.mqtt.homeassistant.internal;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.mqtt.generic.ChannelStateUpdateListener;
|
||||
import org.openhab.binding.mqtt.generic.values.NumberValue;
|
||||
import org.openhab.binding.mqtt.generic.values.TextValue;
|
||||
import org.openhab.binding.mqtt.generic.values.Value;
|
||||
import org.openhab.binding.mqtt.homeassistant.internal.listener.ExpireUpdateStateListener;
|
||||
|
||||
/**
|
||||
* A MQTT sensor, following the https://www.home-assistant.io/components/sensor.mqtt/ specification.
|
||||
@ -42,18 +45,18 @@ public class ComponentSensor extends AbstractComponent<ComponentSensor.ChannelCo
|
||||
protected @Nullable String unit_of_measurement;
|
||||
protected @Nullable String device_class;
|
||||
protected boolean force_update = false;
|
||||
protected int expire_after = 0;
|
||||
protected @Nullable Integer expire_after;
|
||||
|
||||
protected String state_topic = "";
|
||||
|
||||
protected @Nullable String json_attributes_topic;
|
||||
protected @Nullable String json_attributes_template;
|
||||
protected @Nullable List<String> json_attributes;
|
||||
}
|
||||
|
||||
public ComponentSensor(CFactory.ComponentConfiguration componentConfiguration) {
|
||||
super(componentConfiguration, ChannelConfiguration.class);
|
||||
|
||||
if (channelConfiguration.force_update) {
|
||||
throw new UnsupportedOperationException("Component:Sensor does not support forced updates");
|
||||
}
|
||||
|
||||
Value value;
|
||||
|
||||
String uom = channelConfiguration.unit_of_measurement;
|
||||
@ -68,8 +71,19 @@ public class ComponentSensor extends AbstractComponent<ComponentSensor.ChannelCo
|
||||
|
||||
boolean trigger = triggerIcons.matcher(icon).matches();
|
||||
|
||||
buildChannel(sensorChannelID, value, channelConfiguration.name, componentConfiguration.getUpdateListener())//
|
||||
buildChannel(sensorChannelID, value, channelConfiguration.name, getListener(componentConfiguration, value))
|
||||
.stateTopic(channelConfiguration.state_topic, channelConfiguration.value_template)//
|
||||
.trigger(trigger).build();
|
||||
}
|
||||
|
||||
private ChannelStateUpdateListener getListener(CFactory.ComponentConfiguration componentConfiguration,
|
||||
Value value) {
|
||||
ChannelStateUpdateListener updateListener = componentConfiguration.getUpdateListener();
|
||||
|
||||
if (channelConfiguration.expire_after != null) {
|
||||
updateListener = new ExpireUpdateStateListener(updateListener, channelConfiguration.expire_after, value,
|
||||
componentConfiguration.getTracker(), componentConfiguration.getScheduler());
|
||||
}
|
||||
return updateListener;
|
||||
}
|
||||
}
|
||||
|
@ -66,9 +66,9 @@ public class ComponentSwitch extends AbstractComponent<ComponentSwitch.ChannelCo
|
||||
OnOffValue value = new OnOffValue(state_on, state_off, channelConfiguration.payload_on,
|
||||
channelConfiguration.payload_off);
|
||||
|
||||
buildChannel(switchChannelID, value, "state", componentConfiguration.getUpdateListener())//
|
||||
.stateTopic(channelConfiguration.state_topic, channelConfiguration.value_template)//
|
||||
.commandTopic(channelConfiguration.command_topic, channelConfiguration.retain, channelConfiguration.qos)//
|
||||
buildChannel(switchChannelID, value, "state", componentConfiguration.getUpdateListener())
|
||||
.stateTopic(channelConfiguration.state_topic, channelConfiguration.value_template)
|
||||
.commandTopic(channelConfiguration.command_topic, channelConfiguration.retain, channelConfiguration.qos)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
@ -96,7 +96,7 @@ public class DiscoverComponents implements MqttMessageSubscriber {
|
||||
AbstractComponent<?> component = null;
|
||||
|
||||
if (config.length() > 0) {
|
||||
component = CFactory.createComponent(thingUID, haID, config, updateListener, tracker, gson,
|
||||
component = CFactory.createComponent(thingUID, haID, config, updateListener, tracker, scheduler, gson,
|
||||
transformationServiceProvider);
|
||||
}
|
||||
if (component != null) {
|
||||
|
@ -17,6 +17,7 @@ import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.function.Consumer;
|
||||
@ -152,8 +153,8 @@ public class HomeAssistantThingHandler extends AbstractMQTTThingHandler
|
||||
if (channelConfigurationJSON == null) {
|
||||
logger.warn("Provided channel does not have a 'config' configuration key!");
|
||||
} else {
|
||||
component = CFactory.createComponent(thingUID, haID, channelConfigurationJSON, this, this, gson,
|
||||
transformationServiceProvider);
|
||||
component = CFactory.createComponent(thingUID, haID, channelConfigurationJSON, this, this, scheduler,
|
||||
gson, transformationServiceProvider);
|
||||
}
|
||||
|
||||
if (component != null) {
|
||||
@ -296,8 +297,8 @@ public class HomeAssistantThingHandler extends AbstractMQTTThingHandler
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateThingStatus(boolean messageReceived, boolean availabilityTopicsSeen) {
|
||||
if (!messageReceived || availabilityTopicsSeen) {
|
||||
protected void updateThingStatus(boolean messageReceived, Optional<Boolean> availabilityTopicsSeen) {
|
||||
if (availabilityTopicsSeen.orElse(messageReceived)) {
|
||||
updateStatus(ThingStatus.ONLINE, ThingStatusDetail.NONE);
|
||||
} else {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.NONE);
|
||||
|
@ -0,0 +1,52 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.mqtt.homeassistant.internal.listener;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNull;
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.mqtt.generic.ChannelStateUpdateListener;
|
||||
import org.openhab.core.thing.ChannelUID;
|
||||
import org.openhab.core.types.Command;
|
||||
import org.openhab.core.types.State;
|
||||
|
||||
/**
|
||||
* A proxy class for {@link ChannelStateUpdateListener} forwarding everything to the real listener.
|
||||
* <p>
|
||||
* This class is used to be able handle special cases like timeouts.
|
||||
*
|
||||
* @author Jochen Klein - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public abstract class ChannelStateUpdateListenerProxy implements ChannelStateUpdateListener {
|
||||
|
||||
private final ChannelStateUpdateListener original;
|
||||
|
||||
public ChannelStateUpdateListenerProxy(ChannelStateUpdateListener original) {
|
||||
this.original = original;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateChannelState(@NonNull ChannelUID channelUID, @NonNull State value) {
|
||||
original.updateChannelState(channelUID, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postChannelCommand(@NonNull ChannelUID channelUID, @NonNull Command value) {
|
||||
original.postChannelCommand(channelUID, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void triggerChannel(@NonNull ChannelUID channelUID, @NonNull String eventPayload) {
|
||||
original.triggerChannel(channelUID, eventPayload);
|
||||
}
|
||||
}
|
@ -0,0 +1,66 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.mqtt.homeassistant.internal.listener;
|
||||
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.mqtt.generic.AvailabilityTracker;
|
||||
import org.openhab.binding.mqtt.generic.ChannelStateUpdateListener;
|
||||
import org.openhab.binding.mqtt.generic.values.Value;
|
||||
import org.openhab.core.thing.ChannelUID;
|
||||
import org.openhab.core.types.State;
|
||||
|
||||
/**
|
||||
* A listener to reset the channel value after a timeout.
|
||||
*
|
||||
* @author Jochen Klein - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class ExpireUpdateStateListener extends ChannelStateUpdateListenerProxy {
|
||||
|
||||
private final int expireAfter;
|
||||
private final Value value;
|
||||
private final AvailabilityTracker tracker;
|
||||
private final ScheduledExecutorService scheduler;
|
||||
|
||||
private AtomicReference<@Nullable ScheduledFuture<?>> expire = new AtomicReference<>();
|
||||
|
||||
public ExpireUpdateStateListener(ChannelStateUpdateListener original, int expireAfter, Value value,
|
||||
AvailabilityTracker tracker, ScheduledExecutorService scheduler) {
|
||||
super(original);
|
||||
this.expireAfter = expireAfter;
|
||||
this.value = value;
|
||||
this.tracker = tracker;
|
||||
this.scheduler = scheduler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateChannelState(final ChannelUID channelUID, State state) {
|
||||
super.updateChannelState(channelUID, state);
|
||||
|
||||
ScheduledFuture<?> oldExpire = expire.getAndSet(scheduler.schedule(() -> {
|
||||
value.resetState();
|
||||
tracker.resetMessageReceived();
|
||||
ExpireUpdateStateListener.super.updateChannelState(channelUID, value.getChannelState());
|
||||
}, expireAfter, TimeUnit.SECONDS));
|
||||
|
||||
if (oldExpire != null) {
|
||||
oldExpire.cancel(false);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,68 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.mqtt.homeassistant.internal.listener;
|
||||
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.mqtt.generic.ChannelStateUpdateListener;
|
||||
import org.openhab.binding.mqtt.generic.values.Value;
|
||||
import org.openhab.core.library.types.OnOffType;
|
||||
import org.openhab.core.thing.ChannelUID;
|
||||
import org.openhab.core.types.State;
|
||||
|
||||
/**
|
||||
* A listener to set the binary sensor value to 'off' after a timeout.
|
||||
*
|
||||
* @author Jochen Klein - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class OffDelayUpdateStateListener extends ChannelStateUpdateListenerProxy {
|
||||
|
||||
private final int offDelay;
|
||||
private final Value value;
|
||||
private final ScheduledExecutorService scheduler;
|
||||
|
||||
private AtomicReference<@Nullable ScheduledFuture<?>> delay = new AtomicReference<>();
|
||||
|
||||
public OffDelayUpdateStateListener(ChannelStateUpdateListener original, int offDelay, Value value,
|
||||
ScheduledExecutorService scheduler) {
|
||||
super(original);
|
||||
this.offDelay = offDelay;
|
||||
this.value = value;
|
||||
this.scheduler = scheduler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateChannelState(final ChannelUID channelUID, State state) {
|
||||
super.updateChannelState(channelUID, state);
|
||||
|
||||
ScheduledFuture<?> newDelay = null;
|
||||
|
||||
if (OnOffType.ON == state) {
|
||||
newDelay = scheduler.schedule(() -> {
|
||||
value.update(OnOffType.OFF);
|
||||
OffDelayUpdateStateListener.super.updateChannelState(channelUID, value.getChannelState());
|
||||
}, offDelay, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
ScheduledFuture<?> oldDelay = delay.getAndSet(newDelay);
|
||||
if (oldDelay != null) {
|
||||
oldDelay.cancel(false);
|
||||
}
|
||||
}
|
||||
}
|
@ -13,6 +13,7 @@
|
||||
package org.openhab.binding.mqtt.homie.internal.handler;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.function.Consumer;
|
||||
@ -246,7 +247,7 @@ public class HomieThingHandler extends AbstractMQTTThingHandler implements Devic
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateThingStatus(boolean messageReceived, boolean availabilityTopicsSeen) {
|
||||
protected void updateThingStatus(boolean messageReceived, Optional<Boolean> availabilityTopicsSeen) {
|
||||
// not used here
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user