]> git.basschouten.com Git - openhab-addons.git/blob
0422c1f7af4834efabeb766b3b8947da8c46a258
[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.neohub.test;
14
15 import static org.junit.jupiter.api.Assertions.*;
16 import static org.openhab.binding.neohub.internal.NeoHubBindingConstants.*;
17
18 import java.io.BufferedReader;
19 import java.io.FileReader;
20 import java.io.IOException;
21 import java.math.BigDecimal;
22 import java.time.Instant;
23 import java.util.regex.Pattern;
24
25 import org.eclipse.jdt.annotation.NonNullByDefault;
26 import org.junit.jupiter.api.Test;
27 import org.openhab.binding.neohub.internal.NeoHubAbstractDeviceData;
28 import org.openhab.binding.neohub.internal.NeoHubAbstractDeviceData.AbstractRecord;
29 import org.openhab.binding.neohub.internal.NeoHubGetEngineersData;
30 import org.openhab.binding.neohub.internal.NeoHubInfoResponse;
31 import org.openhab.binding.neohub.internal.NeoHubInfoResponse.InfoRecord;
32 import org.openhab.binding.neohub.internal.NeoHubLiveDeviceData;
33 import org.openhab.binding.neohub.internal.NeoHubReadDcbResponse;
34 import org.openhab.binding.neohub.internal.NeoHubSocket;
35 import org.openhab.core.library.unit.ImperialUnits;
36 import org.openhab.core.library.unit.SIUnits;
37
38 /**
39  * The {@link NeoHubTestData} class defines common constants, which are used
40  * across the whole binding.
41  *
42  * @author Andrew Fiddian-Green - Initial contribution
43  */
44 @NonNullByDefault
45 public class NeoHubTestData {
46
47     /*
48      * to actually run tests on a physical device you must have a hub physically available, and its IP address must be
49      * correctly configured in the "hubIPAddress" string constant e.g. "192.168.1.123"
50      * note: only run the test if such a device is actually available
51      */
52     private static final String hubIpAddress = "192.168.1.xxx";
53
54     private static final Pattern VALID_IP_V4_ADDRESS = Pattern
55             .compile("\\b((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\\.|$)){4}\\b");
56
57     /*
58      * Load the test JSON payload string from a file
59      */
60     private String load(String fileName) {
61         try (FileReader file = new FileReader(String.format("src/test/resources/%s.json", fileName));
62                 BufferedReader reader = new BufferedReader(file)) {
63             StringBuilder builder = new StringBuilder();
64             String line;
65             while ((line = reader.readLine()) != null) {
66                 builder.append(line).append("\n");
67             }
68             return builder.toString();
69         } catch (IOException e) {
70             fail(e.getMessage());
71         }
72         return "";
73     }
74
75     /*
76      * Test an INFO JSON response string as produced by older firmware versions
77      */
78     @SuppressWarnings("null")
79     @Test
80     public void testInfoJsonOld() {
81         // load INFO JSON response string in old JSON format
82         NeoHubAbstractDeviceData infoResponse = NeoHubInfoResponse.createDeviceData(load("info_old"));
83         assertNotNull(infoResponse);
84
85         // missing device
86         AbstractRecord device = infoResponse.getDeviceRecord("Aardvark");
87         assertNull(device);
88
89         // existing type 12 thermostat device
90         device = infoResponse.getDeviceRecord("Dining Room");
91         assertNotNull(device);
92         assertEquals("Dining Room", device.getDeviceName());
93         assertEquals(new BigDecimal("22.0"), device.getTargetTemperature());
94         assertEquals(new BigDecimal("22.2"), device.getActualTemperature());
95         assertEquals(new BigDecimal("23"), device.getFloorTemperature());
96         assertTrue(device instanceof InfoRecord);
97         assertEquals(12, ((InfoRecord) device).getDeviceType());
98         assertFalse(device.isStandby());
99         assertFalse(device.isHeating());
100         assertFalse(device.isPreHeating());
101         assertFalse(device.isTimerOn());
102         assertFalse(device.offline());
103         assertFalse(device.stateManual());
104         assertTrue(device.stateAuto());
105         assertFalse(device.isWindowOpen());
106         assertFalse(device.isBatteryLow());
107
108         // existing type 6 plug device (MANUAL OFF)
109         device = infoResponse.getDeviceRecord("Plug South");
110         assertNotNull(device);
111         assertEquals("Plug South", device.getDeviceName());
112         assertTrue(device instanceof InfoRecord);
113         assertEquals(6, ((InfoRecord) device).getDeviceType());
114         assertFalse(device.isTimerOn());
115         assertTrue(device.stateManual());
116
117         // existing type 6 plug device (MANUAL ON)
118         device = infoResponse.getDeviceRecord("Plug North");
119         assertNotNull(device);
120         assertEquals("Plug North", device.getDeviceName());
121         assertTrue(device instanceof InfoRecord);
122         assertEquals(6, ((InfoRecord) device).getDeviceType());
123         assertTrue(device.isTimerOn());
124         assertTrue(device.stateManual());
125
126         // existing type 6 plug device (AUTO OFF)
127         device = infoResponse.getDeviceRecord("Watering System");
128         assertNotNull(device);
129         assertEquals("Watering System", device.getDeviceName());
130         assertTrue(device instanceof InfoRecord);
131         assertEquals(6, ((InfoRecord) device).getDeviceType());
132         assertFalse(device.isTimerOn());
133         assertFalse(device.stateManual());
134     }
135
136     /*
137      * Test an INFO JSON response string as produced by newer firmware versions
138      */
139     @SuppressWarnings("null")
140     @Test
141     public void testInfoJsonNew() {
142         // load INFO JSON response string in new JSON format
143         NeoHubAbstractDeviceData infoResponse = NeoHubInfoResponse.createDeviceData(load("info_new"));
144         assertNotNull(infoResponse);
145
146         // existing device (new JSON format)
147         AbstractRecord device = infoResponse.getDeviceRecord("Dining Room");
148         assertNotNull(device);
149         assertEquals("Dining Room", device.getDeviceName());
150         assertFalse(device.offline());
151         assertFalse(device.isWindowOpen());
152
153         // existing repeater device
154         device = infoResponse.getDeviceRecord("repeaternode54473");
155         assertNotNull(device);
156         assertEquals("repeaternode54473", device.getDeviceName());
157         assertEquals(new BigDecimal("127"), device.getFloorTemperature());
158         assertEquals(new BigDecimal("255.255"), device.getActualTemperature());
159     }
160
161     /*
162      * Test for a READ_DCB JSON string that has valid CORF C response
163      */
164     @SuppressWarnings("null")
165     @Test
166     public void testReadDcbJson() {
167         // load READ_DCB JSON response string with valid CORF C response
168         NeoHubReadDcbResponse dcbResponse = NeoHubReadDcbResponse.createSystemData(load("dcb_celsius"));
169         assertNotNull(dcbResponse);
170         assertEquals(SIUnits.CELSIUS, dcbResponse.getTemperatureUnit());
171         assertEquals("2134", dcbResponse.getFirmwareVersion());
172
173         // load READ_DCB JSON response string with valid CORF F response
174         dcbResponse = NeoHubReadDcbResponse.createSystemData(load("dcb_fahrenheit"));
175         assertNotNull(dcbResponse);
176         assertEquals(ImperialUnits.FAHRENHEIT, dcbResponse.getTemperatureUnit());
177
178         // load READ_DCB JSON response string with missing CORF element
179         dcbResponse = NeoHubReadDcbResponse.createSystemData(load("dcb_corf_missing"));
180         assertNotNull(dcbResponse);
181         assertEquals(SIUnits.CELSIUS, dcbResponse.getTemperatureUnit());
182
183         // load READ_DCB JSON response string where CORF element is an empty string
184         dcbResponse = NeoHubReadDcbResponse.createSystemData(load("dcb_corf_empty"));
185         assertNotNull(dcbResponse);
186         assertEquals(SIUnits.CELSIUS, dcbResponse.getTemperatureUnit());
187     }
188
189     /*
190      * Test an INFO JSON string that has a door contact and a temperature sensor
191      */
192     @SuppressWarnings("null")
193     @Test
194     public void testInfoJsonWithSensors() {
195         /*
196          * load an INFO JSON response string that has a closed door contact and a
197          * temperature sensor
198          */
199         // save("info_sensors_closed", NEOHUB_JSON_TEST_STRING_INFO_SENSORS_CLOSED);
200         NeoHubAbstractDeviceData infoResponse = NeoHubInfoResponse.createDeviceData(load("info_sensors_closed"));
201         assertNotNull(infoResponse);
202
203         // existing contact device type 5 (CLOSED)
204         AbstractRecord device = infoResponse.getDeviceRecord("Back Door");
205         assertNotNull(device);
206         assertEquals("Back Door", device.getDeviceName());
207         assertTrue(device instanceof InfoRecord);
208         assertEquals(5, ((InfoRecord) device).getDeviceType());
209         assertFalse(device.isWindowOpen());
210         assertFalse(device.isBatteryLow());
211
212         // existing temperature sensor type 14
213         device = infoResponse.getDeviceRecord("Master Bedroom");
214         assertNotNull(device);
215         assertEquals("Master Bedroom", device.getDeviceName());
216         assertTrue(device instanceof InfoRecord);
217         assertEquals(14, ((InfoRecord) device).getDeviceType());
218         assertEquals(new BigDecimal("19.5"), device.getActualTemperature());
219
220         // existing thermostat type 1
221         device = infoResponse.getDeviceRecord("Living Room Floor");
222         assertNotNull(device);
223         assertEquals("Living Room Floor", device.getDeviceName());
224         assertTrue(device instanceof InfoRecord);
225         assertEquals(1, ((InfoRecord) device).getDeviceType());
226         assertEquals(new BigDecimal("19.8"), device.getActualTemperature());
227
228         // load an INFO JSON response string that has an open door contact
229         // save("info_sensors_open", NEOHUB_JSON_TEST_STRING_INFO_SENSORS_OPEN);
230         infoResponse = NeoHubInfoResponse.createDeviceData(load("info_sensors_open"));
231         assertNotNull(infoResponse);
232
233         // existing contact device type 5 (OPEN)
234         device = infoResponse.getDeviceRecord("Back Door");
235         assertNotNull(device);
236         assertEquals("Back Door", device.getDeviceName());
237         assertTrue(device instanceof InfoRecord);
238         assertEquals(5, ((InfoRecord) device).getDeviceType());
239         assertTrue(device.isWindowOpen());
240         assertTrue(device.isBatteryLow());
241     }
242
243     /*
244      * From NeoHub rev2.6 onwards the READ_DCB command is "deprecated" so we can
245      * also test the replacement GET_SYSTEM command (valid CORF response)
246      */
247     @SuppressWarnings("null")
248     @Test
249     public void testGetSystemJson() {
250         // load GET_SYSTEM JSON response string
251         NeoHubReadDcbResponse dcbResponse;
252         dcbResponse = NeoHubReadDcbResponse.createSystemData(load("system"));
253         assertNotNull(dcbResponse);
254         assertEquals(SIUnits.CELSIUS, dcbResponse.getTemperatureUnit());
255         assertEquals("2134", dcbResponse.getFirmwareVersion());
256     }
257
258     /*
259      * From NeoHub rev2.6 onwards the INFO command is "deprecated" so we must test
260      * the replacement GET_LIVE_DATA command
261      */
262     @SuppressWarnings("null")
263     @Test
264     public void testGetLiveDataJson() {
265         // load GET_LIVE_DATA JSON response string
266         NeoHubLiveDeviceData liveDataResponse = NeoHubLiveDeviceData.createDeviceData(load("live_data"));
267         assertNotNull(liveDataResponse);
268
269         // test the time stamps
270         assertEquals(1588494785, liveDataResponse.getTimestampEngineers());
271         assertEquals(0, liveDataResponse.getTimestampSystem());
272
273         // missing device
274         AbstractRecord device = liveDataResponse.getDeviceRecord("Aardvark");
275         assertNull(device);
276
277         // test an existing thermostat device
278         device = liveDataResponse.getDeviceRecord("Dining Room");
279         assertNotNull(device);
280         assertEquals("Dining Room", device.getDeviceName());
281         assertEquals(new BigDecimal("22.0"), device.getTargetTemperature());
282         assertEquals(new BigDecimal("22.2"), device.getActualTemperature());
283         assertEquals(new BigDecimal("20.50"), device.getFloorTemperature());
284         assertFalse(device.isStandby());
285         assertFalse(device.isHeating());
286         assertFalse(device.isPreHeating());
287         assertFalse(device.isTimerOn());
288         assertFalse(device.offline());
289         assertFalse(device.stateManual());
290         assertTrue(device.stateAuto());
291         assertFalse(device.isWindowOpen());
292         assertFalse(device.isBatteryLow());
293
294         // test a plug device (MANUAL OFF)
295         device = liveDataResponse.getDeviceRecord("Living Room South");
296         assertNotNull(device);
297         assertEquals("Living Room South", device.getDeviceName());
298         assertFalse(device.isTimerOn());
299         assertTrue(device.stateManual());
300
301         // test a plug device (MANUAL ON)
302         device = liveDataResponse.getDeviceRecord("Living Room North");
303         assertNotNull(device);
304         assertEquals("Living Room North", device.getDeviceName());
305         assertTrue(device.isTimerOn());
306         assertTrue(device.stateManual());
307
308         // test a plug device (AUTO OFF)
309         device = liveDataResponse.getDeviceRecord("Green Wall Watering");
310         assertNotNull(device);
311         assertEquals("Green Wall Watering", device.getDeviceName());
312         assertFalse(device.isTimerOn());
313         assertFalse(device.stateManual());
314
315         // test a device that is offline
316         device = liveDataResponse.getDeviceRecord("Shower Room");
317         assertNotNull(device);
318         assertEquals("Shower Room", device.getDeviceName());
319         assertTrue(device.offline());
320
321         // test a device with a low battery
322         device = liveDataResponse.getDeviceRecord("Conservatory");
323         assertNotNull(device);
324         assertEquals("Conservatory", device.getDeviceName());
325         assertTrue(device.isBatteryLow());
326
327         // test a device with an open window alarm
328         device = liveDataResponse.getDeviceRecord("Door Contact");
329         assertNotNull(device);
330         assertEquals("Door Contact", device.getDeviceName());
331         assertTrue(device.isWindowOpen());
332
333         // test a wireless temperature sensor
334         device = liveDataResponse.getDeviceRecord("Room Sensor");
335         assertNotNull(device);
336         assertEquals("Room Sensor", device.getDeviceName());
337         assertEquals(new BigDecimal("21.5"), device.getActualTemperature());
338
339         // test a repeater node
340         device = liveDataResponse.getDeviceRecord("repeaternode54473");
341         assertNotNull(device);
342         assertEquals("repeaternode54473", device.getDeviceName());
343         assertTrue(MATCHER_HEATMISER_REPEATER.matcher(device.getDeviceName()).matches());
344     }
345
346     /*
347      * From NeoHub rev2.6 onwards the INFO command is "deprecated" and the DEVICE_ID
348      * element is not returned in the GET_LIVE_DATA call so we must test the
349      * replacement GET_ENGINEERS command
350      */
351     @SuppressWarnings("null")
352     @Test
353     public void testGetEngineersJson() {
354         // load GET_ENGINEERS JSON response string
355         NeoHubGetEngineersData engResponse = NeoHubGetEngineersData.createEngineersData(load("engineers"));
356         assertNotNull(engResponse);
357
358         // test device ID (type 12 thermostat device)
359         assertEquals(12, engResponse.getDeviceType("Dining Room"));
360
361         // test device ID (type 6 plug device)
362         assertEquals(6, engResponse.getDeviceType("Living Room South"));
363     }
364
365     /*
366      * send JSON request to the socket and retrieve JSON response
367      */
368     private String testCommunicationInner(String requestJson) {
369         NeoHubSocket socket = new NeoHubSocket(hubIpAddress, 4242, 5);
370         String responseJson = "";
371         try {
372             responseJson = socket.sendMessage(requestJson);
373         } catch (Exception e) {
374             assertTrue(false);
375         }
376         return responseJson;
377     }
378
379     /*
380      * Test the communications
381      */
382     @SuppressWarnings("null")
383     @Test
384     public void testCommunications() {
385         /*
386          * tests the actual communication with a real physical device on 'hubIpAddress'
387          * note: only run the test if such a device is actually available
388          */
389         if (!VALID_IP_V4_ADDRESS.matcher(hubIpAddress).matches()) {
390             return;
391         }
392
393         String responseJson = testCommunicationInner(CMD_CODE_INFO);
394         assertFalse(responseJson.isEmpty());
395
396         responseJson = testCommunicationInner(CMD_CODE_READ_DCB);
397         assertFalse(responseJson.isEmpty());
398
399         NeoHubReadDcbResponse dcbResponse = NeoHubReadDcbResponse.createSystemData(responseJson);
400         assertNotNull(dcbResponse);
401
402         long timeStamp = dcbResponse.timeStamp;
403         assertEquals(Instant.now().getEpochSecond(), timeStamp, 1);
404
405         responseJson = testCommunicationInner(CMD_CODE_GET_LIVE_DATA);
406         assertFalse(responseJson.isEmpty());
407
408         NeoHubLiveDeviceData liveDataResponse = NeoHubLiveDeviceData.createDeviceData(responseJson);
409         assertNotNull(liveDataResponse);
410
411         assertTrue(timeStamp > liveDataResponse.getTimestampEngineers());
412         assertTrue(timeStamp > liveDataResponse.getTimestampSystem());
413
414         responseJson = testCommunicationInner(CMD_CODE_GET_ENGINEERS);
415         assertFalse(responseJson.isEmpty());
416
417         responseJson = testCommunicationInner(CMD_CODE_GET_SYSTEM);
418         assertFalse(responseJson.isEmpty());
419
420         responseJson = testCommunicationInner(String.format(CMD_CODE_TEMP, "20", "Hallway"));
421         assertFalse(responseJson.isEmpty());
422     }
423 }