Skip to content

Commit

Permalink
[mqtt-homeassistant] climate.mqtt support (openhab#10690)
Browse files Browse the repository at this point in the history
* MQTT.Homeassistant Climate support

Signed-off-by: Anton Kharuzhy <[email protected]>

* MQTT.Homeassistant synthetic config test added

Signed-off-by: Anton Kharuzhy <[email protected]>

* MQTT.Homeassistant refactoring

Signed-off-by: Anton Kharuzhy <[email protected]>

* MQTT.Homeassistant discovery test added

Signed-off-by: Anton Kharuzhy <[email protected]>

* MQTT.Homeassistant thing handler test added

Signed-off-by: Anton Kharuzhy <[email protected]>

* MQTT.Homeassistant switch test added

Signed-off-by: Anton Kharuzhy <[email protected]>

* MQTT.Homeassistant Climate test added

Signed-off-by: Anton Kharuzhy <[email protected]>

* MQTT.Homeassistant author header added

Signed-off-by: Anton Kharuzhy <[email protected]>

* MQTT.Homeassistant copyright header added

Signed-off-by: Anton Kharuzhy <[email protected]>

* MQTT.Homeassistant test fixed

Signed-off-by: Anton Kharuzhy <[email protected]>

* MQTT.Homeassistant test fixed

Signed-off-by: Anton Kharuzhy <[email protected]>

* MQTT.Homeassistant test infrastructure updated. Added tests with mqtt publishing and commands posting.

Signed-off-by: Anton Kharuzhy <[email protected]>

* MQTT.Homeassistant fixed Climate#send_if_off handling

Signed-off-by: Anton Kharuzhy <[email protected]>

* MQTT.Homeassistant do not filter the power command

Signed-off-by: Anton Kharuzhy <[email protected]>

* MQTT.Homeassistant climate unit test added

Signed-off-by: Anton Kharuzhy <[email protected]>

* Update bundles/org.openhab.binding.mqtt.homeassistant/src/main/java/org/openhab/binding/mqtt/homeassistant/internal/DiscoverComponents.java

Redundant annotation removed

Co-authored-by: Fabian Wolter <[email protected]>

* MQTT.Homeassistant Redundant @nullable annotations removed

Signed-off-by: Anton Kharuzhy <[email protected]>

* MQTT.Homeassistant Unit tests added for all components

Signed-off-by: Anton Kharuzhy <[email protected]>

* MQTT.Homeassistant Unit tests stability fix

Signed-off-by: Anton Kharuzhy <[email protected]>

* MQTT.Homeassistant @NonNullByDefault removed from Device, config.dto package created

Signed-off-by: Anton Kharuzhy <[email protected]>

* MQTT.Homeassistant Climate author added

Signed-off-by: Anton Kharuzhy <[email protected]>

* MQTT.Homeassistant Device.sw_version renamed

Signed-off-by: Anton Kharuzhy <[email protected]>

* MQTT.Homeassistant tests wait timeout increased to 10s

Signed-off-by: Anton Kharuzhy <[email protected]>

Co-authored-by: antroids <[email protected]>
Co-authored-by: Fabian Wolter <[email protected]>
Signed-off-by: Dave J Schoepel <[email protected]>
  • Loading branch information
3 people authored and dschoepel committed Nov 9, 2021
1 parent 81aeba8 commit 357dbec
Show file tree
Hide file tree
Showing 56 changed files with 3,236 additions and 466 deletions.
7 changes: 7 additions & 0 deletions bundles/org.openhab.binding.mqtt.homeassistant/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,12 @@
<version>${project.version}</version>
<scope>provided</scope>
</dependency>

<dependency>
<groupId>org.openhab.addons.bundles</groupId>
<artifactId>org.openhab.transform.jinja</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import java.net.URI;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ScheduledExecutorService;
import java.util.function.Predicate;

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
Expand All @@ -26,7 +27,7 @@
import org.openhab.binding.mqtt.generic.TransformationServiceProvider;
import org.openhab.binding.mqtt.generic.values.Value;
import org.openhab.binding.mqtt.homeassistant.generic.internal.MqttBindingConstants;
import org.openhab.binding.mqtt.homeassistant.internal.CFactory.ComponentConfiguration;
import org.openhab.binding.mqtt.homeassistant.internal.component.AbstractComponent;
import org.openhab.core.config.core.Configuration;
import org.openhab.core.io.transport.mqtt.MqttBrokerConnection;
import org.openhab.core.thing.Channel;
Expand All @@ -37,6 +38,7 @@
import org.openhab.core.thing.type.ChannelType;
import org.openhab.core.thing.type.ChannelTypeBuilder;
import org.openhab.core.thing.type.ChannelTypeUID;
import org.openhab.core.types.Command;
import org.openhab.core.types.StateDescriptionFragment;

/**
Expand All @@ -55,7 +57,7 @@
* @author David Graeff - Initial contribution
*/
@NonNullByDefault
public class CChannel {
public class ComponentChannel {
private static final String JINJA = "JINJA";

private final ChannelUID channelUID;
Expand All @@ -65,7 +67,7 @@ public class CChannel {
private final ChannelTypeUID channelTypeUID;
private final ChannelStateUpdateListener channelStateUpdateListener;

private CChannel(ChannelUID channelUID, ChannelState channelState, Channel channel, ChannelType type,
private ComponentChannel(ChannelUID channelUID, ChannelState channelState, Channel channel, ChannelType type,
ChannelTypeUID channelTypeUID, ChannelStateUpdateListener channelStateUpdateListener) {
super();
this.channelUID = channelUID;
Expand Down Expand Up @@ -117,24 +119,25 @@ public void resetState() {
}

public static class Builder {
private AbstractComponent<?> component;
private ComponentConfiguration componentConfiguration;
private String channelID;
private Value valueState;
private String label;
private final AbstractComponent<?> component;
private final String channelID;
private final Value valueState;
private final String label;
private final ChannelStateUpdateListener channelStateUpdateListener;

private @Nullable String state_topic;
private @Nullable String command_topic;
private boolean retain;
private boolean trigger;
private @Nullable Integer qos;
private ChannelStateUpdateListener channelStateUpdateListener;
private @Nullable Predicate<Command> commandFilter;

private @Nullable String templateIn;
private @Nullable String templateOut;

public Builder(AbstractComponent<?> component, ComponentConfiguration componentConfiguration, String channelID,
Value valueState, String label, ChannelStateUpdateListener channelStateUpdateListener) {
public Builder(AbstractComponent<?> component, String channelID, Value valueState, String label,
ChannelStateUpdateListener channelStateUpdateListener) {
this.component = component;
this.componentConfiguration = componentConfiguration;
this.channelID = channelID;
this.valueState = valueState;
this.label = label;
Expand All @@ -161,9 +164,9 @@ public Builder stateTopic(@Nullable String state_topic, @Nullable String... temp

/**
* @deprecated use commandTopic(String, boolean, int)
* @param command_topic
* @param retain
* @return
* @param command_topic topic
* @param retain retain
* @return this
*/
@Deprecated
public Builder commandTopic(@Nullable String command_topic, boolean retain) {
Expand All @@ -173,9 +176,17 @@ public Builder commandTopic(@Nullable String command_topic, boolean retain) {
}

public Builder commandTopic(@Nullable String command_topic, boolean retain, int qos) {
return commandTopic(command_topic, retain, qos, null);
}

public Builder commandTopic(@Nullable String command_topic, boolean retain, int qos,
@Nullable String template) {
this.command_topic = command_topic;
this.retain = retain;
this.qos = qos;
if (command_topic != null && !command_topic.isBlank()) {
this.templateOut = template;
}
return this;
}

Expand All @@ -184,24 +195,29 @@ public Builder trigger(boolean trigger) {
return this;
}

public CChannel build() {
public Builder commandFilter(@Nullable Predicate<Command> commandFilter) {
this.commandFilter = commandFilter;
return this;
}

public ComponentChannel build() {
return build(true);
}

public CChannel build(boolean addToComponent) {
public ComponentChannel build(boolean addToComponent) {
ChannelUID channelUID;
ChannelState channelState;
Channel channel;
ChannelType type;
ChannelTypeUID channelTypeUID;

channelUID = new ChannelUID(component.channelGroupUID, channelID);
channelUID = new ChannelUID(component.getGroupUID(), channelID);
channelTypeUID = new ChannelTypeUID(MqttBindingConstants.BINDING_ID,
channelUID.getGroupId() + "_" + channelID);
channelState = new ChannelState(
channelState = new HomeAssistantChannelState(
ChannelConfigBuilder.create().withRetain(retain).withQos(qos).withStateTopic(state_topic)
.withCommandTopic(command_topic).makeTrigger(trigger).build(),
channelUID, valueState, channelStateUpdateListener);
channelUID, valueState, channelStateUpdateListener, commandFilter);

String localStateTopic = state_topic;
if (localStateTopic == null || localStateTopic.isBlank() || this.trigger) {
Expand All @@ -215,26 +231,29 @@ public CChannel build(boolean addToComponent) {
}

Configuration configuration = new Configuration();
configuration.put("config", component.channelConfigurationJson);
component.haID.toConfig(configuration);
configuration.put("config", component.getChannelConfigurationJson());
component.getHaID().toConfig(configuration);

channel = ChannelBuilder.create(channelUID, channelState.getItemType()).withType(channelTypeUID)
.withKind(type.getKind()).withLabel(label).withConfiguration(configuration).build();

CChannel result = new CChannel(channelUID, channelState, channel, type, channelTypeUID,
ComponentChannel result = new ComponentChannel(channelUID, channelState, channel, type, channelTypeUID,
channelStateUpdateListener);

@Nullable
TransformationServiceProvider transformationProvider = componentConfiguration
.getTransformationServiceProvider();
TransformationServiceProvider transformationProvider = component.getTransformationServiceProvider();

final String templateIn = this.templateIn;
if (templateIn != null && transformationProvider != null) {
channelState
.addTransformation(new ChannelStateTransformation(JINJA, templateIn, transformationProvider));
}
final String templateOut = this.templateOut;
if (templateOut != null && transformationProvider != null) {
channelState.addTransformationOut(
new ChannelStateTransformation(JINJA, templateOut, transformationProvider));
}
if (addToComponent) {
component.channels.put(channelID, result);
component.getChannelMap().put(channelID, result);
}
return result;
}
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@
import org.openhab.binding.mqtt.generic.ChannelStateUpdateListener;
import org.openhab.binding.mqtt.generic.TransformationServiceProvider;
import org.openhab.binding.mqtt.generic.utils.FutureCollector;
import org.openhab.binding.mqtt.homeassistant.internal.component.AbstractComponent;
import org.openhab.binding.mqtt.homeassistant.internal.component.ComponentFactory;
import org.openhab.core.io.transport.mqtt.MqttBrokerConnection;
import org.openhab.core.io.transport.mqtt.MqttMessageSubscriber;
import org.openhab.core.thing.ThingUID;
Expand Down Expand Up @@ -55,7 +57,7 @@ public class DiscoverComponents implements MqttMessageSubscriber {

private @Nullable ScheduledFuture<?> stopDiscoveryFuture;
private WeakReference<@Nullable MqttBrokerConnection> connectionRef = new WeakReference<>(null);
protected @NonNullByDefault({}) ComponentDiscovered discoveredListener;
protected @Nullable ComponentDiscovered discoveredListener;
private int discoverTime;
private Set<String> topics = new HashSet<>();

Expand Down Expand Up @@ -92,12 +94,11 @@ public void processMessage(String topic, byte[] payload) {

HaID haID = new HaID(topic);
String config = new String(payload);

AbstractComponent<?> component = null;

if (config.length() > 0) {
component = CFactory.createComponent(thingUID, haID, config, updateListener, tracker, scheduler, gson,
transformationServiceProvider);
component = ComponentFactory.createComponent(thingUID, haID, config, updateListener, tracker, scheduler,
gson, transformationServiceProvider);
}
if (component != null) {
component.setConfigSeen();
Expand All @@ -122,9 +123,9 @@ public void processMessage(String topic, byte[] payload) {
* @param connection A MQTT broker connection
* @param discoverTime The time in milliseconds for the discovery to run. Can be 0 to disable the
* timeout.
* You need to call {@link #stopDiscovery(MqttBrokerConnection)} at some
* You need to call {@link #stopDiscovery()} at some
* point in that case.
* @param topicDescription Contains the object-id (=device id) and potentially a node-id as well.
* @param topicDescriptions Contains the object-id (=device id) and potentially a node-id as well.
* @param componentsDiscoveredListener Listener for results
* @return A future that completes normally after the given time in milliseconds or exceptionally on any error.
* Completes immediately if the timeout is disabled.
Expand Down Expand Up @@ -177,8 +178,6 @@ private void subscribeSuccess() {

/**
* Stops an ongoing discovery or do nothing if no discovery is running.
*
* @param connection A MQTT broker connection
*/
public void stopDiscovery() {
subscribeFail(new Throwable("Stopped"));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ private HaID(String baseTopic, String objectID, String nodeID, String component)
this.topic = createTopic(this);
}

private static final String createTopic(HaID id) {
private static String createTopic(HaID id) {
StringBuilder str = new StringBuilder();
str.append(id.baseTopic).append('/').append(id.component).append('/');
if (!id.nodeID.isBlank()) {
Expand All @@ -104,8 +104,8 @@ private static final String createTopic(HaID id) {
* <p>
* <code>objectid</code>, <code>nodeid</code>, and <code>component</code> values are fetched from the configuration.
*
* @param baseTopic
* @param config
* @param baseTopic base topic
* @param config config
* @return newly created HaID
*/
public static HaID fromConfig(String baseTopic, Configuration config) {
Expand All @@ -120,7 +120,7 @@ public static HaID fromConfig(String baseTopic, Configuration config) {
* <p>
* <code>objectid</code>, <code>nodeid</code>, and <code>component</code> values are added to the configuration.
*
* @param config
* @param config config
* @return the modified configuration
*/
public Configuration toConfig(Configuration config) {
Expand All @@ -139,7 +139,7 @@ public Configuration toConfig(Configuration config) {
* The <code>component</code> component in the resulting HaID will be set to <code>+</code>.
* This enables the HaID to be used as an mqtt subscription topic.
*
* @param config
* @param config config
* @return newly created HaID
*/
public static Collection<HaID> fromConfig(HandlerConfiguration config) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@
*/
@NonNullByDefault
public class HandlerConfiguration {
public static final String PROPERTY_BASETOPIC = "basetopic";
public static final String PROPERTY_TOPICS = "topics";
public static final String DEFAULT_BASETOPIC = "homeassistant";
/**
* hint: cannot be final, or <code>getConfigAs</code> will not work.
* The MQTT prefix topic
Expand Down Expand Up @@ -64,7 +67,7 @@ public class HandlerConfiguration {
public List<String> topics;

public HandlerConfiguration() {
this("homeassistant", Collections.emptyList());
this(DEFAULT_BASETOPIC, Collections.emptyList());
}

public HandlerConfiguration(String basetopic, List<String> topics) {
Expand All @@ -76,12 +79,12 @@ public HandlerConfiguration(String basetopic, List<String> topics) {
/**
* Add the <code>basetopic</code> and <code>objectid</code> to the properties.
*
* @param properties
* @param properties properties
* @return the modified properties
*/
public <T extends Map<String, Object>> T appendToProperties(T properties) {
properties.put("basetopic", basetopic);
properties.put("topics", topics);
properties.put(PROPERTY_BASETOPIC, basetopic);
properties.put(PROPERTY_TOPICS, topics);
return properties;
}
}
Loading

0 comments on commit 357dbec

Please sign in to comment.