]> git.basschouten.com Git - openhab-addons.git/blob
10ca508baee38a43db6664a08a96a53530efb459
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2022 Contributors to the openHAB project
3  *
4  * See the NOTICE file(s) distributed with this work for additional
5  * information.
6  *
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
10  *
11  * SPDX-License-Identifier: EPL-2.0
12  */
13 package org.openhab.binding.hue.internal.handler;
14
15 import static org.junit.jupiter.api.Assertions.assertEquals;
16 import static org.mockito.ArgumentMatchers.*;
17 import static org.mockito.Mockito.*;
18 import static org.openhab.binding.hue.internal.HueBindingConstants.*;
19
20 import java.util.Map;
21
22 import org.eclipse.jdt.annotation.NonNullByDefault;
23 import org.eclipse.jdt.annotation.Nullable;
24 import org.junit.jupiter.api.Test;
25 import org.mockito.ArgumentCaptor;
26 import org.openhab.binding.hue.internal.dto.FullConfig;
27 import org.openhab.binding.hue.internal.dto.FullLight;
28 import org.openhab.binding.hue.internal.dto.State.ColorMode;
29 import org.openhab.binding.hue.internal.dto.StateUpdate;
30 import org.openhab.core.config.core.Configuration;
31 import org.openhab.core.library.types.DecimalType;
32 import org.openhab.core.library.types.HSBType;
33 import org.openhab.core.library.types.IncreaseDecreaseType;
34 import org.openhab.core.library.types.OnOffType;
35 import org.openhab.core.library.types.PercentType;
36 import org.openhab.core.library.types.StringType;
37 import org.openhab.core.thing.Bridge;
38 import org.openhab.core.thing.ChannelUID;
39 import org.openhab.core.thing.Thing;
40 import org.openhab.core.thing.ThingStatus;
41 import org.openhab.core.thing.ThingUID;
42 import org.openhab.core.thing.binding.ThingHandlerCallback;
43 import org.openhab.core.types.Command;
44
45 import com.google.gson.Gson;
46 import com.google.gson.JsonElement;
47 import com.google.gson.JsonParser;
48
49 /**
50  * Tests for {@link HueLightHandler}.
51  *
52  * @author Oliver Libutzki - Initial contribution
53  * @author Michael Grammling - Initial contribution
54  * @author Markus Mazurczak - Added test for OSRAM Par16 50 TW bulbs
55  * @author Andre Fuechsel - modified tests after introducing the generic thing types
56  * @author Denis Dudnik - switched to internally integrated source of Jue library
57  * @author Simon Kaufmann - migrated to plain Java test
58  * @author Christoph Weitkamp - Added support for bulbs using CIE XY colormode only
59  * @author Jacob Laursen - Add workaround for LK Wiser products
60  */
61 @NonNullByDefault
62 public class HueLightHandlerTest {
63
64     private static final int MIN_COLOR_TEMPERATURE = 153;
65     private static final int MAX_COLOR_TEMPERATURE = 500;
66     private static final int COLOR_TEMPERATURE_RANGE = MAX_COLOR_TEMPERATURE - MIN_COLOR_TEMPERATURE;
67
68     private static final String OSRAM = "OSRAM";
69     private static final String OSRAM_MODEL_TYPE = HueLightHandler.OSRAM_PAR16_50_TW_MODEL_ID;
70     private static final String OSRAM_MODEL_TYPE_ID = HueLightHandler.OSRAM_PAR16_50_TW_MODEL_ID;
71
72     private final Gson gson = new Gson();
73
74     @Test
75     public void assertCommandForOsramPar1650ForColorTemperatureChannelOn() {
76         String expectedReply = "{\"on\" : true, \"bri\" : 254}";
77         assertSendCommandForColorTempForPar16(OnOffType.ON, new HueLightState(OSRAM_MODEL_TYPE, OSRAM), expectedReply);
78     }
79
80     @Test
81     public void assertCommandForOsramPar1650ForColorTemperatureChannelOff() {
82         String expectedReply = "{\"on\" : false, \"transitiontime\" : 0}";
83         assertSendCommandForColorTempForPar16(OnOffType.OFF, new HueLightState(OSRAM_MODEL_TYPE, OSRAM), expectedReply);
84     }
85
86     @Test
87     public void assertCommandForOsramPar1650ForBrightnessChannelOn() {
88         String expectedReply = "{\"on\" : true, \"bri\" : 254}";
89         assertSendCommandForBrightnessForPar16(OnOffType.ON, new HueLightState(OSRAM_MODEL_TYPE, OSRAM), expectedReply);
90     }
91
92     @Test
93     public void assertCommandForOsramPar1650ForBrightnessChannelOff() {
94         String expectedReply = "{\"on\" : false, \"transitiontime\" : 0}";
95         assertSendCommandForBrightnessForPar16(OnOffType.OFF, new HueLightState(OSRAM_MODEL_TYPE, OSRAM),
96                 expectedReply);
97     }
98
99     @Test
100     public void assertCommandForLkWiserForBrightnessChannelOff() {
101         final String expectedReply = "{\"on\" : false, \"transitiontime\" : 0}";
102         final String vendor = "Schneider Electric";
103         assertSendCommand(CHANNEL_BRIGHTNESS, OnOffType.OFF,
104                 new HueLightState(HueLightHandler.LK_WISER_MODEL_ID, vendor), expectedReply,
105                 HueLightHandler.LK_WISER_MODEL_ID, vendor);
106     }
107
108     @Test
109     public void assertCommandForColorChannelOn() {
110         String expectedReply = "{\"on\" : true}";
111         assertSendCommandForColor(OnOffType.ON, new HueLightState(), expectedReply);
112     }
113
114     @Test
115     public void assertCommandForColorTemperatureChannelOn() {
116         String expectedReply = "{\"on\" : true}";
117         assertSendCommandForColorTemp(OnOffType.ON, new HueLightState(), expectedReply);
118     }
119
120     @Test
121     public void assertCommandForColorChannelOff() {
122         String expectedReply = "{\"on\" : false}";
123         assertSendCommandForColor(OnOffType.OFF, new HueLightState(), expectedReply);
124     }
125
126     @Test
127     public void assertCommandForColorTemperatureChannelOff() {
128         String expectedReply = "{\"on\" : false}";
129         assertSendCommandForColorTemp(OnOffType.OFF, new HueLightState(), expectedReply);
130     }
131
132     @Test
133     public void assertCommandForColorTemperatureChannel0Percent() {
134         String expectedReply = "{\"ct\" : 153, \"transitiontime\" : 4}";
135         assertSendCommandForColorTemp(new PercentType(0), new HueLightState(), expectedReply);
136     }
137
138     @Test
139     public void assertCommandForColorTemperatureChannel50Percent() {
140         String expectedReply = "{\"ct\" : 327, \"transitiontime\" : 4}";
141         assertSendCommandForColorTemp(new PercentType(50), new HueLightState(), expectedReply);
142     }
143
144     @Test
145     public void assertCommandForColorTemperatureChannel1000Percent() {
146         String expectedReply = "{\"ct\" : 500, \"transitiontime\" : 4}";
147         assertSendCommandForColorTemp(new PercentType(100), new HueLightState(), expectedReply);
148     }
149
150     @Test
151     public void assertCommandForColorTemperatureAbsChannel6500Kelvin() {
152         String expectedReply = "{\"ct\" : 153, \"transitiontime\" : 4}";
153         assertSendCommandForColorTempAbs(new DecimalType(6500), new HueLightState(), expectedReply);
154     }
155
156     @Test
157     public void assertCommandForColorTemperatureAbsChannel4500Kelvin() {
158         String expectedReply = "{\"ct\" : 222, \"transitiontime\" : 4}";
159         assertSendCommandForColorTempAbs(new DecimalType(4500), new HueLightState(), expectedReply);
160     }
161
162     @Test
163     public void assertCommandForColorTemperatureAbsChannel2000Kelvin() {
164         String expectedReply = "{\"ct\" : 500, \"transitiontime\" : 4}";
165         assertSendCommandForColorTempAbs(new DecimalType(2000), new HueLightState(), expectedReply);
166     }
167
168     @Test
169     public void assertPercentageValueOfColorTemperatureWhenCt153() {
170         int expectedReply = 0;
171         asserttoColorTemperaturePercentType(153, expectedReply);
172     }
173
174     @Test
175     public void assertPercentageValueOfColorTemperatureWhenCt326() {
176         int expectedReply = 50;
177         asserttoColorTemperaturePercentType(326, expectedReply);
178     }
179
180     @Test
181     public void assertPercentageValueOfColorTemperatureWhenCt500() {
182         int expectedReply = 100;
183         asserttoColorTemperaturePercentType(500, expectedReply);
184     }
185
186     @Test
187     public void assertCommandForColorChannel0Percent() {
188         String expectedReply = "{\"on\" : false, \"transitiontime\" : 4}";
189         assertSendCommandForColor(new PercentType(0), new HueLightState(), expectedReply);
190     }
191
192     @Test
193     public void assertCommandForColorChannel50Percent() {
194         String expectedReply = "{\"bri\" : 127, \"on\" : true, \"transitiontime\" : 4}";
195         assertSendCommandForColor(new PercentType(50), new HueLightState(), expectedReply);
196     }
197
198     @Test
199     public void assertCommandForColorChannel100Percent() {
200         String expectedReply = "{\"bri\" : 254, \"on\" : true, \"transitiontime\" : 4}";
201         assertSendCommandForColor(new PercentType(100), new HueLightState(), expectedReply);
202     }
203
204     @Test
205     public void assertCommandForColorChannelBlack() {
206         String expectedReply = "{\"on\" : false}";
207         assertSendCommandForColor(HSBType.BLACK, new HueLightState(), expectedReply);
208     }
209
210     @Test
211     public void assertCommandForColorChannelRed() {
212         String expectedReply = "{\"bri\" : 254, \"sat\" : 254, \"hue\" : 0, \"transitiontime\" : 4}";
213         assertSendCommandForColor(HSBType.RED, new HueLightState(), expectedReply);
214     }
215
216     @Test
217     public void assertCommandForColorChannelGreen() {
218         String expectedReply = "{\"bri\" : 254, \"sat\" : 254, \"hue\" : 21845, \"transitiontime\" : 4}";
219         assertSendCommandForColor(HSBType.GREEN, new HueLightState(), expectedReply);
220     }
221
222     @Test
223     public void assertCommandForColorChannelBlue() {
224         String expectedReply = "{\"bri\" : 254, \"sat\" : 254, \"hue\" : 43690, \"transitiontime\" : 4}";
225         assertSendCommandForColor(HSBType.BLUE, new HueLightState(), expectedReply);
226     }
227
228     @Test
229     public void assertCommandForColorChannelWhite() {
230         String expectedReply = "{\"bri\" : 254, \"sat\" : 0, \"hue\" : 0, \"transitiontime\" : 4}";
231         assertSendCommandForColor(HSBType.WHITE, new HueLightState(), expectedReply);
232     }
233
234     @Test
235     public void assertXYCommandForColorChannelBlack() {
236         String expectedReply = "{\"on\" : false}";
237         assertSendCommandForColor(HSBType.BLACK, new HueLightState().colormode(ColorMode.XY), expectedReply);
238     }
239
240     @Test
241     public void assertXYCommandForColorChannelWhite() {
242         String expectedReply = "{\"xy\" : [ 0.31271592 , 0.32900152 ], \"bri\" : 254, \"transitiontime\" : 4}";
243         assertSendCommandForColor(HSBType.WHITE, new HueLightState().colormode(ColorMode.XY), expectedReply);
244     }
245
246     @Test
247     public void assertXYCommandForColorChannelColorful() {
248         String expectedReply = "{\"xy\" : [ 0.16969365 , 0.12379659 ], \"bri\" : 127, \"transitiontime\" : 4}";
249         assertSendCommandForColor(new HSBType("220,90,50"), new HueLightState().colormode(ColorMode.XY), expectedReply);
250     }
251
252     @Test
253     public void asserCommandForColorChannelIncrease() {
254         HueLightState currentState = new HueLightState().bri(1).on(false);
255         String expectedReply = "{\"bri\" : 30, \"on\" : true, \"transitiontime\" : 4}";
256         assertSendCommandForColor(IncreaseDecreaseType.INCREASE, currentState, expectedReply);
257
258         currentState.bri(200).on(true);
259         expectedReply = "{\"bri\" : 230, \"transitiontime\" : 4}";
260         assertSendCommandForColor(IncreaseDecreaseType.INCREASE, currentState, expectedReply);
261
262         currentState.bri(230);
263         expectedReply = "{\"bri\" : 254, \"transitiontime\" : 4}";
264         assertSendCommandForColor(IncreaseDecreaseType.INCREASE, currentState, expectedReply);
265     }
266
267     @Test
268     public void asserCommandForColorChannelDecrease() {
269         HueLightState currentState = new HueLightState().bri(200);
270         String expectedReply = "{\"bri\" : 170, \"transitiontime\" : 4}";
271         assertSendCommandForColor(IncreaseDecreaseType.DECREASE, currentState, expectedReply);
272
273         currentState.bri(20);
274         expectedReply = "{\"on\" : false, \"transitiontime\" : 4}";
275         assertSendCommandForColor(IncreaseDecreaseType.DECREASE, currentState, expectedReply);
276     }
277
278     @Test
279     public void assertCommandForBrightnessChannel50Percent() {
280         HueLightState currentState = new HueLightState();
281         String expectedReply = "{\"bri\" : 127, \"on\" : true, \"transitiontime\" : 4}";
282         assertSendCommandForBrightness(new PercentType(50), currentState, expectedReply);
283     }
284
285     @Test
286     public void assertCommandForBrightnessChannelIncrease() {
287         HueLightState currentState = new HueLightState().bri(1).on(false);
288         String expectedReply = "{\"bri\" : 30, \"on\" : true, \"transitiontime\" : 4}";
289         assertSendCommandForBrightness(IncreaseDecreaseType.INCREASE, currentState, expectedReply);
290
291         currentState.bri(200).on(true);
292         expectedReply = "{\"bri\" : 230, \"transitiontime\" : 4}";
293         assertSendCommandForBrightness(IncreaseDecreaseType.INCREASE, currentState, expectedReply);
294
295         currentState.bri(230);
296         expectedReply = "{\"bri\" : 254, \"transitiontime\" : 4}";
297         assertSendCommandForBrightness(IncreaseDecreaseType.INCREASE, currentState, expectedReply);
298     }
299
300     @Test
301     public void assertCommandForBrightnessChannelDecrease() {
302         HueLightState currentState = new HueLightState().bri(200);
303         String expectedReply = "{\"bri\" : 170, \"transitiontime\" : 4}";
304         assertSendCommandForBrightness(IncreaseDecreaseType.DECREASE, currentState, expectedReply);
305
306         currentState.bri(20);
307         expectedReply = "{\"on\" : false, \"transitiontime\" : 4}";
308         assertSendCommandForBrightness(IncreaseDecreaseType.DECREASE, currentState, expectedReply);
309     }
310
311     @Test
312     public void assertCommandForBrightnessChannelOff() {
313         HueLightState currentState = new HueLightState();
314         String expectedReply = "{\"on\" : false}";
315         assertSendCommandForBrightness(OnOffType.OFF, currentState, expectedReply);
316     }
317
318     @Test
319     public void assertCommandForBrightnessChannelOn() {
320         HueLightState currentState = new HueLightState();
321         String expectedReply = "{\"on\" : true}";
322         assertSendCommandForBrightness(OnOffType.ON, currentState, expectedReply);
323     }
324
325     @Test
326     public void assertCommandForAlertChannel() {
327         HueLightState currentState = new HueLightState().alert("NONE");
328         String expectedReply = "{\"alert\" : \"none\"}";
329         assertSendCommandForAlert(new StringType("NONE"), currentState, expectedReply);
330
331         currentState.alert("NONE");
332         expectedReply = "{\"alert\" : \"select\"}";
333         assertSendCommandForAlert(new StringType("SELECT"), currentState, expectedReply);
334
335         currentState.alert("LSELECT");
336         expectedReply = "{\"alert\" : \"lselect\"}";
337         assertSendCommandForAlert(new StringType("LSELECT"), currentState, expectedReply);
338     }
339
340     @Test
341     public void assertCommandForEffectChannel() {
342         HueLightState currentState = new HueLightState().effect("ON");
343         String expectedReply = "{\"effect\" : \"colorloop\"}";
344         assertSendCommandForEffect(OnOffType.ON, currentState, expectedReply);
345
346         currentState.effect("OFF");
347         expectedReply = "{\"effect\" : \"none\"}";
348         assertSendCommandForEffect(OnOffType.OFF, currentState, expectedReply);
349     }
350
351     private void assertSendCommandForColorTempForPar16(Command command, HueLightState currentState,
352             String expectedReply) {
353         assertSendCommand(CHANNEL_COLORTEMPERATURE, command, currentState, expectedReply, OSRAM_MODEL_TYPE_ID, OSRAM);
354     }
355
356     private void assertSendCommandForBrightnessForPar16(Command command, HueLightState currentState,
357             String expectedReply) {
358         assertSendCommand(CHANNEL_BRIGHTNESS, command, currentState, expectedReply, OSRAM_MODEL_TYPE_ID, OSRAM);
359     }
360
361     private void assertSendCommandForColor(Command command, HueLightState currentState, String expectedReply) {
362         assertSendCommand(CHANNEL_COLOR, command, currentState, expectedReply);
363     }
364
365     private void assertSendCommandForColorTemp(Command command, HueLightState currentState, String expectedReply) {
366         assertSendCommand(CHANNEL_COLORTEMPERATURE, command, currentState, expectedReply);
367     }
368
369     private void assertSendCommandForColorTempAbs(Command command, HueLightState currentState, String expectedReply) {
370         assertSendCommand(CHANNEL_COLORTEMPERATURE_ABS, command, currentState, expectedReply);
371     }
372
373     private void asserttoColorTemperaturePercentType(int ctValue, int expectedPercent) {
374         int percent = (int) Math.round(((ctValue - MIN_COLOR_TEMPERATURE) * 100.0) / COLOR_TEMPERATURE_RANGE);
375         assertEquals(percent, expectedPercent);
376     }
377
378     private void assertSendCommandForBrightness(Command command, HueLightState currentState, String expectedReply) {
379         assertSendCommand(CHANNEL_BRIGHTNESS, command, currentState, expectedReply);
380     }
381
382     private void assertSendCommandForAlert(Command command, HueLightState currentState, String expectedReply) {
383         assertSendCommand(CHANNEL_ALERT, command, currentState, expectedReply);
384     }
385
386     private void assertSendCommandForEffect(Command command, HueLightState currentState, String expectedReply) {
387         assertSendCommand(CHANNEL_EFFECT, command, currentState, expectedReply);
388     }
389
390     private void assertSendCommand(String channel, Command command, HueLightState currentState, String expectedReply) {
391         assertSendCommand(channel, command, currentState, expectedReply, "LCT001", "Philips");
392     }
393
394     @SuppressWarnings("null")
395     private void assertSendCommand(String channel, Command command, HueLightState currentState, String expectedReply,
396             String expectedModel, String expectedVendor) {
397         FullLight light = gson.fromJson(currentState.toString(), FullConfig.class).getLights().get(0);
398
399         Bridge mockBridge = mock(Bridge.class);
400         when(mockBridge.getStatus()).thenReturn(ThingStatus.ONLINE);
401
402         Thing mockThing = mock(Thing.class);
403         when(mockThing.getConfiguration()).thenReturn(new Configuration(Map.of(LIGHT_ID, "1")));
404
405         HueClient mockClient = mock(HueClient.class);
406         when(mockClient.getLightById(any())).thenReturn(light);
407
408         long fadeTime = 400;
409
410         HueLightHandler hueLightHandler = new HueLightHandler(mockThing, mock(HueStateDescriptionProvider.class)) {
411             @Override
412             protected synchronized @Nullable HueClient getHueClient() {
413                 return mockClient;
414             }
415
416             @Override
417             protected @Nullable Bridge getBridge() {
418                 return mockBridge;
419             }
420         };
421         hueLightHandler.setCallback(mock(ThingHandlerCallback.class));
422         hueLightHandler.initialize();
423
424         verify(mockThing).setProperty(eq(Thing.PROPERTY_MODEL_ID), eq(expectedModel));
425         verify(mockThing).setProperty(eq(Thing.PROPERTY_VENDOR), eq(expectedVendor));
426
427         hueLightHandler.handleCommand(new ChannelUID(new ThingUID("hue::test"), channel), command);
428
429         ArgumentCaptor<StateUpdate> captorStateUpdate = ArgumentCaptor.forClass(StateUpdate.class);
430         verify(mockClient).updateLightState(any(LightStatusListener.class), any(FullLight.class),
431                 captorStateUpdate.capture(), eq(fadeTime));
432         assertJson(expectedReply, captorStateUpdate.getValue().toJson());
433     }
434
435     private void assertJson(String expected, String actual) {
436         JsonElement jsonExpected = JsonParser.parseString(expected);
437         JsonElement jsonActual = JsonParser.parseString(actual);
438         assertEquals(jsonExpected, jsonActual);
439     }
440 }