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.neohub.test;
15 import static org.junit.Assert.assertEquals;
16 import static org.junit.Assert.assertFalse;
17 import static org.junit.Assert.assertNotNull;
18 import static org.junit.Assert.assertNull;
19 import static org.junit.Assert.assertTrue;
20 import static org.junit.Assert.fail;
21 import static org.openhab.binding.neohub.internal.NeoHubBindingConstants.*;
23 import java.io.BufferedReader;
24 import java.io.FileReader;
25 import java.io.IOException;
26 import java.math.BigDecimal;
27 import java.time.Instant;
29 import org.eclipse.jdt.annotation.NonNullByDefault;
30 import org.junit.Test;
31 import org.openhab.binding.neohub.internal.NeoHubAbstractDeviceData;
32 import org.openhab.binding.neohub.internal.NeoHubAbstractDeviceData.AbstractRecord;
33 import org.openhab.binding.neohub.internal.NeoHubGetEngineersData;
34 import org.openhab.binding.neohub.internal.NeoHubInfoResponse;
35 import org.openhab.binding.neohub.internal.NeoHubInfoResponse.InfoRecord;
36 import org.openhab.binding.neohub.internal.NeoHubLiveDeviceData;
37 import org.openhab.binding.neohub.internal.NeoHubReadDcbResponse;
38 import org.openhab.binding.neohub.internal.NeoHubSocket;
39 import org.openhab.core.library.unit.ImperialUnits;
40 import org.openhab.core.library.unit.SIUnits;
43 * The {@link NeoHubTestData} class defines common constants, which are used
44 * across the whole binding.
46 * @author Andrew Fiddian-Green - Initial contribution
49 public class NeoHubTestData {
52 * Load the test JSON payload string from a file
54 private String load(String fileName) {
55 try (FileReader file = new FileReader(String.format("src/test/resources/%s.json", fileName));
56 BufferedReader reader = new BufferedReader(file)) {
57 StringBuilder builder = new StringBuilder();
59 while ((line = reader.readLine()) != null) {
60 builder.append(line).append("\n");
62 return builder.toString();
63 } catch (IOException e) {
70 * Test an INFO JSON response string as produced by older firmware versions
73 public void testInfoJsonOld() {
74 // load INFO JSON response string in old JSON format
75 NeoHubAbstractDeviceData infoResponse = NeoHubInfoResponse.createDeviceData(load("info_old"));
76 assertNotNull(infoResponse);
79 AbstractRecord device = infoResponse.getDeviceRecord("Aardvark");
82 // existing type 12 thermostat device
83 device = infoResponse.getDeviceRecord("Dining Room");
84 assertNotNull(device);
85 assertEquals("Dining Room", device.getDeviceName());
86 assertEquals(new BigDecimal("22.0"), device.getTargetTemperature());
87 assertEquals(new BigDecimal("22.2"), device.getActualTemperature());
88 assertEquals(new BigDecimal("23"), device.getFloorTemperature());
89 assertTrue(device instanceof InfoRecord);
90 assertEquals(12, ((InfoRecord) device).getDeviceType());
91 assertFalse(device.isStandby());
92 assertFalse(device.isHeating());
93 assertFalse(device.isPreHeating());
94 assertFalse(device.isTimerOn());
95 assertFalse(device.offline());
96 assertFalse(device.stateManual());
97 assertTrue(device.stateAuto());
98 assertFalse(device.isWindowOpen());
99 assertFalse(device.isBatteryLow());
101 // existing type 6 plug device (MANUAL OFF)
102 device = infoResponse.getDeviceRecord("Plug South");
103 assertNotNull(device);
104 assertEquals("Plug South", device.getDeviceName());
105 assertTrue(device instanceof InfoRecord);
106 assertEquals(6, ((InfoRecord) device).getDeviceType());
107 assertFalse(device.isTimerOn());
108 assertTrue(device.stateManual());
110 // existing type 6 plug device (MANUAL ON)
111 device = infoResponse.getDeviceRecord("Plug North");
112 assertNotNull(device);
113 assertEquals("Plug North", device.getDeviceName());
114 assertTrue(device instanceof InfoRecord);
115 assertEquals(6, ((InfoRecord) device).getDeviceType());
116 assertTrue(device.isTimerOn());
117 assertTrue(device.stateManual());
119 // existing type 6 plug device (AUTO OFF)
120 device = infoResponse.getDeviceRecord("Watering System");
121 assertNotNull(device);
122 assertEquals("Watering System", device.getDeviceName());
123 assertTrue(device instanceof InfoRecord);
124 assertEquals(6, ((InfoRecord) device).getDeviceType());
125 assertFalse(device.isTimerOn());
126 assertFalse(device.stateManual());
130 * Test an INFO JSON response string as produced by newer firmware versions
133 public void testInfoJsonNew() {
134 // load INFO JSON response string in new JSON format
135 NeoHubAbstractDeviceData infoResponse = NeoHubInfoResponse.createDeviceData(load("info_new"));
136 assertNotNull(infoResponse);
138 // existing device (new JSON format)
139 AbstractRecord device = infoResponse.getDeviceRecord("Dining Room");
140 assertNotNull(device);
141 assertEquals("Dining Room", device.getDeviceName());
142 assertFalse(device.offline());
143 assertFalse(device.isWindowOpen());
145 // existing repeater device
146 device = infoResponse.getDeviceRecord("repeaternode54473");
147 assertNotNull(device);
148 assertEquals("repeaternode54473", device.getDeviceName());
149 assertEquals(new BigDecimal("127"), device.getFloorTemperature());
150 assertEquals(new BigDecimal("255.255"), device.getActualTemperature());
154 * Test for a READ_DCB JSON string that has valid CORF C response
157 public void testReadDcbJson() {
158 // load READ_DCB JSON response string with valid CORF C response
159 NeoHubReadDcbResponse dcbResponse = NeoHubReadDcbResponse.createSystemData(load("dcb_celsius"));
160 assertNotNull(dcbResponse);
161 assertEquals(SIUnits.CELSIUS, dcbResponse.getTemperatureUnit());
163 // load READ_DCB JSON response string with valid CORF F response
164 dcbResponse = NeoHubReadDcbResponse.createSystemData(load("dcb_fahrenheit"));
165 assertNotNull(dcbResponse);
166 assertEquals(ImperialUnits.FAHRENHEIT, dcbResponse.getTemperatureUnit());
168 // load READ_DCB JSON response string with missing CORF element
169 dcbResponse = NeoHubReadDcbResponse.createSystemData(load("dcb_corf_missing"));
170 assertNotNull(dcbResponse);
171 assertEquals(SIUnits.CELSIUS, dcbResponse.getTemperatureUnit());
173 // load READ_DCB JSON response string where CORF element is an empty string
174 dcbResponse = NeoHubReadDcbResponse.createSystemData(load("dcb_corf_empty"));
175 assertNotNull(dcbResponse);
176 assertEquals(SIUnits.CELSIUS, dcbResponse.getTemperatureUnit());
180 * Test an INFO JSON string that has a door contact and a temperature sensor
183 public void testInfoJsonWithSensors() {
185 * load an INFO JSON response string that has a closed door contact and a
188 // save("info_sensors_closed", NEOHUB_JSON_TEST_STRING_INFO_SENSORS_CLOSED);
189 NeoHubAbstractDeviceData infoResponse = NeoHubInfoResponse.createDeviceData(load("info_sensors_closed"));
190 assertNotNull(infoResponse);
192 // existing contact device type 5 (CLOSED)
193 AbstractRecord device = infoResponse.getDeviceRecord("Back Door");
194 assertNotNull(device);
195 assertEquals("Back Door", device.getDeviceName());
196 assertTrue(device instanceof InfoRecord);
197 assertEquals(5, ((InfoRecord) device).getDeviceType());
198 assertFalse(device.isWindowOpen());
199 assertFalse(device.isBatteryLow());
201 // existing temperature sensor type 14
202 device = infoResponse.getDeviceRecord("Master Bedroom");
203 assertNotNull(device);
204 assertEquals("Master Bedroom", device.getDeviceName());
205 assertTrue(device instanceof InfoRecord);
206 assertEquals(14, ((InfoRecord) device).getDeviceType());
207 assertEquals(new BigDecimal("19.5"), device.getActualTemperature());
209 // existing thermostat type 1
210 device = infoResponse.getDeviceRecord("Living Room Floor");
211 assertNotNull(device);
212 assertEquals("Living Room Floor", device.getDeviceName());
213 assertTrue(device instanceof InfoRecord);
214 assertEquals(1, ((InfoRecord) device).getDeviceType());
215 assertEquals(new BigDecimal("19.8"), device.getActualTemperature());
217 // load an INFO JSON response string that has an open door contact
218 // save("info_sensors_open", NEOHUB_JSON_TEST_STRING_INFO_SENSORS_OPEN);
219 infoResponse = NeoHubInfoResponse.createDeviceData(load("info_sensors_open"));
220 assertNotNull(infoResponse);
222 // existing contact device type 5 (OPEN)
223 device = infoResponse.getDeviceRecord("Back Door");
224 assertNotNull(device);
225 assertEquals("Back Door", device.getDeviceName());
226 assertTrue(device instanceof InfoRecord);
227 assertEquals(5, ((InfoRecord) device).getDeviceType());
228 assertTrue(device.isWindowOpen());
229 assertTrue(device.isBatteryLow());
233 * From NeoHub rev2.6 onwards the READ_DCB command is "deprecated" so we can
234 * also test the replacement GET_SYSTEM command (valid CORF response)
237 public void testGetSystemJson() {
238 // load GET_SYSTEM JSON response string
239 NeoHubReadDcbResponse dcbResponse;
240 dcbResponse = NeoHubReadDcbResponse.createSystemData(load("system"));
241 assertNotNull(dcbResponse);
242 assertEquals(SIUnits.CELSIUS, dcbResponse.getTemperatureUnit());
246 * From NeoHub rev2.6 onwards the INFO command is "deprecated" so we must test
247 * the replacement GET_LIVE_DATA command
250 public void testGetLiveDataJson() {
251 // load GET_LIVE_DATA JSON response string
252 NeoHubLiveDeviceData liveDataResponse = NeoHubLiveDeviceData.createDeviceData(load("live_data"));
253 assertNotNull(liveDataResponse);
255 // test the time stamps
256 assertEquals(1588494785, liveDataResponse.getTimestampEngineers());
257 assertEquals(0, liveDataResponse.getTimestampSystem());
260 AbstractRecord device = liveDataResponse.getDeviceRecord("Aardvark");
263 // test an existing thermostat device
264 device = liveDataResponse.getDeviceRecord("Dining Room");
265 assertNotNull(device);
266 assertEquals("Dining Room", device.getDeviceName());
267 assertEquals(new BigDecimal("22.0"), device.getTargetTemperature());
268 assertEquals(new BigDecimal("22.2"), device.getActualTemperature());
269 assertEquals(new BigDecimal("20.50"), device.getFloorTemperature());
270 assertFalse(device.isStandby());
271 assertFalse(device.isHeating());
272 assertFalse(device.isPreHeating());
273 assertFalse(device.isTimerOn());
274 assertFalse(device.offline());
275 assertFalse(device.stateManual());
276 assertTrue(device.stateAuto());
277 assertFalse(device.isWindowOpen());
278 assertFalse(device.isBatteryLow());
280 // test a plug device (MANUAL OFF)
281 device = liveDataResponse.getDeviceRecord("Living Room South");
282 assertNotNull(device);
283 assertEquals("Living Room South", device.getDeviceName());
284 assertFalse(device.isTimerOn());
285 assertTrue(device.stateManual());
287 // test a plug device (MANUAL ON)
288 device = liveDataResponse.getDeviceRecord("Living Room North");
289 assertNotNull(device);
290 assertEquals("Living Room North", device.getDeviceName());
291 assertTrue(device.isTimerOn());
292 assertTrue(device.stateManual());
294 // test a plug device (AUTO OFF)
295 device = liveDataResponse.getDeviceRecord("Green Wall Watering");
296 assertNotNull(device);
297 assertEquals("Green Wall Watering", device.getDeviceName());
298 assertFalse(device.isTimerOn());
299 assertFalse(device.stateManual());
301 // test a device that is offline
302 device = liveDataResponse.getDeviceRecord("Shower Room");
303 assertNotNull(device);
304 assertEquals("Shower Room", device.getDeviceName());
305 assertTrue(device.offline());
307 // test a device with a low battery
308 device = liveDataResponse.getDeviceRecord("Conservatory");
309 assertNotNull(device);
310 assertEquals("Conservatory", device.getDeviceName());
311 assertTrue(device.isBatteryLow());
313 // test a device with an open window alarm
314 device = liveDataResponse.getDeviceRecord("Door Contact");
315 assertNotNull(device);
316 assertEquals("Door Contact", device.getDeviceName());
317 assertTrue(device.isWindowOpen());
319 // test a wireless temperature sensor
320 device = liveDataResponse.getDeviceRecord("Room Sensor");
321 assertNotNull(device);
322 assertEquals("Room Sensor", device.getDeviceName());
323 assertEquals(new BigDecimal("21.5"), device.getActualTemperature());
325 // test a repeater node
326 device = liveDataResponse.getDeviceRecord("repeaternode54473");
327 assertNotNull(device);
328 assertEquals("repeaternode54473", device.getDeviceName());
329 assertTrue(MATCHER_HEATMISER_REPEATER.matcher(device.getDeviceName()).matches());
333 * From NeoHub rev2.6 onwards the INFO command is "deprecated" and the DEVICE_ID
334 * element is not returned in the GET_LIVE_DATA call so we must test the
335 * replacement GET_ENGINEERS command
338 public void testGetEngineersJson() {
339 // load GET_ENGINEERS JSON response string
340 NeoHubGetEngineersData engResponse = NeoHubGetEngineersData.createEngineersData(load("engineers"));
341 assertNotNull(engResponse);
343 // test device ID (type 12 thermostat device)
344 assertEquals(12, engResponse.getDeviceType("Dining Room"));
346 // test device ID (type 6 plug device)
347 assertEquals(6, engResponse.getDeviceType("Living Room South"));
351 * send JSON request to the socket and retrieve JSON response
353 private String testCommunicationInner(String requestJson) {
354 NeoHubSocket socket = new NeoHubSocket("192.168.1.109", 4242, 5);
355 String responseJson = "";
357 responseJson = socket.sendMessage(requestJson);
358 } catch (Exception e) {
365 * Test the communications
368 public void testCommunications() {
369 String responseJson = testCommunicationInner(CMD_CODE_INFO);
370 assertFalse(responseJson.isEmpty());
372 responseJson = testCommunicationInner(CMD_CODE_READ_DCB);
373 assertFalse(responseJson.isEmpty());
375 NeoHubReadDcbResponse dcbResponse = NeoHubReadDcbResponse.createSystemData(responseJson);
376 assertNotNull(dcbResponse);
378 long timeStamp = dcbResponse.timeStamp;
379 assertEquals(Instant.now().getEpochSecond(), timeStamp, 1);
381 responseJson = testCommunicationInner(CMD_CODE_GET_LIVE_DATA);
382 assertFalse(responseJson.isEmpty());
384 NeoHubLiveDeviceData liveDataResponse = NeoHubLiveDeviceData.createDeviceData(responseJson);
385 assertNotNull(liveDataResponse);
387 assertTrue(timeStamp > liveDataResponse.getTimestampEngineers());
388 assertTrue(timeStamp > liveDataResponse.getTimestampSystem());
390 responseJson = testCommunicationInner(CMD_CODE_GET_ENGINEERS);
391 assertFalse(responseJson.isEmpty());
393 responseJson = testCommunicationInner(CMD_CODE_GET_SYSTEM);
394 assertFalse(responseJson.isEmpty());
396 responseJson = testCommunicationInner(String.format(CMD_CODE_TEMP, "20", "Hallway"));
397 assertFalse(responseJson.isEmpty());