]> git.basschouten.com Git - openhab-addons.git/blob
727dd7056c61ecb7780d3708e0dfbd2cfd99f531
[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.anel.internal;
14
15 import static org.hamcrest.MatcherAssert.assertThat;
16 import static org.hamcrest.Matchers.*;
17
18 import java.util.LinkedHashSet;
19 import java.util.Queue;
20 import java.util.Set;
21 import java.util.concurrent.ConcurrentLinkedQueue;
22 import java.util.concurrent.ExecutorService;
23 import java.util.concurrent.Executors;
24
25 import org.eclipse.jdt.annotation.NonNullByDefault;
26 import org.eclipse.jdt.annotation.Nullable;
27 import org.junit.jupiter.api.AfterAll;
28 import org.junit.jupiter.api.BeforeAll;
29 import org.junit.jupiter.api.BeforeEach;
30 import org.junit.jupiter.api.Disabled;
31 import org.junit.jupiter.api.Test;
32 import org.openhab.binding.anel.internal.auth.AnelAuthentication;
33 import org.openhab.binding.anel.internal.auth.AnelAuthentication.AuthMethod;
34
35 /**
36  * This test requires a physical Anel device!
37  *
38  * @author Patrick Koenemann - Initial contribution
39  */
40 @NonNullByDefault
41 @Disabled // requires a physically available device in the local network
42 public class AnelUdpConnectorTest {
43
44     /*
45      * The IP and ports for the Anel device under test.
46      */
47     private static final String HOST = "192.168.6.63"; // 63 / 64
48     private static final int PORT_SEND = 7500; // 7500 / 75001
49     private static final int PORT_RECEIVE = 7700; // 7700 / 7701
50     private static final String USER = "user7";
51     private static final String PASSWORD = "anel";
52
53     /* The device may have an internal delay of 200ms, plus network latency! Should not be <1sec. */
54     private static final int WAIT_FOR_DEVICE_RESPONSE_MS = 1000;
55
56     private static final ExecutorService EXECUTOR_SERVICE = Executors.newCachedThreadPool();
57
58     private final Queue<String> receivedMessages = new ConcurrentLinkedQueue<>();
59
60     @Nullable
61     private static AnelUdpConnector connector;
62
63     @BeforeAll
64     public static void prepareConnector() {
65         connector = new AnelUdpConnector(HOST, PORT_RECEIVE, PORT_SEND, EXECUTOR_SERVICE);
66     }
67
68     @AfterAll
69     @SuppressWarnings("null")
70     public static void closeConnection() {
71         connector.disconnect();
72     }
73
74     @BeforeEach
75     @SuppressWarnings("null")
76     public void connectIfNotYetConnected() throws Exception {
77         Thread.sleep(100);
78         receivedMessages.clear(); // clear all previously received messages
79
80         if (!connector.isConnected()) {
81             connector.connect(receivedMessages::offer, false);
82         }
83     }
84
85     @Test
86     public void connectionTest() throws Exception {
87         final String response = sendAndReceiveSingle(IAnelConstants.BROADCAST_DISCOVERY_MSG);
88         /*
89          * Expected example response:
90          * "NET-PwrCtrl:NET-CONTROL    :192.168.0.244:255.255.255.0:192.168.0.1:0.5.163.21.4.71:Nr. 1,0:Nr. 2,1:Nr. 3,0:Nr. 4,0:Nr. 5,0:Nr. 6,0:Nr. 7,0:Nr. 8,0:248:80:NET-PWRCTRL_04.6:H:xor:"
91          */
92         assertThat(response, startsWith(IAnelConstants.STATUS_RESPONSE_PREFIX + IAnelConstants.STATUS_SEPARATOR));
93     }
94
95     @Test
96     public void toggleSwitch1() throws Exception {
97         toggleSwitch(1);
98     }
99
100     @Test
101     public void toggleSwitch2() throws Exception {
102         toggleSwitch(2);
103     }
104
105     @Test
106     public void toggleSwitch3() throws Exception {
107         toggleSwitch(3);
108     }
109
110     @Test
111     public void toggleSwitch4() throws Exception {
112         toggleSwitch(4);
113     }
114
115     @Test
116     public void toggleSwitch5() throws Exception {
117         toggleSwitch(5);
118     }
119
120     @Test
121     public void toggleSwitch6() throws Exception {
122         toggleSwitch(6);
123     }
124
125     @Test
126     public void toggleSwitch7() throws Exception {
127         toggleSwitch(7);
128     }
129
130     @Test
131     public void toggleSwitch8() throws Exception {
132         toggleSwitch(8);
133     }
134
135     private void toggleSwitch(int switchNr) throws Exception {
136         assertThat(switchNr, allOf(greaterThan(0), lessThan(9)));
137         final int index = 5 + switchNr;
138
139         // get state of switch 1
140         final String status = sendAndReceiveSingle(IAnelConstants.BROADCAST_DISCOVERY_MSG);
141         final String[] segments = status.split(IAnelConstants.STATUS_SEPARATOR);
142         assertThat(segments[5 + switchNr], anyOf(endsWith(",1"), endsWith(",0")));
143         final boolean switch1state = segments[index].endsWith(",1");
144
145         // toggle state of switch 1
146         final String auth = AnelAuthentication.getUserPasswordString(USER, PASSWORD, AuthMethod.of(status));
147         final String command = "Sw_" + (switch1state ? "off" : "on") + switchNr + auth;
148         final String status2 = sendAndReceiveSingle(command);
149
150         // assert new state of switch 1
151         assertThat(status2.trim(), not(endsWith(":Err")));
152         final String[] segments2 = status2.split(IAnelConstants.STATUS_SEPARATOR);
153         final String expectedState = segments2[index].substring(0, segments2[index].length() - 1)
154                 + (switch1state ? "0" : "1");
155         assertThat(segments2[index], equalTo(expectedState));
156     }
157
158     @Test
159     public void withoutCredentials() throws Exception {
160         final String status2 = sendAndReceiveSingle("Sw_on1");
161         assertThat(status2.trim(), endsWith(":NoPass:Err"));
162         Thread.sleep(3100); // locked for 3 seconds
163     }
164
165     private String sendAndReceiveSingle(final String msg) throws Exception {
166         final Set<String> response = sendAndReceive(msg);
167         assertThat(response, hasSize(1));
168         return response.iterator().next();
169     }
170
171     @SuppressWarnings("null")
172     private Set<String> sendAndReceive(final String msg) throws Exception {
173         assertThat(receivedMessages, is(empty()));
174         connector.send(msg);
175         Thread.sleep(WAIT_FOR_DEVICE_RESPONSE_MS);
176         final Set<String> response = new LinkedHashSet<>();
177         while (!receivedMessages.isEmpty()) {
178             final String receivedMessage = receivedMessages.poll();
179             if (receivedMessage != null) {
180                 response.add(receivedMessage);
181             }
182         }
183         return response;
184     }
185 }