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