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