2 * Copyright (c) 2010-2020 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.loxone.internal.controls;
15 import static org.hamcrest.CoreMatchers.*;
16 import static org.junit.Assert.*;
18 import java.io.BufferedReader;
19 import java.io.InputStream;
20 import java.io.InputStreamReader;
21 import java.math.BigDecimal;
22 import java.util.ArrayList;
23 import java.util.Collections;
24 import java.util.List;
25 import java.util.stream.Collectors;
27 import org.junit.Before;
28 import org.junit.Test;
29 import org.openhab.binding.loxone.internal.types.LxUuid;
30 import org.openhab.core.library.types.DecimalType;
31 import org.openhab.core.library.types.OnOffType;
32 import org.openhab.core.library.types.UpDownType;
33 import org.openhab.core.types.StateOption;
34 import org.openhab.core.types.UnDefType;
37 * Test class for (@link LxControlSwitch}
39 * @author Pawel Pieczul - initial contribution
42 public class LxControlLightControllerV2Test extends LxControlTest {
45 setupControl("1076668f-0101-7076-ffff403fb0c34b9e", "0b734138-03ac-03f0-ffff403fb0c34b9e",
46 "0b734138-033e-02d4-ffff403fb0c34b9e", "Lighting controller");
50 public void testControlCreation() {
51 testControlCreation(LxControlLightControllerV2.class, 1, 5, 1, 6, 4);
52 testSubControl(LxControlSwitch.class, "Overall Switch");
53 testSubControl(LxControlSwitch.class, "Hall Study Lights");
54 testSubControl(LxControlSwitch.class, "Roof Lights");
55 testSubControl(LxControlSwitch.class, "Hall Left Lights");
56 testSubControl(LxControlSwitch.class, "Hall Right Lights");
60 public void testChannels() {
61 testChannel("Number", Collections.singleton("Scene"));
65 public void testCommands() {
66 for (int i = 0; i < 20; i++) {
67 executeCommand(UpDownType.UP);
69 executeCommand(UpDownType.DOWN);
72 executeCommand(new DecimalType(1));
77 executeCommand(new DecimalType(0));
79 executeCommand(new DecimalType(1));
81 executeCommand(new DecimalType(2));
82 testAction("changeTo/2");
83 executeCommand(new DecimalType(3));
84 testAction("changeTo/3");
85 executeCommand(new DecimalType(4));
86 testAction("changeTo/4");
87 executeCommand(new DecimalType(5));
88 testAction("changeTo/5");
89 executeCommand(new DecimalType(6));
91 executeCommand(new DecimalType(777));
92 testAction("changeTo/777");
93 executeCommand(new DecimalType(778));
94 testAction("changeTo/778");
95 executeCommand(new DecimalType(779));
101 public void testMoodListChanges() {
102 for (int i = 0; i < 20; i++) {
110 public void testActiveMoodChanges() {
112 for (int i = 0; i < 10; i++) {
113 changeLoxoneState("activemoods", "[4]");
114 testActiveMoods(779, 4);
115 changeLoxoneState("activemoods", "[4,6]");
116 testActiveMoods(779, 4, 6);
117 changeLoxoneState("activemoods", "[4,6,7,8,5]");
118 testActiveMoods(779, 4, 6, 7, 8, 5);
119 changeLoxoneState("activemoods", "[4,6,7,8,5,777,778]");
120 testActiveMoods(779, 4, 6, 7, 8, 5, 777, 778);
121 changeLoxoneState("activemoods", "[6,8,777]");
122 testActiveMoods(779, 6, 8, 777);
123 changeLoxoneState("activemoods", "[779]");
124 testActiveMoods(779, 779);
125 changeLoxoneState("activemoods", "[1,2,3,500,900]");
126 testActiveMoods(779);
127 changeLoxoneState("activemoods", "[1,2,3,6,500,900]");
128 testActiveMoods(779, 6);
129 changeLoxoneState("activemoods", "[5]");
130 testActiveMoods(779, 5);
131 changeLoxoneState("activemoods", "[778]");
132 testActiveMoods(779, 778);
138 public void testMoodAddRemove() {
140 for (int i = 0; i < 10; i++) {
141 handler.extraControls.values().forEach(c -> {
142 LxControlMood m = (LxControlMood) c;
143 if (!m.getId().equals(778)) {
144 executeCommand(m, OnOffType.ON);
145 testAction("addMood/" + m.getId());
146 executeCommand(m, OnOffType.OFF);
147 testAction("removeMood/" + m.getId());
154 private void testActiveMoods(Integer offId, Integer... moods) {
155 List<Integer> ids = new ArrayList<>();
156 for (Integer id : moods) {
157 if (!offId.equals(id)) {
158 LxControlMood m = getMood(id);
159 testChannelState(m, OnOffType.ON);
163 handler.extraControls.values().stream()
164 .filter(c -> !ids.contains(((LxControlMood) c).getId()) && !((LxControlMood) c).getId().equals(offId))
165 .forEach(c -> testChannelState(c, OnOffType.OFF));
167 if (ids.size() == 1) {
168 testChannelState(new DecimalType(ids.get(0)));
170 testChannelState(UnDefType.UNDEF);
174 private void loadMoodList1() {
175 String list = loadMoodList("MoodList1.json");
176 changeLoxoneState("moodlist", list);
177 List<StateOption> options = new ArrayList<>();
178 options.add(new StateOption("2", "Side Lights"));
179 options.add(new StateOption("3", "Play Lights"));
180 options.add(new StateOption("4", "Study Only"));
181 options.add(new StateOption("5", "Low Lights"));
182 options.add(new StateOption("777", "Bright"));
183 options.add(new StateOption("778", "Off"));
184 testMoodList(options, 778);
187 private void loadMoodList2() {
188 String list = loadMoodList("MoodList2.json");
189 changeLoxoneState("moodlist", list);
190 List<StateOption> options = new ArrayList<>();
191 options.add(new StateOption("4", "Study Only Changed Name")); // changed name
192 options.add(new StateOption("5", "Low Lights")); // same as in list 1
193 options.add(new StateOption("6", "Play Lights")); // changed id
194 options.add(new StateOption("7", "New Mood 1"));
195 options.add(new StateOption("8", "New Mood 2"));
196 options.add(new StateOption("777", "Bright"));
197 options.add(new StateOption("778", "Off"));
198 options.add(new StateOption("779", "New Off"));
199 testMoodList(options, 779);
202 private LxControlMood getMood(Integer id) {
203 LxControl ctrl = handler.extraControls.get(new LxUuid("1076668f-0101-7076-ffff403fb0c34b9e-M" + id));
205 assertThat(ctrl, is(instanceOf(LxControlMood.class)));
206 return (LxControlMood) ctrl;
209 private void clearMoodList() {
210 changeLoxoneState("moodlist", "[]");
211 List<StateOption> options = new ArrayList<>();
212 testMoodList(options, 0);
215 private void testMoodList(List<StateOption> options, Integer offId) {
216 assertEquals(options.size(), handler.extraControls.size());
217 if (options.isEmpty()) {
222 for (StateOption o : options) {
223 testMood(o.getLabel(), o.getValue(), o.getValue().equals(offId.toString()));
224 Integer id = Integer.parseInt(o.getValue());
226 if (min == null || id < min) {
229 if (max == null || id > max) {
235 testChannel("Number", null, new BigDecimal(min), new BigDecimal(max), BigDecimal.ONE, null, false, options,
236 Collections.singleton("Scene"));
239 private void testMood(String name, String id, boolean isStatic) {
240 LxControlMood mood = getMood(Integer.parseInt(id));
241 assertEquals(new LxUuid("0b734138-03ac-03f0-ffff403fb0c34b9e"), mood.getRoom().getUuid());
242 assertEquals(new LxUuid("0b734138-033e-02d4-ffff403fb0c34b9e"), mood.getCategory().getUuid());
243 assertEquals(name, mood.getName());
244 assertEquals(id, mood.getId().toString());
246 assertEquals(0, mood.getChannels().size());
248 assertEquals(1, mood.getChannels().size());
249 testChannel(mood, "Switch", Collections.singleton("Lighting"));
253 private String loadMoodList(String name) {
254 InputStream stream = LxControlLightControllerV2Test.class.getResourceAsStream(name);
255 assertNotNull(stream);
256 BufferedReader reader = new BufferedReader(new InputStreamReader(stream));
257 assertNotNull(reader);
258 String msg = reader.lines().collect(Collectors.joining(System.lineSeparator()));
260 // mood list comes as a single line JSON from Loxone Miniserver
261 msg = msg.replaceAll("[\\t+\\n+]", "");