Skip to content

Commit

Permalink
[mqtt.homeassistant] Fix color lights that don't specify color_mode: …
Browse files Browse the repository at this point in the history
…true (openhab#17240)

* [mqtt.homeassistant] Fix color lights that don't specify color_mode: true

See home-assistant/core#111676

Signed-off-by: Cody Cutrer <cody@cutrer.us>
  • Loading branch information
ccutrer authored Aug 13, 2024
1 parent 8dfb10e commit 740e449
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 16 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
import org.openhab.binding.mqtt.generic.ChannelStateUpdateListener;
import org.openhab.binding.mqtt.generic.values.TextValue;
import org.openhab.binding.mqtt.homeassistant.internal.ComponentChannelType;
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;
Expand Down Expand Up @@ -82,19 +81,7 @@ public JSONSchemaLight(ComponentFactory.ComponentConfiguration builder, boolean
@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, ComponentChannelType.STRING, colorModeValue, "Color Mode", this)
.isAdvanced(true).build();
}

if (channelConfiguration.colorMode) {
if (supportedColorModes == null || channelConfiguration.supportedColorModes.isEmpty()) {
throw new UnsupportedComponentException("JSON schema light with color modes '" + getHaID()
+ "' does not define supported_color_modes!");
}

if (supportedColorModes != null) {
if (LightColorMode.hasColorChannel(supportedColorModes)) {
hasColorChannel = true;
}
Expand All @@ -103,6 +90,14 @@ protected void buildChannels() {
buildChannel(COLOR_TEMP_CHANNEL_ID, ComponentChannelType.NUMBER, colorTempValue, "Color Temperature",
this).commandTopic(DUMMY_TOPIC, true, 1)
.commandFilter(command -> handleColorTempCommand(command)).build();

if (hasColorChannel) {
colorModeValue = new TextValue(
supportedColorModes.stream().map(LightColorMode::serializedName).toArray(String[]::new));
buildChannel(COLOR_MODE_CHANNEL_ID, ComponentChannelType.STRING, colorModeValue, "Color Mode", this)
.isAdvanced(true).build();

}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,6 @@ static class ChannelConfiguration extends AbstractChannelConfiguration {
protected String schema = DEFAULT_SCHEMA;
protected @Nullable Boolean optimistic; // All schemas
protected boolean brightness = false; // JSON schema only
@SerializedName("color_mode")
protected boolean colorMode = false; // JSON schema only
@SerializedName("supported_color_modes")
protected @Nullable List<LightColorMode> supportedColorModes; // JSON schema only
// Defines when on the payload_on is sent. Using last (the default) will send
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,63 @@ public void testRgb() throws InterruptedException {
assertPublished("zigbee2mqtt/light/set/state", "{\"state\":\"ON\",\"brightness\":127}");
}

@Test
public void testRgbNewStyle() throws InterruptedException {
// @formatter:off
var component = (Light) discoverComponent(configTopicToMqtt(CONFIG_TOPIC),
"""
{ \
"availability": [ \
{ \
"topic": "zigbee2mqtt/bridge/state" \
} \
], \
"device": { \
"identifiers": [ \
"zigbee2mqtt_0x0000000000000000" \
], \
"manufacturer": "Lights inc", \
"model": "light v1", \
"name": "Light", \
"sw_version": "Zigbee2MQTT 1.18.2" \
}, \
"name": "light", \
"schema": "json", \
"state_topic": "zigbee2mqtt/light/state", \
"command_topic": "zigbee2mqtt/light/set/state", \
"brightness": true, \
"supported_color_modes": ["rgb"]\
}\
""");
// @formatter:on

assertThat(component.channels.size(), is(1));
assertThat(component.getName(), is("light"));

assertChannel(component, Light.COLOR_CHANNEL_ID, "", "dummy", "Color", ColorValue.class);

publishMessage("zigbee2mqtt/light/state", "{ \"state\": \"ON\" }");
assertState(component, Light.COLOR_CHANNEL_ID, HSBType.WHITE);
publishMessage("zigbee2mqtt/light/state", "{ \"color\": {\"r\": 10, \"g\": 20, \"b\": 30 } }");
assertState(component, Light.COLOR_CHANNEL_ID, HSBType.fromRGB(10, 20, 30));
publishMessage("zigbee2mqtt/light/state", "{ \"brightness\": 255 }");
assertState(component, Light.COLOR_CHANNEL_ID, new HSBType("210,67,100"));

sendCommand(component, Light.COLOR_CHANNEL_ID, HSBType.BLUE);
assertPublished("zigbee2mqtt/light/set/state",
"{\"state\":\"ON\",\"brightness\":255,\"color\":{\"r\":0,\"g\":0,\"b\":255}}");

// OnOff commands should route to the correct topic
sendCommand(component, Light.COLOR_CHANNEL_ID, OnOffType.OFF);
assertPublished("zigbee2mqtt/light/set/state", "{\"state\":\"OFF\"}");

sendCommand(component, Light.COLOR_CHANNEL_ID, OnOffType.ON);
assertPublished("zigbee2mqtt/light/set/state", "{\"state\":\"ON\"}");

sendCommand(component, Light.COLOR_CHANNEL_ID, new PercentType(50));
assertPublished("zigbee2mqtt/light/set/state", "{\"state\":\"ON\",\"brightness\":127}");
}

@Test
public void testBrightnessAndOnOff() throws InterruptedException {
// @formatter:off
Expand Down

0 comments on commit 740e449

Please sign in to comment.