]> git.basschouten.com Git - openhab-addons.git/commitdiff
[mqtt.homeassistant] Support color temp on JSON schema lights (#14839)
authorCody Cutrer <cody@cutrer.us>
Sat, 18 Nov 2023 20:31:49 +0000 (13:31 -0700)
committerGitHub <noreply@github.com>
Sat, 18 Nov 2023 20:31:49 +0000 (21:31 +0100)
* [mqtt.homeassistant] support color temp on JSON schema lights

also adds a color_mode channel if color temp is possible, so you can
know how the bulb is behaving

* put color mode channel construction into buildChannels()

---------

Signed-off-by: Cody Cutrer <cody@cutrer.us>
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/LightColorMode.java

index 01e8dcb9fe02ba35264650144a1e6bac991d5f68..8650018426da4777bd4b8511abf17cb559aea7db 100644 (file)
@@ -20,12 +20,15 @@ import java.util.Objects;
 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.TextValue;
 import org.openhab.binding.mqtt.homeassistant.internal.exception.UnsupportedComponentException;
 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.QuantityType;
 import org.openhab.core.library.types.StringType;
+import org.openhab.core.library.unit.Units;
 import org.openhab.core.thing.ChannelUID;
 import org.openhab.core.types.Command;
 import org.openhab.core.types.State;
@@ -47,6 +50,7 @@ import com.google.gson.annotations.SerializedName;
 @NonNullByDefault
 public class JSONSchemaLight extends AbstractRawSchemaLight {
     private static final BigDecimal SCALE_FACTOR = new BigDecimal("2.55"); // string to not lose precision
+    private static final BigDecimal BIG_DECIMAL_HUNDRED = new BigDecimal(100);
 
     private final Logger logger = LoggerFactory.getLogger(JSONSchemaLight.class);
 
@@ -67,14 +71,23 @@ public class JSONSchemaLight extends AbstractRawSchemaLight {
         protected @Nullable Integer transition;
     }
 
+    TextValue colorModeValue;
+
     public JSONSchemaLight(ComponentFactory.ComponentConfiguration builder) {
         super(builder);
+        colorModeValue = new TextValue();
     }
 
     @Override
     protected void buildChannels() {
+        List<LightColorMode> supportedColorModes = channelConfiguration.supportedColorModes;
+        if (supportedColorModes != null && supportedColorModes.contains(LightColorMode.COLOR_MODE_COLOR_TEMP)) {
+            colorModeValue = new TextValue(
+                    supportedColorModes.stream().map(LightColorMode::serializedName).toArray(String[]::new));
+            buildChannel(COLOR_MODE_CHANNEL_ID, colorModeValue, "Color Mode", this).isAdvanced(true).build();
+        }
+
         if (channelConfiguration.colorMode) {
-            List<LightColorMode> supportedColorModes = channelConfiguration.supportedColorModes;
             if (supportedColorModes == null || channelConfiguration.supportedColorModes.isEmpty()) {
                 throw new UnsupportedComponentException("JSON schema light with color modes '" + getHaID()
                         + "' does not define supported_color_modes!");
@@ -83,6 +96,12 @@ public class JSONSchemaLight extends AbstractRawSchemaLight {
             if (LightColorMode.hasColorChannel(supportedColorModes)) {
                 hasColorChannel = true;
             }
+
+            if (supportedColorModes.contains(LightColorMode.COLOR_MODE_COLOR_TEMP)) {
+                buildChannel(COLOR_TEMP_CHANNEL_ID, colorTempValue, "Color Temperature", this)
+                        .commandTopic(DUMMY_TOPIC, true, 1).commandFilter(command -> handleColorTempCommand(command))
+                        .build();
+            }
         }
 
         if (hasColorChannel) {
@@ -118,7 +137,7 @@ public class JSONSchemaLight extends AbstractRawSchemaLight {
                 json.color = new JSONState.Color();
                 if (channelConfiguration.supportedColorModes.contains(LightColorMode.COLOR_MODE_HS)) {
                     json.color.h = state.getHue().toBigDecimal();
-                    json.color.s = state.getSaturation().toBigDecimal();
+                    json.color.s = state.getSaturation().toBigDecimal().divide(BIG_DECIMAL_HUNDRED);
                 } else if (LightColorMode.hasRGB(Objects.requireNonNull(channelConfiguration.supportedColorModes))) {
                     var rgb = state.toRGB();
                     json.color.r = rgb[0].toBigDecimal().multiply(SCALE_FACTOR).intValue();
@@ -126,8 +145,8 @@ public class JSONSchemaLight extends AbstractRawSchemaLight {
                     json.color.b = rgb[2].toBigDecimal().multiply(SCALE_FACTOR).intValue();
                 } else { // if (channelConfiguration.supportedColorModes.contains(COLOR_MODE_XY))
                     var xy = state.toXY();
-                    json.color.x = xy[0].toBigDecimal();
-                    json.color.y = xy[1].toBigDecimal();
+                    json.color.x = xy[0].toBigDecimal().divide(BIG_DECIMAL_HUNDRED);
+                    json.color.y = xy[1].toBigDecimal().divide(BIG_DECIMAL_HUNDRED);
                 }
             }
         }
@@ -163,6 +182,30 @@ public class JSONSchemaLight extends AbstractRawSchemaLight {
         return false;
     }
 
+    private boolean handleColorTempCommand(Command command) {
+        JSONState json = new JSONState();
+
+        if (command instanceof DecimalType) {
+            command = new QuantityType<>(((DecimalType) command).toBigDecimal(), Units.MIRED);
+        }
+        if (command instanceof QuantityType) {
+            QuantityType<?> mireds = ((QuantityType<?>) command).toInvertibleUnit(Units.MIRED);
+            if (mireds == null) {
+                logger.warn("Unable to convert {} to mireds", command);
+                return false;
+            }
+            json.state = "ON";
+            json.colorTemp = mireds.toBigDecimal().intValue();
+        } else {
+            return false;
+        }
+
+        String jsonCommand = getGson().toJson(json);
+        logger.debug("Publishing new state '{}' of light {} to MQTT.", jsonCommand, getName());
+        rawChannel.getState().publishValue(new StringType(jsonCommand));
+        return false;
+    }
+
     @Override
     public void updateChannelState(ChannelUID channel, State state) {
         ChannelStateUpdateListener listener = this.channelStateUpdateListener;
@@ -204,6 +247,14 @@ public class JSONSchemaLight extends AbstractRawSchemaLight {
             }
         }
 
+        if (jsonState.colorTemp != null) {
+            colorTempValue.update(new QuantityType(Objects.requireNonNull(jsonState.colorTemp), Units.MIRED));
+            listener.updateChannelState(new ChannelUID(getGroupUID(), COLOR_TEMP_CHANNEL_ID),
+                    colorTempValue.getChannelState());
+
+            colorModeValue.update(new StringType(LightColorMode.COLOR_MODE_COLOR_TEMP.serializedName()));
+        }
+
         if (jsonState.color != null) {
             PercentType brightness = brightnessValue.getChannelState() instanceof PercentType
                     ? (PercentType) brightnessValue.getChannelState()
@@ -216,14 +267,24 @@ public class JSONSchemaLight extends AbstractRawSchemaLight {
             if (jsonState.color.h != null && jsonState.color.s != null) {
                 colorValue.update(new HSBType(new DecimalType(Objects.requireNonNull(jsonState.color.h)),
                         new PercentType(Objects.requireNonNull(jsonState.color.s)), brightness));
+                colorModeValue.update(new StringType(LightColorMode.COLOR_MODE_HS.serializedName()));
             } else if (jsonState.color.x != null && jsonState.color.y != null) {
                 HSBType newColor = HSBType.fromXY(jsonState.color.x.floatValue(), jsonState.color.y.floatValue());
                 colorValue.update(new HSBType(newColor.getHue(), newColor.getSaturation(), brightness));
+                colorModeValue.update(new StringType(LightColorMode.COLOR_MODE_XY.serializedName()));
             } else if (jsonState.color.r != null && jsonState.color.g != null && jsonState.color.b != null) {
                 colorValue.update(HSBType.fromRGB(jsonState.color.r, jsonState.color.g, jsonState.color.b));
+                colorModeValue.update(new StringType(LightColorMode.COLOR_MODE_RGB.serializedName()));
             }
         }
 
+        if (jsonState.colorMode != null) {
+            colorModeValue.update(new StringType(jsonState.colorMode.serializedName()));
+        }
+
+        listener.updateChannelState(new ChannelUID(getGroupUID(), COLOR_MODE_CHANNEL_ID),
+                colorModeValue.getChannelState());
+
         if (hasColorChannel) {
             listener.updateChannelState(new ChannelUID(getGroupUID(), COLOR_CHANNEL_ID), colorValue.getChannelState());
         } else if (brightnessChannel != null) {
index cb8aa6fb950b76acb796d63c67c4421ed7a47b2a..a7d364ff7544ef075564fb18cccabee6cc464e25 100644 (file)
@@ -61,4 +61,13 @@ public enum LightColorMode {
     public static boolean hasRGB(List<LightColorMode> supportedColorModes) {
         return WITH_RGB.stream().anyMatch(cm -> supportedColorModes.contains(cm));
     }
+
+    public String serializedName() {
+        try {
+            return LightColorMode.class.getDeclaredField(toString()).getAnnotation(SerializedName.class).value();
+        } catch (NoSuchFieldException e) {
+            // can't happen
+            throw new IllegalStateException(e);
+        }
+    }
 }