[mqtt.homeassistant] Support color temp on JSON schema lights (#14839)
* [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>
This commit is contained in:
parent
87ae9e2a37
commit
27924d677f
|
@ -20,12 +20,15 @@ import java.util.Objects;
|
||||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
import org.eclipse.jdt.annotation.Nullable;
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
import org.openhab.binding.mqtt.generic.ChannelStateUpdateListener;
|
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.binding.mqtt.homeassistant.internal.exception.UnsupportedComponentException;
|
||||||
import org.openhab.core.library.types.DecimalType;
|
import org.openhab.core.library.types.DecimalType;
|
||||||
import org.openhab.core.library.types.HSBType;
|
import org.openhab.core.library.types.HSBType;
|
||||||
import org.openhab.core.library.types.OnOffType;
|
import org.openhab.core.library.types.OnOffType;
|
||||||
import org.openhab.core.library.types.PercentType;
|
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.types.StringType;
|
||||||
|
import org.openhab.core.library.unit.Units;
|
||||||
import org.openhab.core.thing.ChannelUID;
|
import org.openhab.core.thing.ChannelUID;
|
||||||
import org.openhab.core.types.Command;
|
import org.openhab.core.types.Command;
|
||||||
import org.openhab.core.types.State;
|
import org.openhab.core.types.State;
|
||||||
|
@ -47,6 +50,7 @@ import com.google.gson.annotations.SerializedName;
|
||||||
@NonNullByDefault
|
@NonNullByDefault
|
||||||
public class JSONSchemaLight extends AbstractRawSchemaLight {
|
public class JSONSchemaLight extends AbstractRawSchemaLight {
|
||||||
private static final BigDecimal SCALE_FACTOR = new BigDecimal("2.55"); // string to not lose precision
|
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);
|
private final Logger logger = LoggerFactory.getLogger(JSONSchemaLight.class);
|
||||||
|
|
||||||
|
@ -67,14 +71,23 @@ public class JSONSchemaLight extends AbstractRawSchemaLight {
|
||||||
protected @Nullable Integer transition;
|
protected @Nullable Integer transition;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TextValue colorModeValue;
|
||||||
|
|
||||||
public JSONSchemaLight(ComponentFactory.ComponentConfiguration builder) {
|
public JSONSchemaLight(ComponentFactory.ComponentConfiguration builder) {
|
||||||
super(builder);
|
super(builder);
|
||||||
|
colorModeValue = new TextValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void buildChannels() {
|
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) {
|
if (channelConfiguration.colorMode) {
|
||||||
List<LightColorMode> supportedColorModes = channelConfiguration.supportedColorModes;
|
|
||||||
if (supportedColorModes == null || channelConfiguration.supportedColorModes.isEmpty()) {
|
if (supportedColorModes == null || channelConfiguration.supportedColorModes.isEmpty()) {
|
||||||
throw new UnsupportedComponentException("JSON schema light with color modes '" + getHaID()
|
throw new UnsupportedComponentException("JSON schema light with color modes '" + getHaID()
|
||||||
+ "' does not define supported_color_modes!");
|
+ "' does not define supported_color_modes!");
|
||||||
|
@ -83,6 +96,12 @@ public class JSONSchemaLight extends AbstractRawSchemaLight {
|
||||||
if (LightColorMode.hasColorChannel(supportedColorModes)) {
|
if (LightColorMode.hasColorChannel(supportedColorModes)) {
|
||||||
hasColorChannel = true;
|
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) {
|
if (hasColorChannel) {
|
||||||
|
@ -118,7 +137,7 @@ public class JSONSchemaLight extends AbstractRawSchemaLight {
|
||||||
json.color = new JSONState.Color();
|
json.color = new JSONState.Color();
|
||||||
if (channelConfiguration.supportedColorModes.contains(LightColorMode.COLOR_MODE_HS)) {
|
if (channelConfiguration.supportedColorModes.contains(LightColorMode.COLOR_MODE_HS)) {
|
||||||
json.color.h = state.getHue().toBigDecimal();
|
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))) {
|
} else if (LightColorMode.hasRGB(Objects.requireNonNull(channelConfiguration.supportedColorModes))) {
|
||||||
var rgb = state.toRGB();
|
var rgb = state.toRGB();
|
||||||
json.color.r = rgb[0].toBigDecimal().multiply(SCALE_FACTOR).intValue();
|
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();
|
json.color.b = rgb[2].toBigDecimal().multiply(SCALE_FACTOR).intValue();
|
||||||
} else { // if (channelConfiguration.supportedColorModes.contains(COLOR_MODE_XY))
|
} else { // if (channelConfiguration.supportedColorModes.contains(COLOR_MODE_XY))
|
||||||
var xy = state.toXY();
|
var xy = state.toXY();
|
||||||
json.color.x = xy[0].toBigDecimal();
|
json.color.x = xy[0].toBigDecimal().divide(BIG_DECIMAL_HUNDRED);
|
||||||
json.color.y = xy[1].toBigDecimal();
|
json.color.y = xy[1].toBigDecimal().divide(BIG_DECIMAL_HUNDRED);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -163,6 +182,30 @@ public class JSONSchemaLight extends AbstractRawSchemaLight {
|
||||||
return false;
|
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
|
@Override
|
||||||
public void updateChannelState(ChannelUID channel, State state) {
|
public void updateChannelState(ChannelUID channel, State state) {
|
||||||
ChannelStateUpdateListener listener = this.channelStateUpdateListener;
|
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) {
|
if (jsonState.color != null) {
|
||||||
PercentType brightness = brightnessValue.getChannelState() instanceof PercentType
|
PercentType brightness = brightnessValue.getChannelState() instanceof PercentType
|
||||||
? (PercentType) brightnessValue.getChannelState()
|
? (PercentType) brightnessValue.getChannelState()
|
||||||
|
@ -216,14 +267,24 @@ public class JSONSchemaLight extends AbstractRawSchemaLight {
|
||||||
if (jsonState.color.h != null && jsonState.color.s != null) {
|
if (jsonState.color.h != null && jsonState.color.s != null) {
|
||||||
colorValue.update(new HSBType(new DecimalType(Objects.requireNonNull(jsonState.color.h)),
|
colorValue.update(new HSBType(new DecimalType(Objects.requireNonNull(jsonState.color.h)),
|
||||||
new PercentType(Objects.requireNonNull(jsonState.color.s)), brightness));
|
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) {
|
} else if (jsonState.color.x != null && jsonState.color.y != null) {
|
||||||
HSBType newColor = HSBType.fromXY(jsonState.color.x.floatValue(), jsonState.color.y.floatValue());
|
HSBType newColor = HSBType.fromXY(jsonState.color.x.floatValue(), jsonState.color.y.floatValue());
|
||||||
colorValue.update(new HSBType(newColor.getHue(), newColor.getSaturation(), brightness));
|
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) {
|
} 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));
|
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) {
|
if (hasColorChannel) {
|
||||||
listener.updateChannelState(new ChannelUID(getGroupUID(), COLOR_CHANNEL_ID), colorValue.getChannelState());
|
listener.updateChannelState(new ChannelUID(getGroupUID(), COLOR_CHANNEL_ID), colorValue.getChannelState());
|
||||||
} else if (brightnessChannel != null) {
|
} else if (brightnessChannel != null) {
|
||||||
|
|
|
@ -61,4 +61,13 @@ public enum LightColorMode {
|
||||||
public static boolean hasRGB(List<LightColorMode> supportedColorModes) {
|
public static boolean hasRGB(List<LightColorMode> supportedColorModes) {
|
||||||
return WITH_RGB.stream().anyMatch(cm -> supportedColorModes.contains(cm));
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue