]> git.basschouten.com Git - openhab-addons.git/blob
883124450d0cb98a50aff1189cf667226c410ae9
[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.hdpowerview;
14
15 import static org.junit.jupiter.api.Assertions.*;
16 import static org.openhab.binding.hdpowerview.internal.api.CoordinateSystem.*;
17
18 import java.io.IOException;
19 import java.nio.file.Files;
20 import java.nio.file.Paths;
21 import java.util.List;
22 import java.util.regex.Pattern;
23 import java.util.stream.Collectors;
24
25 import org.eclipse.jdt.annotation.NonNullByDefault;
26 import org.eclipse.jetty.client.HttpClient;
27 import org.junit.jupiter.api.Test;
28 import org.openhab.binding.hdpowerview.internal.HDPowerViewWebTargets;
29 import org.openhab.binding.hdpowerview.internal.api.ShadePosition;
30 import org.openhab.binding.hdpowerview.internal.api.responses.SceneCollections;
31 import org.openhab.binding.hdpowerview.internal.api.responses.SceneCollections.SceneCollection;
32 import org.openhab.binding.hdpowerview.internal.api.responses.Scenes;
33 import org.openhab.binding.hdpowerview.internal.api.responses.Scenes.Scene;
34 import org.openhab.binding.hdpowerview.internal.api.responses.Shades;
35 import org.openhab.binding.hdpowerview.internal.api.responses.Shades.ShadeData;
36 import org.openhab.binding.hdpowerview.internal.database.ShadeCapabilitiesDatabase;
37 import org.openhab.binding.hdpowerview.internal.database.ShadeCapabilitiesDatabase.Capabilities;
38 import org.openhab.binding.hdpowerview.internal.exceptions.HubException;
39 import org.openhab.binding.hdpowerview.internal.exceptions.HubMaintenanceException;
40 import org.openhab.binding.hdpowerview.internal.exceptions.HubProcessingException;
41 import org.openhab.core.library.types.PercentType;
42 import org.openhab.core.types.State;
43 import org.openhab.core.types.UnDefType;
44
45 import com.google.gson.Gson;
46 import com.google.gson.JsonParseException;
47
48 /**
49  * Unit tests for HD PowerView binding.
50  *
51  * @author Andrew Fiddian-Green - Initial contribution
52  * @author Jacob Laursen - Add support for scene groups
53  */
54 @NonNullByDefault
55 public class HDPowerViewJUnitTests {
56
57     private static final Pattern VALID_IP_V4_ADDRESS = Pattern
58             .compile("\\b((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\\.|$)){4}\\b");
59
60     /*
61      * load a test JSON string from a file.
62      */
63     private String loadJson(String fileName) {
64         try {
65             return Files.readAllLines(Paths.get(String.format("src/test/resources/%s.json", fileName))).stream()
66                     .collect(Collectors.joining());
67         } catch (IOException e) {
68             fail(e.getMessage());
69         }
70         return "";
71     }
72
73     /**
74      * Run a series of ONLINE tests on the communication with a hub.
75      *
76      * @param hubIPAddress must be a valid hub IP address to run the
77      *            tests on; or an INVALID IP address to
78      *            suppress the tests
79      * @param allowShadeMovementCommands set to true if you accept that the tests
80      *            shall physically move the shades
81      */
82     @Test
83     public void testOnlineCommunication() {
84         /*
85          * NOTE: in order to actually run these tests you must have a hub physically
86          * available, and its IP address must be correctly configured in the
87          * "hubIPAddress" string constant e.g. "192.168.1.123"
88          */
89         String hubIPAddress = "192.168.1.xxx";
90
91         /*
92          * NOTE: set allowShadeMovementCommands = true if you accept physically moving
93          * the shades during these tests
94          */
95         boolean allowShadeMovementCommands = false;
96
97         if (VALID_IP_V4_ADDRESS.matcher(hubIPAddress).matches()) {
98             // ==== initialize stuff ====
99             HttpClient client = new HttpClient();
100             assertNotNull(client);
101
102             // ==== start the client ====
103             try {
104                 client.start();
105                 assertTrue(client.isStarted());
106             } catch (Exception e) {
107                 fail(e.getMessage());
108             }
109
110             HDPowerViewWebTargets webTargets = new HDPowerViewWebTargets(client, hubIPAddress);
111             assertNotNull(webTargets);
112
113             int shadeId = 0;
114             ShadePosition shadePos = null;
115             Shades shadesX = null;
116
117             // ==== get all shades ====
118             try {
119                 shadesX = webTargets.getShades();
120                 assertNotNull(shadesX);
121                 List<ShadeData> shadesData = shadesX.shadeData;
122                 assertNotNull(shadesData);
123
124                 if (shadesData != null) {
125                     assertTrue(!shadesData.isEmpty());
126                     ShadeData shadeData;
127                     shadeData = shadesData.get(0);
128                     assertNotNull(shadeData);
129                     assertTrue(shadeData.getName().length() > 0);
130                     shadePos = shadeData.positions;
131                     assertNotNull(shadePos);
132                     ShadeData shadeZero = shadesData.get(0);
133                     assertNotNull(shadeZero);
134                     shadeId = shadeZero.id;
135                     assertNotEquals(0, shadeId);
136
137                     for (ShadeData shadexData : shadesData) {
138                         String shadeName = shadexData.getName();
139                         assertNotNull(shadeName);
140                     }
141                 }
142             } catch (HubException e) {
143                 fail(e.getMessage());
144             }
145
146             // ==== get all scenes ====
147             int sceneId = 0;
148             try {
149                 Scenes scenes = webTargets.getScenes();
150                 assertNotNull(scenes);
151
152                 List<Scene> scenesData = scenes.sceneData;
153                 assertNotNull(scenesData);
154
155                 if (scenesData != null) {
156                     assertTrue(!scenesData.isEmpty());
157                     Scene sceneZero = scenesData.get(0);
158                     assertNotNull(sceneZero);
159                     sceneId = sceneZero.id;
160                     assertTrue(sceneId > 0);
161
162                     for (Scene scene : scenesData) {
163                         String sceneName = scene.getName();
164                         assertNotNull(sceneName);
165                     }
166                 }
167             } catch (HubException e) {
168                 fail(e.getMessage());
169             }
170
171             // ==== refresh a specific shade ====
172             ShadeData shadeData = null;
173             try {
174                 assertNotEquals(0, shadeId);
175                 shadeData = webTargets.refreshShadePosition(shadeId);
176             } catch (HubException e) {
177                 fail(e.getMessage());
178             }
179
180             // ==== move a specific shade ====
181             try {
182                 assertNotEquals(0, shadeId);
183
184                 if (shadeData != null) {
185                     ShadePosition positions = shadeData.positions;
186                     assertNotNull(positions);
187                     Integer capabilitiesValue = shadeData.capabilities;
188                     assertNotNull(capabilitiesValue);
189
190                     if (positions != null && capabilitiesValue != null) {
191                         Capabilities capabilities = new ShadeCapabilitiesDatabase()
192                                 .getCapabilities(capabilitiesValue.intValue());
193
194                         State pos = positions.getState(capabilities, PRIMARY_POSITION);
195                         assertEquals(PercentType.class, pos.getClass());
196
197                         int position = ((PercentType) pos).intValue();
198                         position = position + ((position <= 10) ? 5 : -5);
199
200                         ShadePosition targetPosition = new ShadePosition().setPosition(capabilities, PRIMARY_POSITION,
201                                 position);
202                         assertNotNull(targetPosition);
203
204                         if (allowShadeMovementCommands) {
205                             webTargets.moveShade(shadeId, targetPosition);
206
207                             ShadeData newData = webTargets.getShade(shadeId);
208                             ShadePosition actualPosition = newData.positions;
209                             assertNotNull(actualPosition);
210                             if (actualPosition != null) {
211                                 assertEquals(targetPosition.getState(capabilities, PRIMARY_POSITION),
212                                         actualPosition.getState(capabilities, PRIMARY_POSITION));
213                             }
214                         }
215                     }
216                 }
217             } catch (HubException e) {
218                 fail(e.getMessage());
219             }
220
221             // ==== activate a specific scene ====
222             if (allowShadeMovementCommands) {
223                 try {
224                     assertNotNull(sceneId);
225                     webTargets.activateScene(sceneId);
226                 } catch (HubProcessingException | HubMaintenanceException e) {
227                     fail(e.getMessage());
228                 }
229             }
230
231             // ==== test stop command ====
232             if (allowShadeMovementCommands) {
233                 try {
234                     assertNotNull(sceneId);
235                     webTargets.stopShade(shadeId);
236                 } catch (HubException e) {
237                     fail(e.getMessage());
238                 }
239             }
240
241             // ==== stop the client ====
242             if (client.isRunning()) {
243                 try {
244                     client.stop();
245                 } catch (Exception e) {
246                     fail(e.getMessage());
247                 }
248             }
249         }
250     }
251
252     /**
253      * Test generic JSON shades response.
254      */
255     @Test
256     public void shadeResponseIsParsedCorrectly() throws JsonParseException {
257         final Gson gson = new Gson();
258         Shades shades;
259         String json = loadJson("shades");
260         assertNotEquals("", json);
261         shades = gson.fromJson(json, Shades.class);
262         assertNotNull(shades);
263     }
264
265     /**
266      * Test generic JSON scene response.
267      */
268     @Test
269     public void sceneResponseIsParsedCorrectly() throws JsonParseException {
270         final Gson gson = new Gson();
271         String json = loadJson("scenes");
272         assertNotEquals("", json);
273
274         Scenes scenes = gson.fromJson(json, Scenes.class);
275         assertNotNull(scenes);
276         if (scenes != null) {
277             List<Scene> sceneData = scenes.sceneData;
278             assertNotNull(sceneData);
279             if (sceneData != null) {
280                 assertEquals(4, sceneData.size());
281                 Scene scene = sceneData.get(0);
282                 assertEquals("Door Open", scene.getName());
283                 assertEquals(18097, scene.id);
284             }
285         }
286     }
287
288     /**
289      * Test generic JSON scene collection response.
290      */
291     @Test
292     public void sceneCollectionResponseIsParsedCorrectly() throws JsonParseException {
293         final Gson gson = new Gson();
294         String json = loadJson("sceneCollections");
295         assertNotEquals("", json);
296
297         SceneCollections sceneCollections = gson.fromJson(json, SceneCollections.class);
298         assertNotNull(sceneCollections);
299
300         if (sceneCollections != null) {
301             List<SceneCollection> sceneCollectionData = sceneCollections.sceneCollectionData;
302             assertNotNull(sceneCollectionData);
303             if (sceneCollectionData != null) {
304                 assertEquals(1, sceneCollectionData.size());
305
306                 SceneCollection sceneCollection = sceneCollectionData.get(0);
307                 assertEquals("Børn op", sceneCollection.getName());
308                 assertEquals(27119, sceneCollection.id);
309             }
310         }
311     }
312
313     /**
314      * Test the JSON parsing for a duette top down bottom up shade.
315      */
316     @Test
317     public void duetteTopDownBottomUpShadeIsParsedCorrectly() throws JsonParseException {
318         final Gson gson = new Gson();
319         String json = loadJson("duette");
320         assertNotEquals("", json);
321
322         Shades shades = gson.fromJson(json, Shades.class);
323         assertNotNull(shades);
324         if (shades != null) {
325             List<ShadeData> shadesData = shades.shadeData;
326             assertNotNull(shadesData);
327
328             if (shadesData != null) {
329                 assertEquals(1, shadesData.size());
330                 ShadeData shadeData = shadesData.get(0);
331                 assertNotNull(shadeData);
332
333                 assertEquals("Gardin 1", shadeData.getName());
334                 assertEquals(63778, shadeData.id);
335
336                 ShadePosition shadePos = shadeData.positions;
337                 assertNotNull(shadePos);
338
339                 if (shadePos != null) {
340                     Integer capabilitiesValue = shadeData.capabilities;
341                     assertNotNull(capabilitiesValue);
342                     if (capabilitiesValue != null) {
343                         assertEquals(7, capabilitiesValue.intValue());
344                         ShadeCapabilitiesDatabase db = new ShadeCapabilitiesDatabase();
345                         Capabilities capabilities = db.getCapabilities(capabilitiesValue);
346
347                         State pos = shadePos.getState(capabilities, PRIMARY_POSITION);
348                         assertEquals(PercentType.class, pos.getClass());
349                         assertEquals(59, ((PercentType) pos).intValue());
350
351                         pos = shadePos.getState(capabilities, SECONDARY_POSITION);
352                         assertEquals(PercentType.class, pos.getClass());
353                         assertEquals(35, ((PercentType) pos).intValue());
354
355                         pos = shadePos.getState(capabilities, VANE_TILT_POSITION);
356                         assertEquals(UnDefType.class, pos.getClass());
357
358                         assertEquals(3, shadeData.batteryStatus);
359
360                         assertEquals(4, shadeData.signalStrength);
361
362                         assertEquals(8, shadeData.type);
363
364                         assertTrue(db.isTypeInDatabase(shadeData.type));
365                         assertTrue(db.isCapabilitiesInDatabase(capabilitiesValue.intValue()));
366
367                         assertEquals(db.getType(shadeData.type).getCapabilities(), capabilitiesValue.intValue());
368
369                         assertTrue(db.getCapabilities(capabilitiesValue.intValue()).supportsSecondary());
370                         assertNotEquals(db.getType(shadeData.type).getCapabilities(), capabilitiesValue.intValue() + 1);
371
372                         // ==== when changing position1, position2 value is not changed (vice-versa) ====
373                         ShadePosition shadePosition = shadeData.positions;
374                         assertNotNull(shadePosition);
375                         if (shadePosition != null) {
376                             // ==== position2 ====
377                             State position2Old = shadePosition.getState(capabilities, SECONDARY_POSITION);
378                             shadePosition.setPosition(capabilities, PRIMARY_POSITION, 99);
379                             State position2New = shadePosition.getState(capabilities, SECONDARY_POSITION);
380                             assertEquals(PercentType.class, position2Old.getClass());
381                             assertEquals(PercentType.class, position2New.getClass());
382                             assertEquals(((PercentType) position2Old).intValue(),
383                                     ((PercentType) position2New).intValue());
384
385                             // ==== position2 ====
386                             State position1Old = shadePosition.getState(capabilities, PRIMARY_POSITION);
387                             shadePosition.setPosition(capabilities, SECONDARY_POSITION, 99);
388                             State position1New = shadePosition.getState(capabilities, PRIMARY_POSITION);
389                             assertEquals(PercentType.class, position1Old.getClass());
390                             assertEquals(PercentType.class, position1New.getClass());
391                             assertEquals(((PercentType) position1Old).intValue(),
392                                     ((PercentType) position1New).intValue());
393                         }
394                     }
395                 }
396             }
397         }
398     }
399 }