]> git.basschouten.com Git - openhab-addons.git/commitdiff
[mqtt.homeassistant] add support for DeviceTrigger component (#14234)
authorCody Cutrer <cody@cutrer.us>
Fri, 27 Jan 2023 23:37:45 +0000 (16:37 -0700)
committerGitHub <noreply@github.com>
Fri, 27 Jan 2023 23:37:45 +0000 (00:37 +0100)
Signed-off-by: Cody Cutrer <cody@cutrer.us>
bundles/org.openhab.binding.mqtt.homeassistant/src/main/java/org/openhab/binding/mqtt/homeassistant/internal/component/ComponentFactory.java
bundles/org.openhab.binding.mqtt.homeassistant/src/main/java/org/openhab/binding/mqtt/homeassistant/internal/component/DeviceTrigger.java [new file with mode: 0644]
bundles/org.openhab.binding.mqtt.homeassistant/src/test/java/org/openhab/binding/mqtt/homeassistant/internal/component/AbstractComponentTests.java
bundles/org.openhab.binding.mqtt.homeassistant/src/test/java/org/openhab/binding/mqtt/homeassistant/internal/component/DeviceTriggerTests.java [new file with mode: 0644]

index f502f45fda1fd25287d8c80a116d621e320225d9..0e2c16e5735a68c112e1c724e8a7bef22603ae0f 100644 (file)
@@ -65,6 +65,8 @@ public class ComponentFactory {
                 return new Fan(componentConfiguration);
             case "climate":
                 return new Climate(componentConfiguration);
+            case "device_automation":
+                return new DeviceTrigger(componentConfiguration);
             case "light":
                 return Light.create(componentConfiguration);
             case "lock":
diff --git a/bundles/org.openhab.binding.mqtt.homeassistant/src/main/java/org/openhab/binding/mqtt/homeassistant/internal/component/DeviceTrigger.java b/bundles/org.openhab.binding.mqtt.homeassistant/src/main/java/org/openhab/binding/mqtt/homeassistant/internal/component/DeviceTrigger.java
new file mode 100644 (file)
index 0000000..4381911
--- /dev/null
@@ -0,0 +1,73 @@
+/**
+ * Copyright (c) 2010-2023 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.component;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
+import org.openhab.binding.mqtt.generic.values.TextValue;
+import org.openhab.binding.mqtt.homeassistant.internal.config.dto.AbstractChannelConfiguration;
+import org.openhab.binding.mqtt.homeassistant.internal.exception.ConfigurationException;
+
+import com.google.gson.annotations.SerializedName;
+
+/**
+ * A MQTT Device Trigger, following the https://www.home-assistant.io/integrations/device_trigger.mqtt/ specification.
+ *
+ * @author Cody Cutrer - Initial contribution
+ */
+@NonNullByDefault
+public class DeviceTrigger extends AbstractComponent<DeviceTrigger.ChannelConfiguration> {
+    /**
+     * Configuration class for MQTT component
+     */
+    static class ChannelConfiguration extends AbstractChannelConfiguration {
+        ChannelConfiguration() {
+            super("MQTT Device Trigger");
+        }
+
+        @SerializedName("automation_type")
+        protected String automationType = "trigger";
+        protected String topic = "";
+        protected String type = "";
+        protected String subtype = "";
+
+        protected @Nullable String payload;
+    }
+
+    public DeviceTrigger(ComponentFactory.ComponentConfiguration componentConfiguration) {
+        super(componentConfiguration, ChannelConfiguration.class);
+
+        if (!channelConfiguration.automationType.equals("trigger")) {
+            throw new ConfigurationException("Component:DeviceTrigger must have automation_type 'trigger'");
+        }
+        if (channelConfiguration.type.isBlank()) {
+            throw new ConfigurationException("Component:DeviceTrigger must have a type");
+        }
+        if (channelConfiguration.subtype.isBlank()) {
+            throw new ConfigurationException("Component:DeviceTrigger must have a subtype");
+        }
+
+        TextValue value;
+        String payload = channelConfiguration.payload;
+        if (payload != null) {
+            value = new TextValue(new String[] { payload });
+        } else {
+            value = new TextValue();
+        }
+
+        buildChannel(channelConfiguration.type, value, channelConfiguration.getName(),
+                componentConfiguration.getUpdateListener())
+                        .stateTopic(channelConfiguration.topic, channelConfiguration.getValueTemplate()).trigger(true)
+                        .build();
+    }
+}
index 533c9885446fe9b1ee1ecfad6df224eb1e7f4d92..c14dee7af6d82c403c72ecabe41cc53a889b187b 100644 (file)
@@ -176,6 +176,20 @@ public abstract class AbstractComponentTests extends AbstractHomeAssistantTests
         assertThat(component.getChannel(channelId).getState().getCache().getChannelState(), is(state));
     }
 
+    protected void spyOnChannelUpdates(AbstractComponent<@NonNull ? extends AbstractChannelConfiguration> component,
+            String channelId) {
+        // It's already thingHandler, but not the spy version
+        component.getChannel(channelId).getState().setChannelStateUpdateListener(thingHandler);
+    }
+
+    /**
+     * Assert a channel triggers
+     */
+    protected void assertTriggered(AbstractComponent<@NonNull ? extends AbstractChannelConfiguration> component,
+            String channelId, String trigger) {
+        verify(thingHandler).triggerChannel(eq(component.getChannel(channelId).getChannelUID()), eq(trigger));
+    }
+
     /**
      * Assert that given payload was published exact-once on given topic.
      *
diff --git a/bundles/org.openhab.binding.mqtt.homeassistant/src/test/java/org/openhab/binding/mqtt/homeassistant/internal/component/DeviceTriggerTests.java b/bundles/org.openhab.binding.mqtt.homeassistant/src/test/java/org/openhab/binding/mqtt/homeassistant/internal/component/DeviceTriggerTests.java
new file mode 100644 (file)
index 0000000..4c49cde
--- /dev/null
@@ -0,0 +1,71 @@
+/**
+ * Copyright (c) 2010-2023 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.component;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.MatcherAssert.assertThat;
+
+import java.util.Set;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.junit.jupiter.api.Test;
+import org.openhab.binding.mqtt.generic.values.TextValue;
+
+/**
+ * Tests for {@link DeviceTrigger}
+ *
+ * @author Cody Cutrer - Initial contribution
+ */
+@NonNullByDefault
+public class DeviceTriggerTests extends AbstractComponentTests {
+    public static final String CONFIG_TOPIC = "device_automation/0x8cf681fffe2fd2a6";
+
+    @SuppressWarnings("null")
+    @Test
+    public void test() throws InterruptedException {
+        var component = discoverComponent(configTopicToMqtt(CONFIG_TOPIC), """
+                {
+                    "automation_type": "trigger",
+                    "device": {
+                        "configuration_url": "#/device/0x8cf681fffe2fd2a6/info",
+                        "identifiers": [
+                            "zigbee2mqtt_0x8cf681fffe2fd2a6"
+                        ],
+                        "manufacturer": "IKEA",
+                        "model": "TRADFRI shortcut button (E1812)",
+                        "name": "Charge Now Button",
+                        "sw_version": "2.3.015"
+                    },
+                    "payload": "on",
+                    "subtype": "on",
+                    "topic": "zigbee2mqtt/Charge Now Button/action",
+                    "type": "action"
+                }
+                    """);
+
+        assertThat(component.channels.size(), is(1));
+        assertThat(component.getName(), is("MQTT Device Trigger"));
+
+        assertChannel(component, "action", "zigbee2mqtt/Charge Now Button/action", "", "MQTT Device Trigger",
+                TextValue.class);
+
+        spyOnChannelUpdates(component, "action");
+        publishMessage("zigbee2mqtt/Charge Now Button/action", "on");
+        assertTriggered(component, "action", "on");
+    }
+
+    @Override
+    protected Set<String> getConfigTopics() {
+        return Set.of(CONFIG_TOPIC);
+    }
+}