]> git.basschouten.com Git - openhab-addons.git/commitdiff
[mqtt.homeassistant] implement effect channel for light (#15914)
authorCody Cutrer <cody@cutrer.us>
Sun, 19 Nov 2023 16:52:51 +0000 (09:52 -0700)
committerGitHub <noreply@github.com>
Sun, 19 Nov 2023 16:52:51 +0000 (17:52 +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/DefaultSchemaLight.java
bundles/org.openhab.binding.mqtt.homeassistant/src/main/java/org/openhab/binding/mqtt/homeassistant/internal/component/JSONSchemaLight.java
bundles/org.openhab.binding.mqtt.homeassistant/src/main/java/org/openhab/binding/mqtt/homeassistant/internal/component/Light.java
bundles/org.openhab.binding.mqtt.homeassistant/src/test/java/org/openhab/binding/mqtt/homeassistant/internal/component/DefaultSchemaLightTests.java

index 8b90631d3a93a984002f8ae26e03c86d05c52051..676d6ddd2cbc7271fbd0d81cf7eac325115c2470 100644 (file)
@@ -98,8 +98,9 @@ public class DefaultSchemaLight extends Light {
                     .build();
         }
 
-        if (channelConfiguration.effectStateTopic != null || channelConfiguration.effectCommandTopic != null) {
-            buildChannel(EFFECT_CHANNEL_ID, effectValue, "Lighting effect", this)
+        if (effectValue != null
+                && (channelConfiguration.effectStateTopic != null || channelConfiguration.effectCommandTopic != null)) {
+            buildChannel(EFFECT_CHANNEL_ID, Objects.requireNonNull(effectValue), "Lighting Effect", this)
                     .stateTopic(channelConfiguration.effectStateTopic, channelConfiguration.effectValueTemplate)
                     .commandTopic(channelConfiguration.effectCommandTopic, channelConfiguration.isRetain(),
                             channelConfiguration.getQos())
index 8a270d01e01c7f27c6bdbf772619435d88ec07fc..93dcd606a695855745fb7f67306388a8095683f7 100644 (file)
@@ -114,6 +114,22 @@ public class JSONSchemaLight extends AbstractRawSchemaLight {
             onOffChannel = buildChannel(ON_OFF_CHANNEL_ID, onOffValue, "On/Off State", this)
                     .commandTopic(DUMMY_TOPIC, true, 1).commandFilter(this::handleCommand).build();
         }
+
+        if (effectValue != null) {
+            buildChannel(EFFECT_CHANNEL_ID, Objects.requireNonNull(effectValue), "Lighting Effect", this)
+                    .commandTopic(DUMMY_TOPIC, true, 1).commandFilter(command -> handleEffectCommand(command)).build();
+
+        }
+    }
+
+    private boolean handleEffectCommand(Command command) {
+        if (command instanceof StringType) {
+            JSONState json = new JSONState();
+            json.state = "ON";
+            json.effect = command.toString();
+            publishState(json);
+        }
+        return false;
     }
 
     @Override
@@ -151,6 +167,10 @@ public class JSONSchemaLight extends AbstractRawSchemaLight {
             }
         }
 
+        publishState(json);
+    }
+
+    private void publishState(JSONState json) {
         String command = getGson().toJson(json);
         logger.debug("Publishing new state '{}' of light {} to MQTT.", command, getName());
         rawChannel.getState().publishValue(new StringType(command));
@@ -224,6 +244,15 @@ public class JSONSchemaLight extends AbstractRawSchemaLight {
             return;
         }
 
+        if (effectValue != null) {
+            if (jsonState.effect != null) {
+                effectValue.update(new StringType(jsonState.effect));
+                listener.updateChannelState(buildChannelUID(EFFECT_CHANNEL_ID), effectValue.getChannelState());
+            } else {
+                listener.updateChannelState(buildChannelUID(EFFECT_CHANNEL_ID), UnDefType.NULL);
+            }
+        }
+
         if (jsonState.state != null) {
             onOffValue.update(onOffValue.parseCommand(new StringType(jsonState.state)));
             if (brightnessValue.getChannelState() instanceof UnDefType) {
index 782268cdab047c1b60fc745760818eb3274acf54..c0c41ef34a20c18762510e658e1a214661ef864a 100644 (file)
@@ -47,7 +47,7 @@ import com.google.gson.annotations.SerializedName;
  * three different schemas.
  *
  * As of now, only on/off, brightness, and RGB are fully implemented and tested.
- * HS and XY are implemented, but not tested. Color temp and effect are only
+ * HS and XY are implemented, but not tested. Color temp is only
  * implemented (but not tested) for the default schema.
  *
  * @author David Graeff - Initial contribution
@@ -246,7 +246,7 @@ public abstract class Light extends AbstractComponent<Light.ChannelConfiguration
     protected OnOffValue onOffValue;
     protected PercentageValue brightnessValue;
     protected final NumberValue colorTempValue;
-    protected final TextValue effectValue = new TextValue();
+    protected final @Nullable TextValue effectValue;
     protected final ColorValue colorValue = new ColorValue(ColorMode.HSB, null, null, 100);
 
     protected final List<ComponentChannel> hiddenChannels = new ArrayList<>();
@@ -281,6 +281,13 @@ public abstract class Light extends AbstractComponent<Light.ChannelConfiguration
         brightnessValue = new PercentageValue(null, new BigDecimal(channelConfiguration.brightnessScale), null, null,
                 null);
         @Nullable
+        List<String> effectList = channelConfiguration.effectList;
+        if (effectList != null) {
+            effectValue = new TextValue(effectList.toArray(new String[0]));
+        } else {
+            effectValue = null;
+        }
+        @Nullable
         BigDecimal min = null, max = null;
         if (channelConfiguration.minMireds != null) {
             min = new BigDecimal(channelConfiguration.minMireds);
index a5b092b01e779a6caeaa6bec1682aeadd4c1af8a..150d9e4f15f1525901a48b91b92ecae0ecac8870 100644 (file)
@@ -27,11 +27,13 @@ import org.junit.jupiter.api.Test;
 import org.openhab.binding.mqtt.generic.values.ColorValue;
 import org.openhab.binding.mqtt.generic.values.OnOffValue;
 import org.openhab.binding.mqtt.generic.values.PercentageValue;
+import org.openhab.binding.mqtt.generic.values.TextValue;
 import org.openhab.binding.mqtt.homeassistant.internal.ComponentChannel;
 import org.openhab.core.library.types.DecimalType;
 import org.openhab.core.library.types.HSBType;
 import org.openhab.core.library.types.OnOffType;
 import org.openhab.core.library.types.PercentType;
+import org.openhab.core.library.types.StringType;
 
 /**
  * Tests for {@link Light} confirming to the default schema
@@ -285,6 +287,40 @@ public class DefaultSchemaLightTests extends AbstractComponentTests {
         assertPublished("zigbee2mqtt/light/set/state", "OFF_");
     }
 
+    @Test
+    public void testOnOffWithEffect() throws InterruptedException {
+        // @formatter:off
+        var component = (Light) discoverComponent(configTopicToMqtt(CONFIG_TOPIC),
+                "{ " +
+                        "  \"name\": \"light\", " +
+                        "  \"state_topic\": \"zigbee2mqtt/light/state\", " +
+                        "  \"command_topic\": \"zigbee2mqtt/light/set/state\", " +
+                        "  \"effect_command_topic\": \"zigbee2mqtt/light/set/effect\", " +
+                        "  \"state_value_template\": \"{{ value_json.power }}\", " +
+                        "  \"effect_list\": [\"party\", \"rainbow\"]," +
+                        "  \"effect_state_topic\": \"zigbee2mqtt/light/effect\"" +
+                        "}");
+        // @formatter:on
+
+        assertThat(component.channels.size(), is(2));
+        assertThat(component.getName(), is("light"));
+
+        assertChannel(component, Light.ON_OFF_CHANNEL_ID, "zigbee2mqtt/light/state", "zigbee2mqtt/light/set/state",
+                "On/Off State", OnOffValue.class);
+        assertChannel(component, Light.EFFECT_CHANNEL_ID, "zigbee2mqtt/light/effect", "zigbee2mqtt/light/set/effect",
+                "Lighting Effect", TextValue.class);
+
+        publishMessage("zigbee2mqtt/light/state", "{\"power\": \"ON\"}");
+        assertState(component, Light.ON_OFF_CHANNEL_ID, OnOffType.ON);
+        publishMessage("zigbee2mqtt/light/effect", "party");
+        assertState(component, Light.EFFECT_CHANNEL_ID, new StringType("party"));
+        publishMessage("zigbee2mqtt/light/state", "{\"power\": \"OFF\"}");
+        assertState(component, Light.ON_OFF_CHANNEL_ID, OnOffType.OFF);
+
+        sendCommand(component, Light.EFFECT_CHANNEL_ID, new StringType("rainbow"));
+        assertPublished("zigbee2mqtt/light/set/effect", "rainbow");
+    }
+
     @Override
     protected Set<String> getConfigTopics() {
         return Set.of(CONFIG_TOPIC);