]> git.basschouten.com Git - openhab-addons.git/blob
b6d3e7330791d1b60755e0181029439a99c4db38
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2020 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.nest.handler;
14
15 import static org.hamcrest.MatcherAssert.assertThat;
16 import static org.hamcrest.core.Is.is;
17 import static org.openhab.binding.nest.internal.NestBindingConstants.*;
18 import static org.openhab.binding.nest.internal.data.NestDataUtil.*;
19 import static org.openhab.core.library.types.OnOffType.*;
20 import static org.openhab.core.library.unit.ImperialUnits.FAHRENHEIT;
21 import static org.openhab.core.library.unit.SIUnits.CELSIUS;
22
23 import java.io.IOException;
24 import java.util.HashMap;
25 import java.util.Map;
26
27 import org.junit.jupiter.api.Test;
28 import org.openhab.binding.nest.internal.config.NestDeviceConfiguration;
29 import org.openhab.binding.nest.internal.handler.NestThermostatHandler;
30 import org.openhab.core.config.core.Configuration;
31 import org.openhab.core.library.types.QuantityType;
32 import org.openhab.core.library.types.StringType;
33 import org.openhab.core.library.unit.Units;
34 import org.openhab.core.thing.Bridge;
35 import org.openhab.core.thing.Thing;
36 import org.openhab.core.thing.ThingStatus;
37 import org.openhab.core.thing.ThingStatusDetail;
38 import org.openhab.core.thing.ThingUID;
39 import org.openhab.core.thing.binding.builder.ThingBuilder;
40
41 /**
42  * Tests for {@link NestThermostatHandler}.
43  *
44  * @author Wouter Born - Increase test coverage
45  */
46 public class NestThermostatHandlerTest extends NestThingHandlerOSGiTest {
47
48     private static final ThingUID THERMOSTAT_UID = new ThingUID(THING_TYPE_THERMOSTAT, "thermostat1");
49     private static final int CHANNEL_COUNT = 25;
50
51     public NestThermostatHandlerTest() {
52         super(NestThermostatHandler.class);
53     }
54
55     @Override
56     protected Thing buildThing(Bridge bridge) {
57         Map<String, Object> properties = new HashMap<>();
58         properties.put(NestDeviceConfiguration.DEVICE_ID, THERMOSTAT1_DEVICE_ID);
59
60         return ThingBuilder.create(THING_TYPE_THERMOSTAT, THERMOSTAT_UID).withLabel("Test Thermostat")
61                 .withBridge(bridge.getUID()).withChannels(buildChannels(THING_TYPE_THERMOSTAT, THERMOSTAT_UID))
62                 .withConfiguration(new Configuration(properties)).build();
63     }
64
65     @Test
66     public void completeThermostatCelsiusUpdate() throws IOException {
67         assertThat(thing.getChannels().size(), is(CHANNEL_COUNT));
68         assertThat(thing.getStatus(), is(ThingStatus.OFFLINE));
69
70         waitForAssert(() -> assertThat(bridge.getStatus(), is(ThingStatus.ONLINE)));
71         putStreamingEventData(fromFile(COMPLETE_DATA_FILE_NAME, CELSIUS));
72         waitForAssert(() -> assertThat(thing.getStatus(), is(ThingStatus.ONLINE)));
73
74         assertThatItemHasState(CHANNEL_CAN_COOL, OFF);
75         assertThatItemHasState(CHANNEL_CAN_HEAT, ON);
76         assertThatItemHasState(CHANNEL_ECO_MAX_SET_POINT, new QuantityType<>(24, CELSIUS));
77         assertThatItemHasState(CHANNEL_ECO_MIN_SET_POINT, new QuantityType<>(12.5, CELSIUS));
78         assertThatItemHasState(CHANNEL_FAN_TIMER_ACTIVE, OFF);
79         assertThatItemHasState(CHANNEL_FAN_TIMER_DURATION, new QuantityType<>(15, Units.MINUTE));
80         assertThatItemHasState(CHANNEL_FAN_TIMER_TIMEOUT, parseDateTimeType("1970-01-01T00:00:00.000Z"));
81         assertThatItemHasState(CHANNEL_HAS_FAN, ON);
82         assertThatItemHasState(CHANNEL_HAS_LEAF, ON);
83         assertThatItemHasState(CHANNEL_HUMIDITY, new QuantityType<>(25, Units.PERCENT));
84         assertThatItemHasState(CHANNEL_LAST_CONNECTION, parseDateTimeType("2017-02-02T21:00:06.000Z"));
85         assertThatItemHasState(CHANNEL_LOCKED, OFF);
86         assertThatItemHasState(CHANNEL_LOCKED_MAX_SET_POINT, new QuantityType<>(22, CELSIUS));
87         assertThatItemHasState(CHANNEL_LOCKED_MIN_SET_POINT, new QuantityType<>(20, CELSIUS));
88         assertThatItemHasState(CHANNEL_MAX_SET_POINT, new QuantityType<>(24, CELSIUS));
89         assertThatItemHasState(CHANNEL_MIN_SET_POINT, new QuantityType<>(20, CELSIUS));
90         assertThatItemHasState(CHANNEL_MODE, new StringType("HEAT"));
91         assertThatItemHasState(CHANNEL_PREVIOUS_MODE, new StringType("HEAT"));
92         assertThatItemHasState(CHANNEL_SET_POINT, new QuantityType<>(15.5, CELSIUS));
93         assertThatItemHasState(CHANNEL_STATE, new StringType("OFF"));
94         assertThatItemHasState(CHANNEL_SUNLIGHT_CORRECTION_ACTIVE, OFF);
95         assertThatItemHasState(CHANNEL_SUNLIGHT_CORRECTION_ENABLED, ON);
96         assertThatItemHasState(CHANNEL_TEMPERATURE, new QuantityType<>(19, CELSIUS));
97         assertThatItemHasState(CHANNEL_TIME_TO_TARGET, new QuantityType<>(0, Units.MINUTE));
98         assertThatItemHasState(CHANNEL_USING_EMERGENCY_HEAT, OFF);
99
100         assertThatAllItemStatesAreNotNull();
101     }
102
103     @Test
104     public void completeThermostatFahrenheitUpdate() throws IOException {
105         assertThat(thing.getChannels().size(), is(CHANNEL_COUNT));
106         assertThat(thing.getStatus(), is(ThingStatus.OFFLINE));
107
108         waitForAssert(() -> assertThat(bridge.getStatus(), is(ThingStatus.ONLINE)));
109         putStreamingEventData(fromFile(COMPLETE_DATA_FILE_NAME, FAHRENHEIT));
110         waitForAssert(() -> assertThat(thing.getStatus(), is(ThingStatus.ONLINE)));
111
112         assertThatItemHasState(CHANNEL_CAN_COOL, OFF);
113         assertThatItemHasState(CHANNEL_CAN_HEAT, ON);
114         assertThatItemHasState(CHANNEL_ECO_MAX_SET_POINT, new QuantityType<>(76, FAHRENHEIT));
115         assertThatItemHasState(CHANNEL_ECO_MIN_SET_POINT, new QuantityType<>(55, FAHRENHEIT));
116         assertThatItemHasState(CHANNEL_FAN_TIMER_ACTIVE, OFF);
117         assertThatItemHasState(CHANNEL_FAN_TIMER_DURATION, new QuantityType<>(15, Units.MINUTE));
118         assertThatItemHasState(CHANNEL_FAN_TIMER_TIMEOUT, parseDateTimeType("1970-01-01T00:00:00.000Z"));
119         assertThatItemHasState(CHANNEL_HAS_FAN, ON);
120         assertThatItemHasState(CHANNEL_HAS_LEAF, ON);
121         assertThatItemHasState(CHANNEL_HUMIDITY, new QuantityType<>(25, Units.PERCENT));
122         assertThatItemHasState(CHANNEL_LAST_CONNECTION, parseDateTimeType("2017-02-02T21:00:06.000Z"));
123         assertThatItemHasState(CHANNEL_LOCKED, OFF);
124         assertThatItemHasState(CHANNEL_LOCKED_MAX_SET_POINT, new QuantityType<>(72, FAHRENHEIT));
125         assertThatItemHasState(CHANNEL_LOCKED_MIN_SET_POINT, new QuantityType<>(68, FAHRENHEIT));
126         assertThatItemHasState(CHANNEL_MAX_SET_POINT, new QuantityType<>(75, FAHRENHEIT));
127         assertThatItemHasState(CHANNEL_MIN_SET_POINT, new QuantityType<>(68, FAHRENHEIT));
128         assertThatItemHasState(CHANNEL_MODE, new StringType("HEAT"));
129         assertThatItemHasState(CHANNEL_PREVIOUS_MODE, new StringType("HEAT"));
130         assertThatItemHasState(CHANNEL_SET_POINT, new QuantityType<>(60, FAHRENHEIT));
131         assertThatItemHasState(CHANNEL_STATE, new StringType("OFF"));
132         assertThatItemHasState(CHANNEL_SUNLIGHT_CORRECTION_ACTIVE, OFF);
133         assertThatItemHasState(CHANNEL_SUNLIGHT_CORRECTION_ENABLED, ON);
134         assertThatItemHasState(CHANNEL_TEMPERATURE, new QuantityType<>(66, FAHRENHEIT));
135         assertThatItemHasState(CHANNEL_TIME_TO_TARGET, new QuantityType<>(0, Units.MINUTE));
136         assertThatItemHasState(CHANNEL_USING_EMERGENCY_HEAT, OFF);
137
138         assertThatAllItemStatesAreNotNull();
139     }
140
141     @Test
142     public void incompleteThermostatUpdate() throws IOException {
143         assertThat(thing.getChannels().size(), is(CHANNEL_COUNT));
144         assertThat(thing.getStatus(), is(ThingStatus.OFFLINE));
145
146         waitForAssert(() -> assertThat(bridge.getStatus(), is(ThingStatus.ONLINE)));
147         putStreamingEventData(fromFile(COMPLETE_DATA_FILE_NAME));
148         waitForAssert(() -> assertThat(thing.getStatus(), is(ThingStatus.ONLINE)));
149         assertThatAllItemStatesAreNotNull();
150
151         putStreamingEventData(fromFile(INCOMPLETE_DATA_FILE_NAME));
152         waitForAssert(() -> assertThat(thing.getStatus(), is(ThingStatus.UNKNOWN)));
153         assertThatAllItemStatesAreNull();
154     }
155
156     @Test
157     public void thermostatGone() throws IOException {
158         waitForAssert(() -> assertThat(bridge.getStatus(), is(ThingStatus.ONLINE)));
159         putStreamingEventData(fromFile(COMPLETE_DATA_FILE_NAME));
160         waitForAssert(() -> assertThat(thing.getStatus(), is(ThingStatus.ONLINE)));
161
162         putStreamingEventData(fromFile(EMPTY_DATA_FILE_NAME));
163         waitForAssert(() -> assertThat(thing.getStatus(), is(ThingStatus.OFFLINE)));
164         assertThat(thing.getStatusInfo().getStatusDetail(), is(ThingStatusDetail.GONE));
165     }
166
167     @Test
168     public void channelRefresh() throws IOException {
169         waitForAssert(() -> assertThat(bridge.getStatus(), is(ThingStatus.ONLINE)));
170         putStreamingEventData(fromFile(COMPLETE_DATA_FILE_NAME));
171         waitForAssert(() -> assertThat(thing.getStatus(), is(ThingStatus.ONLINE)));
172         assertThatAllItemStatesAreNotNull();
173
174         updateAllItemStatesToNull();
175         assertThatAllItemStatesAreNull();
176
177         refreshAllChannels();
178         assertThatAllItemStatesAreNotNull();
179     }
180
181     @Test
182     public void handleFanTimerActiveCommands() throws IOException {
183         handleCommand(CHANNEL_FAN_TIMER_ACTIVE, ON);
184         assertNestApiPropertyState(THERMOSTAT1_DEVICE_ID, "fan_timer_active", "true");
185
186         handleCommand(CHANNEL_FAN_TIMER_ACTIVE, OFF);
187         assertNestApiPropertyState(THERMOSTAT1_DEVICE_ID, "fan_timer_active", "false");
188
189         handleCommand(CHANNEL_FAN_TIMER_ACTIVE, ON);
190         assertNestApiPropertyState(THERMOSTAT1_DEVICE_ID, "fan_timer_active", "true");
191     }
192
193     @Test
194     public void handleFanTimerDurationCommands() throws IOException {
195         int[] durations = { 15, 30, 45, 60, 120, 240, 480, 960, 15 };
196         for (int duration : durations) {
197             handleCommand(CHANNEL_FAN_TIMER_DURATION, new QuantityType<>(duration, Units.MINUTE));
198             assertNestApiPropertyState(THERMOSTAT1_DEVICE_ID, "fan_timer_duration", String.valueOf(duration));
199         }
200     }
201
202     @Test
203     public void handleMaxSetPointCelsiusCommands() throws IOException {
204         celsiusCommandsTest(CHANNEL_MAX_SET_POINT, "target_temperature_high_c");
205     }
206
207     @Test
208     public void handleMaxSetPointFahrenheitCommands() throws IOException {
209         fahrenheitCommandsTest(CHANNEL_MAX_SET_POINT, "target_temperature_high_f");
210     }
211
212     @Test
213     public void handleMinSetPointCelsiusCommands() throws IOException {
214         celsiusCommandsTest(CHANNEL_MIN_SET_POINT, "target_temperature_low_c");
215     }
216
217     @Test
218     public void handleMinSetPointFahrenheitCommands() throws IOException {
219         fahrenheitCommandsTest(CHANNEL_MIN_SET_POINT, "target_temperature_low_f");
220     }
221
222     @Test
223     public void handleChannelModeCommands() throws IOException {
224         handleCommand(CHANNEL_MODE, new StringType("HEAT"));
225         assertNestApiPropertyState(THERMOSTAT1_DEVICE_ID, "hvac_mode", "heat");
226
227         handleCommand(CHANNEL_MODE, new StringType("COOL"));
228         assertNestApiPropertyState(THERMOSTAT1_DEVICE_ID, "hvac_mode", "cool");
229
230         handleCommand(CHANNEL_MODE, new StringType("HEAT_COOL"));
231         assertNestApiPropertyState(THERMOSTAT1_DEVICE_ID, "hvac_mode", "heat-cool");
232
233         handleCommand(CHANNEL_MODE, new StringType("ECO"));
234         assertNestApiPropertyState(THERMOSTAT1_DEVICE_ID, "hvac_mode", "eco");
235
236         handleCommand(CHANNEL_MODE, new StringType("OFF"));
237         assertNestApiPropertyState(THERMOSTAT1_DEVICE_ID, "hvac_mode", "off");
238
239         handleCommand(CHANNEL_MODE, new StringType("HEAT"));
240         assertNestApiPropertyState(THERMOSTAT1_DEVICE_ID, "hvac_mode", "heat");
241     }
242
243     @Test
244     public void handleSetPointCelsiusCommands() throws IOException {
245         celsiusCommandsTest(CHANNEL_SET_POINT, "target_temperature_c");
246     }
247
248     @Test
249     public void handleSetPointFahrenheitCommands() throws IOException {
250         fahrenheitCommandsTest(CHANNEL_SET_POINT, "target_temperature_f");
251     }
252
253     private void celsiusCommandsTest(String channelId, String apiPropertyName) throws IOException {
254         waitForAssert(() -> assertThat(bridge.getStatus(), is(ThingStatus.ONLINE)));
255         putStreamingEventData(fromFile(COMPLETE_DATA_FILE_NAME, CELSIUS));
256         waitForAssert(() -> assertThat(thing.getStatus(), is(ThingStatus.ONLINE)));
257
258         handleCommand(channelId, new QuantityType<>(20, CELSIUS));
259         assertNestApiPropertyState(THERMOSTAT1_DEVICE_ID, apiPropertyName, "20.0");
260
261         handleCommand(channelId, new QuantityType<>(21.123, CELSIUS));
262         assertNestApiPropertyState(THERMOSTAT1_DEVICE_ID, apiPropertyName, "21.0");
263
264         handleCommand(channelId, new QuantityType<>(22.541, CELSIUS));
265         assertNestApiPropertyState(THERMOSTAT1_DEVICE_ID, apiPropertyName, "22.5");
266
267         handleCommand(channelId, new QuantityType<>(23.74, CELSIUS));
268         assertNestApiPropertyState(THERMOSTAT1_DEVICE_ID, apiPropertyName, "23.5");
269
270         handleCommand(channelId, new QuantityType<>(23.75, CELSIUS));
271         assertNestApiPropertyState(THERMOSTAT1_DEVICE_ID, apiPropertyName, "24.0");
272
273         handleCommand(channelId, new QuantityType<>(70, FAHRENHEIT));
274         assertNestApiPropertyState(THERMOSTAT1_DEVICE_ID, apiPropertyName, "21.0");
275     }
276
277     private void fahrenheitCommandsTest(String channelId, String apiPropertyName) throws IOException {
278         waitForAssert(() -> assertThat(bridge.getStatus(), is(ThingStatus.ONLINE)));
279         putStreamingEventData(fromFile(COMPLETE_DATA_FILE_NAME, FAHRENHEIT));
280         waitForAssert(() -> assertThat(thing.getStatus(), is(ThingStatus.ONLINE)));
281
282         handleCommand(channelId, new QuantityType<>(70, FAHRENHEIT));
283         assertNestApiPropertyState(THERMOSTAT1_DEVICE_ID, apiPropertyName, "70");
284
285         handleCommand(channelId, new QuantityType<>(71.123, FAHRENHEIT));
286         assertNestApiPropertyState(THERMOSTAT1_DEVICE_ID, apiPropertyName, "71");
287
288         handleCommand(channelId, new QuantityType<>(71.541, FAHRENHEIT));
289         assertNestApiPropertyState(THERMOSTAT1_DEVICE_ID, apiPropertyName, "72");
290
291         handleCommand(channelId, new QuantityType<>(72.74, FAHRENHEIT));
292         assertNestApiPropertyState(THERMOSTAT1_DEVICE_ID, apiPropertyName, "73");
293
294         handleCommand(channelId, new QuantityType<>(73.75, FAHRENHEIT));
295         assertNestApiPropertyState(THERMOSTAT1_DEVICE_ID, apiPropertyName, "74");
296
297         handleCommand(channelId, new QuantityType<>(21, CELSIUS));
298         assertNestApiPropertyState(THERMOSTAT1_DEVICE_ID, apiPropertyName, "70");
299     }
300 }