2 * Copyright (c) 2010-2024 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.broadlink.internal.handler;
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.*;
20 import java.io.IOException;
21 import java.util.List;
23 import javax.measure.quantity.Power;
25 import org.eclipse.jdt.annotation.NonNullByDefault;
26 import org.junit.jupiter.api.BeforeEach;
27 import org.junit.jupiter.api.Test;
28 import org.mockito.ArgumentCaptor;
29 import org.mockito.ArgumentMatchers;
30 import org.mockito.Mockito;
31 import org.mockito.MockitoAnnotations;
32 import org.openhab.binding.broadlink.internal.BroadlinkBindingConstants;
33 import org.openhab.core.library.types.OnOffType;
34 import org.openhab.core.library.types.QuantityType;
35 import org.openhab.core.thing.ChannelUID;
36 import org.openhab.core.types.State;
39 * Tests the Socket Model 2 handler.
41 * @author John Marshall - Initial contribution
44 public class BroadlinkSocketModel2HandlerTest extends AbstractBroadlinkThingHandlerTest {
46 private final byte[] response = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
47 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
48 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
49 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
50 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
51 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
52 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, };
56 public void setUp() throws Exception {
57 configureUnderlyingThing(BroadlinkBindingConstants.THING_TYPE_SP2, "sp2-test");
58 MockitoAnnotations.openMocks(this).close();
59 Mockito.when(mockSocket.sendAndReceive(ArgumentMatchers.any(byte[].class), ArgumentMatchers.anyString()))
60 .thenReturn(response);
64 public void derivePowerStateBitsOff() {
65 BroadlinkSocketModel2Handler model2 = new BroadlinkSocketModel2Handler(thing, false);
66 byte[] payload = { 0x00, 0x00, 0x00, 0x00, 0x00 };
67 OnOffType result = model2.derivePowerStateFromStatusBytes(payload);
68 assertEquals(OnOffType.OFF, result);
72 public void derivePowerStateBitsOn1() {
73 BroadlinkSocketModel2Handler model2 = new BroadlinkSocketModel2Handler(thing, false);
74 byte[] payload = { 0x00, 0x00, 0x00, 0x00, 0x01 };
75 OnOffType result = model2.derivePowerStateFromStatusBytes(payload);
76 assertEquals(OnOffType.ON, result);
80 public void derivePowerStateBitsOn3() {
81 BroadlinkSocketModel2Handler model2 = new BroadlinkSocketModel2Handler(thing, false);
82 byte[] payload = { 0x00, 0x00, 0x00, 0x00, 0x03 };
83 OnOffType result = model2.derivePowerStateFromStatusBytes(payload);
84 assertEquals(OnOffType.ON, result);
88 public void derivePowerStateBitsOnFD() {
89 BroadlinkSocketModel2Handler model2 = new BroadlinkSocketModel2Handler(thing, false);
90 byte[] payload = { 0x00, 0x00, 0x00, 0x00, (byte) 0xFD };
91 OnOffType result = model2.derivePowerStateFromStatusBytes(payload);
92 assertEquals(OnOffType.ON, result);
96 public void derivePowerConsumptionFromStatusBytesTooShort() throws IOException {
97 BroadlinkSocketModel2Handler model2 = new BroadlinkSocketModel2Handler(thing, false);
98 byte[] payload = { 0x00, 0x00, 0x00, 0x00, 0x33 };
99 double result = model2.derivePowerConsumption(payload);
100 assertEquals(0D, result, 0.1D);
104 public void derivePowerConsumptionFromStatusBytesCorrect() throws IOException {
105 BroadlinkSocketModel2Handler model2 = new BroadlinkSocketModel2Handler(thing, false);
106 byte[] payload = { 0x00, 0x00, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00 };
107 double result = model2.derivePowerConsumption(payload);
108 assertEquals(66.051D, result, 0.1D);
112 public void setsThePowerChannelOnlyAfterGettingStatusOnSP2() {
113 byte[] response = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
114 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
115 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
116 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x03, 0x00, 0x00, 0x00,
117 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
118 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
119 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
121 Mockito.when(mockSocket.sendAndReceive(ArgumentMatchers.any(byte[].class), ArgumentMatchers.anyString()))
122 .thenReturn(response);
123 BroadlinkSocketHandler model2 = new BroadlinkSocketModel2Handler(thing, false);
124 setMocksForTesting(model2);
129 model2.getStatusFromDevice();
130 } catch (IOException | BroadlinkException e) {
131 fail("Unexpected exception: " + e.getClass().getCanonicalName());
134 ArgumentCaptor<ChannelUID> channelCaptor = ArgumentCaptor.forClass(ChannelUID.class);
135 ArgumentCaptor<State> stateCaptor = ArgumentCaptor.forClass(State.class);
136 verify(mockCallback).stateUpdated(channelCaptor.capture(), stateCaptor.capture());
138 ChannelUID expectedPowerChannel = new ChannelUID(thing.getUID(), COMMAND_POWER_ON);
139 assertEquals(expectedPowerChannel, channelCaptor.getValue());
141 assertEquals(OnOffType.ON, stateCaptor.getValue());
145 public void setsThePowerAndPowerConsumptionAfterGettingStatusOnSP2S() {
146 // Power bytes are 4, 5, 6 (little-endian)
147 // So here it's 0x38291 => 230033, divided by 1000 ==> 230.033W
148 byte[] payload = { 0x08, 0x00, 0x11, 0x22, (byte) 0x91, (byte) 0x82, 0x3, 0x16, 0x27, 0x28, 0x01, 0x02, 0x03,
150 byte[] responseMessage = generateReceivedBroadlinkMessage(payload);
151 Mockito.when(mockSocket.sendAndReceive(ArgumentMatchers.any(byte[].class), ArgumentMatchers.anyString()))
152 .thenReturn(responseMessage);
153 BroadlinkSocketHandler model2s = new BroadlinkSocketModel2Handler(thing, true);
154 setMocksForTesting(model2s);
159 model2s.getStatusFromDevice();
160 } catch (IOException | BroadlinkException e) {
161 fail("Unexpected exception: " + e.getClass().getCanonicalName());
164 ArgumentCaptor<ChannelUID> channelCaptor = ArgumentCaptor.forClass(ChannelUID.class);
165 ArgumentCaptor<State> stateCaptor = ArgumentCaptor.forClass(State.class);
166 verify(mockCallback, Mockito.times(2)).stateUpdated(channelCaptor.capture(), stateCaptor.capture());
168 List<ChannelUID> channels = channelCaptor.getAllValues();
169 List<State> states = stateCaptor.getAllValues();
171 ChannelUID expectedPowerChannel = new ChannelUID(thing.getUID(), COMMAND_POWER_ON);
172 assertEquals(expectedPowerChannel, channels.get(0));
174 assertEquals(OnOffType.ON, states.get(0));
176 ChannelUID expectedConsumptionChannel = new ChannelUID(thing.getUID(), POWER_CONSUMPTION_CHANNEL);
177 assertEquals(expectedConsumptionChannel, channels.get(1));
179 QuantityType<Power> expectedPower = new QuantityType<>(230.033,
180 BroadlinkBindingConstants.BROADLINK_POWER_CONSUMPTION_UNIT);
181 assertEquals(expectedPower, states.get(1));