]> git.basschouten.com Git - openhab-addons.git/blob
ac4867fdbb0571704eaf589be24308159eb1cbfa
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2024 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.broadlink.internal.handler;
14
15 import static org.junit.Assert.fail;
16 import static org.junit.jupiter.api.Assertions.assertEquals;
17 import static org.mockito.Mockito.*;
18 import static org.openhab.binding.broadlink.internal.BroadlinkBindingConstants.*;
19
20 import java.io.IOException;
21 import java.util.List;
22
23 import javax.measure.quantity.Dimensionless;
24 import javax.measure.quantity.Temperature;
25
26 import org.eclipse.jdt.annotation.NonNullByDefault;
27 import org.junit.jupiter.api.BeforeEach;
28 import org.junit.jupiter.api.Test;
29 import org.mockito.ArgumentCaptor;
30 import org.mockito.ArgumentMatchers;
31 import org.mockito.Mockito;
32 import org.mockito.MockitoAnnotations;
33 import org.openhab.binding.broadlink.internal.BroadlinkBindingConstants;
34 import org.openhab.core.library.types.QuantityType;
35 import org.openhab.core.test.storage.VolatileStorageService;
36 import org.openhab.core.thing.ChannelUID;
37 import org.openhab.core.types.State;
38
39 /**
40  * Tests the Remote Model 4 handler.
41  *
42  * @author John Marshall - Initial contribution
43  */
44 @NonNullByDefault
45 public class BroadlinkRemoteModel4HandlerTest extends AbstractBroadlinkThingHandlerTest {
46
47     private byte[] response = { (byte) 0x5a, (byte) 0xa5, (byte) 0xaa, (byte) 0x55, (byte) 0x5a, (byte) 0xa5,
48             (byte) 0xaa, (byte) 0x55, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
49             (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
50             (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
51             (byte) 0x00, (byte) 0x00, (byte) 0xf6, (byte) 0xcd, (byte) 0x00, (byte) 0x00, (byte) 0x14, (byte) 0x27,
52             (byte) 0x6a, (byte) 0x00, (byte) 0x63, (byte) 0x00, (byte) 0x11, (byte) 0x22, (byte) 0x11, (byte) 0x22,
53             (byte) 0x11, (byte) 0x22, (byte) 0x11, (byte) 0x22, (byte) 0x11, (byte) 0x22, (byte) 0x00, (byte) 0xc0,
54             (byte) 0x00, (byte) 0x00, (byte) 0x09, (byte) 0x9a, (byte) 0x60, (byte) 0xfb, (byte) 0x72, (byte) 0x07,
55             (byte) 0x4f, (byte) 0x89, (byte) 0xf8, (byte) 0xb4, (byte) 0xdb, (byte) 0xb0, (byte) 0x72, (byte) 0xe7,
56             (byte) 0x1f, (byte) 0x86, };
57
58     @Override
59     @BeforeEach
60     public void setUp() throws Exception {
61         configureUnderlyingThing(BroadlinkBindingConstants.THING_TYPE_RM4_MINI, "rm4-test");
62         MockitoAnnotations.openMocks(this).close();
63         Mockito.when(mockSocket.sendAndReceive(ArgumentMatchers.any(byte[].class), ArgumentMatchers.anyString()))
64                 .thenReturn(response);
65     }
66
67     @Test
68     public void sendsExpectedBytesWhenGettingDeviceStatus() {
69         VolatileStorageService storageService = new VolatileStorageService();
70         ArgumentCaptor<Byte> commandCaptor = ArgumentCaptor.forClass(Byte.class);
71         ArgumentCaptor<byte[]> byteCaptor = ArgumentCaptor.forClass(byte[].class);
72         BroadlinkRemoteHandler model4 = new BroadlinkRemoteModel4MiniHandler(thing, commandDescriptionProvider,
73                 storageService);
74         setMocksForTesting(model4);
75         reset(trafficObserver);
76         try {
77             model4.getStatusFromDevice();
78         } catch (IOException | BroadlinkException e) {
79             fail("Unexpected exception: " + e.getClass().getCanonicalName());
80         }
81
82         verify(trafficObserver).onCommandSent(commandCaptor.capture());
83         assertEquals(0x6a, commandCaptor.getValue().byteValue());
84
85         verify(trafficObserver).onBytesSent(byteCaptor.capture());
86
87         byte[] sentBytes = byteCaptor.getValue();
88         assertEquals(16, sentBytes.length);
89
90         assertEquals(0x04, sentBytes[0]);
91         assertEquals(0x00, sentBytes[1]);
92         assertEquals(0x24, sentBytes[2]);
93     }
94
95     @Test
96     public void sendsExpectedBytesWhenSendingCode() throws IOException {
97         VolatileStorageService storageService = new VolatileStorageService();
98         ArgumentCaptor<Byte> commandCaptor = ArgumentCaptor.forClass(Byte.class);
99         ArgumentCaptor<byte[]> byteCaptor = ArgumentCaptor.forClass(byte[].class);
100         BroadlinkRemoteHandler model4 = new BroadlinkRemoteModel4MiniHandler(thing, commandDescriptionProvider,
101                 storageService);
102         setMocksForTesting(model4);
103         // Note the length is 10 so as to not require padding (6 byte preamble)
104         byte[] code = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a };
105
106         reset(trafficObserver);
107         model4.sendCode(code);
108
109         verify(trafficObserver).onCommandSent(commandCaptor.capture());
110         assertEquals(0x6a, commandCaptor.getValue().byteValue());
111
112         verify(trafficObserver).onBytesSent(byteCaptor.capture());
113
114         byte[] sentBytes = byteCaptor.getValue();
115         assertEquals(16, sentBytes.length);
116
117         assertEquals((byte) 0x0e, sentBytes[0]);
118         assertEquals(0x00, sentBytes[1]);
119
120         assertEquals(0x02, sentBytes[2]);
121         assertEquals(0x00, sentBytes[3]);
122         assertEquals(0x00, sentBytes[4]);
123         assertEquals(0x00, sentBytes[5]);
124
125         assertEquals(0x01, sentBytes[6]);
126         assertEquals(0x02, sentBytes[7]);
127         assertEquals(0x03, sentBytes[8]);
128         assertEquals(0x04, sentBytes[9]);
129         assertEquals(0x05, sentBytes[10]);
130         assertEquals(0x06, sentBytes[11]);
131         assertEquals(0x07, sentBytes[12]);
132         assertEquals(0x08, sentBytes[13]);
133         assertEquals(0x09, sentBytes[14]);
134         assertEquals(0x0a, sentBytes[15]);
135     }
136
137     @Test
138     public void sendsExpectedBytesWhenSendingCodeIncludingPadding() throws IOException {
139         VolatileStorageService storageService = new VolatileStorageService();
140         ArgumentCaptor<Byte> commandCaptor = ArgumentCaptor.forClass(Byte.class);
141         ArgumentCaptor<byte[]> byteCaptor = ArgumentCaptor.forClass(byte[].class);
142         BroadlinkRemoteHandler model4 = new BroadlinkRemoteModel4MiniHandler(thing, commandDescriptionProvider,
143                 storageService);
144         setMocksForTesting(model4);
145         // Note the length is such that padding up to the next multiple of 16 will be needed
146         byte[] code = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b };
147         reset(trafficObserver);
148         model4.sendCode(code);
149
150         verify(trafficObserver).onCommandSent(commandCaptor.capture());
151         assertEquals(0x6a, commandCaptor.getValue().byteValue());
152
153         verify(trafficObserver).onBytesSent(byteCaptor.capture());
154
155         byte[] sentBytes = byteCaptor.getValue();
156         assertEquals(32, sentBytes.length);
157
158         // Calculated length field is len(data) + 4 ===> 11 + 4 = 15 = 0x0f
159
160         assertEquals((byte) 0x0f, sentBytes[0]);
161         assertEquals(0x00, sentBytes[1]);
162
163         assertEquals(0x02, sentBytes[2]); // The "send code" command
164
165         assertEquals(0x01, sentBytes[6]); // The payload
166         assertEquals(0x02, sentBytes[7]);
167         assertEquals(0x03, sentBytes[8]);
168         assertEquals(0x04, sentBytes[9]);
169         assertEquals(0x05, sentBytes[10]);
170         assertEquals(0x06, sentBytes[11]);
171         assertEquals(0x07, sentBytes[12]);
172         assertEquals(0x08, sentBytes[13]);
173         assertEquals(0x09, sentBytes[14]);
174         assertEquals(0x0a, sentBytes[15]);
175         assertEquals(0x0b, sentBytes[16]);
176         assertEquals(0x00, sentBytes[17]);
177     }
178
179     @Test
180     public void setsTheTemperatureAndHumidityChannelsAfterGettingStatus() {
181         VolatileStorageService storageService = new VolatileStorageService();
182         BroadlinkRemoteHandler model4 = new BroadlinkRemoteModel4MiniHandler(thing, commandDescriptionProvider,
183                 storageService);
184         setMocksForTesting(model4);
185         reset(mockCallback);
186
187         try {
188             model4.getStatusFromDevice();
189         } catch (IOException | BroadlinkException e) {
190             fail("Unexpected exception: " + e.getClass().getCanonicalName());
191         }
192
193         ArgumentCaptor<ChannelUID> channelCaptor = ArgumentCaptor.forClass(ChannelUID.class);
194         ArgumentCaptor<State> stateCaptor = ArgumentCaptor.forClass(State.class);
195         verify(mockCallback, times(2)).stateUpdated(channelCaptor.capture(), stateCaptor.capture());
196
197         List<ChannelUID> channelCaptures = channelCaptor.getAllValues();
198         List<State> stateCaptures = stateCaptor.getAllValues();
199
200         ChannelUID expectedTemperatureChannel = new ChannelUID(thing.getUID(), TEMPERATURE_CHANNEL);
201         assertEquals(expectedTemperatureChannel, channelCaptures.get(0));
202
203         QuantityType<Temperature> expectedTemperature = new QuantityType<>(21.22,
204                 BroadlinkBindingConstants.BROADLINK_TEMPERATURE_UNIT);
205         assertEquals(expectedTemperature, stateCaptures.get(0));
206
207         ChannelUID expectedHumidityChannel = new ChannelUID(thing.getUID(), HUMIDITY_CHANNEL);
208         assertEquals(expectedHumidityChannel, channelCaptures.get(1));
209
210         QuantityType<Dimensionless> expectedHumidity = new QuantityType<>(39.4,
211                 BroadlinkBindingConstants.BROADLINK_HUMIDITY_UNIT);
212         assertEquals(expectedHumidity, stateCaptures.get(1));
213     }
214
215     @Test
216     public void sendsExpectedBytesWhenEnteringLearnMode() throws IOException {
217         VolatileStorageService storageService = new VolatileStorageService();
218         ArgumentCaptor<Byte> commandCaptor = ArgumentCaptor.forClass(Byte.class);
219         ArgumentCaptor<byte[]> byteCaptor = ArgumentCaptor.forClass(byte[].class);
220         BroadlinkRemoteHandler model4 = new BroadlinkRemoteModel4MiniHandler(thing, commandDescriptionProvider,
221                 storageService);
222         setMocksForTesting(model4);
223
224         reset(trafficObserver);
225         model4.handleLearningCommand(LEARNING_CONTROL_COMMAND_LEARN);
226
227         verify(trafficObserver).onCommandSent(commandCaptor.capture());
228         assertEquals(0x6a, commandCaptor.getValue().byteValue());
229
230         verify(trafficObserver).onBytesSent(byteCaptor.capture());
231
232         byte[] sentBytes = byteCaptor.getValue();
233         assertEquals(16, sentBytes.length);
234
235         // Expecting:
236         // PLl, PLh, <commandByte> 0 0 0 then padding for the rest up to 16
237         // Where PL = length(data) + 4 - so in this case, 4
238         assertEquals(0x04, sentBytes[0]); // Low length byte
239         assertEquals(0x00, sentBytes[1]); // High length byte
240         assertEquals(0x03, sentBytes[2]);
241         assertEquals(0x00, sentBytes[3]);
242         assertEquals(0x00, sentBytes[4]);
243         assertEquals(0x00, sentBytes[5]);
244         assertEquals(0x00, sentBytes[6]);
245         assertEquals(0x00, sentBytes[7]);
246         assertEquals(0x00, sentBytes[8]);
247         assertEquals(0x00, sentBytes[9]);
248         assertEquals(0x00, sentBytes[10]);
249         assertEquals(0x00, sentBytes[11]);
250         assertEquals(0x00, sentBytes[12]);
251         assertEquals(0x00, sentBytes[13]);
252         assertEquals(0x00, sentBytes[14]);
253         assertEquals(0x00, sentBytes[15]);
254     }
255 }