2 * Copyright (c) 2010-2023 Contributors to the openHAB project
4 * See the NOTICE file(s) distributed with this work for additional
7 * This program and the accompanying materials are made available under the
8 * terms of the Eclipse Public License 2.0 which is available at
9 * http://www.eclipse.org/legal/epl-2.0
11 * SPDX-License-Identifier: EPL-2.0
13 package org.openhab.binding.mqtt.homeassistant.internal.component;
15 import static org.hamcrest.CoreMatchers.is;
16 import static org.hamcrest.MatcherAssert.assertThat;
18 import java.math.BigDecimal;
19 import java.math.MathContext;
22 import org.eclipse.jdt.annotation.NonNullByDefault;
23 import org.junit.jupiter.api.Test;
24 import org.openhab.binding.mqtt.generic.values.ColorValue;
25 import org.openhab.binding.mqtt.generic.values.OnOffValue;
26 import org.openhab.binding.mqtt.generic.values.PercentageValue;
27 import org.openhab.core.library.types.HSBType;
28 import org.openhab.core.library.types.OnOffType;
29 import org.openhab.core.library.types.PercentType;
32 * Tests for {@link Light} conforming to the JSON schema
34 * @author Cody Cutrer - Initial contribution
37 public class JSONSchemaLightTests extends AbstractComponentTests {
38 public static final String CONFIG_TOPIC = "light/0x0000000000000000_light_zigbee2mqtt";
41 public void testRgb() throws InterruptedException {
43 var component = (Light) discoverComponent(configTopicToMqtt(CONFIG_TOPIC),
45 " \"availability\": [ " +
47 " \"topic\": \"zigbee2mqtt/bridge/state\" " +
51 " \"identifiers\": [ " +
52 " \"zigbee2mqtt_0x0000000000000000\" " +
54 " \"manufacturer\": \"Lights inc\", " +
55 " \"model\": \"light v1\", " +
56 " \"name\": \"Light\", " +
57 " \"sw_version\": \"Zigbee2MQTT 1.18.2\" " +
59 " \"name\": \"light\", " +
60 " \"schema\": \"json\", " +
61 " \"state_topic\": \"zigbee2mqtt/light/state\", " +
62 " \"command_topic\": \"zigbee2mqtt/light/set/state\", " +
63 " \"brightness\": true, " +
64 " \"color_mode\": true, " +
65 " \"supported_color_modes\": [\"onoff\", \"brightness\", \"rgb\"]" +
69 assertThat(component.channels.size(), is(1));
70 assertThat(component.getName(), is("light"));
72 assertChannel(component, Light.COLOR_CHANNEL_ID, "", "dummy", "Color", ColorValue.class);
74 publishMessage("zigbee2mqtt/light/state", "{ \"state\": \"ON\" }");
75 assertState(component, Light.COLOR_CHANNEL_ID, HSBType.WHITE);
76 publishMessage("zigbee2mqtt/light/state", "{ \"color\": {\"r\": 10, \"g\": 20, \"b\": 30 } }");
77 assertState(component, Light.COLOR_CHANNEL_ID, HSBType.fromRGB(10, 20, 30));
78 publishMessage("zigbee2mqtt/light/state", "{ \"brightness\": 255 }");
79 assertState(component, Light.COLOR_CHANNEL_ID, new HSBType("210,66,100"));
81 sendCommand(component, Light.COLOR_CHANNEL_ID, HSBType.BLUE);
82 assertPublished("zigbee2mqtt/light/set/state",
83 "{\"state\":\"ON\",\"brightness\":255,\"color\":{\"r\":0,\"g\":0,\"b\":255}}");
85 // OnOff commands should route to the correct topic
86 sendCommand(component, Light.COLOR_CHANNEL_ID, OnOffType.OFF);
87 assertPublished("zigbee2mqtt/light/set/state", "{\"state\":\"OFF\"}");
89 sendCommand(component, Light.COLOR_CHANNEL_ID, OnOffType.ON);
90 assertPublished("zigbee2mqtt/light/set/state", "{\"state\":\"ON\"}");
92 sendCommand(component, Light.COLOR_CHANNEL_ID, new PercentType(50));
93 assertPublished("zigbee2mqtt/light/set/state", "{\"state\":\"ON\",\"brightness\":127}");
97 public void testBrightnessAndOnOff() throws InterruptedException {
99 var component = (Light) discoverComponent(configTopicToMqtt(CONFIG_TOPIC),
101 " \"name\": \"light\", " +
102 " \"schema\": \"json\", " +
103 " \"state_topic\": \"zigbee2mqtt/light/state\", " +
104 " \"command_topic\": \"zigbee2mqtt/light/set/state\", " +
105 " \"brightness\": true" +
109 assertThat(component.channels.size(), is(1));
110 assertThat(component.getName(), is("light"));
112 assertChannel(component, Light.BRIGHTNESS_CHANNEL_ID, "", "dummy", "Brightness", PercentageValue.class);
114 publishMessage("zigbee2mqtt/light/state", "{ \"state\": \"ON\", \"brightness\": 128 }");
115 assertState(component, Light.BRIGHTNESS_CHANNEL_ID,
116 new PercentType(new BigDecimal(128 * 100).divide(new BigDecimal(255), MathContext.DECIMAL128)));
118 sendCommand(component, Light.BRIGHTNESS_CHANNEL_ID, PercentType.HUNDRED);
119 assertPublished("zigbee2mqtt/light/set/state", "{\"state\":\"ON\",\"brightness\":255}");
121 sendCommand(component, Light.BRIGHTNESS_CHANNEL_ID, OnOffType.OFF);
122 assertPublished("zigbee2mqtt/light/set/state", "{\"state\":\"OFF\"}");
126 public void testOnOffOnly() throws InterruptedException {
128 var component = (Light) discoverComponent(configTopicToMqtt(CONFIG_TOPIC),
130 " \"name\": \"light\", " +
131 " \"schema\": \"json\", " +
132 " \"state_topic\": \"zigbee2mqtt/light/state\", " +
133 " \"command_topic\": \"zigbee2mqtt/light/set/state\"" +
137 assertThat(component.channels.size(), is(1));
138 assertThat(component.getName(), is("light"));
140 assertChannel(component, Light.ON_OFF_CHANNEL_ID, "", "dummy", "On/Off State", OnOffValue.class);
142 publishMessage("zigbee2mqtt/light/state", "{ \"state\": \"ON\" }");
143 assertState(component, Light.ON_OFF_CHANNEL_ID, OnOffType.ON);
144 publishMessage("zigbee2mqtt/light/state", "{ \"state\": \"OFF\" }");
145 assertState(component, Light.ON_OFF_CHANNEL_ID, OnOffType.OFF);
147 sendCommand(component, Light.ON_OFF_CHANNEL_ID, OnOffType.OFF);
148 assertPublished("zigbee2mqtt/light/set/state", "{\"state\":\"OFF\"}");
149 sendCommand(component, Light.ON_OFF_CHANNEL_ID, OnOffType.ON);
150 assertPublished("zigbee2mqtt/light/set/state", "{\"state\":\"ON\"}");
154 protected Set<String> getConfigTopics() {
155 return Set.of(CONFIG_TOPIC);