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