]> git.basschouten.com Git - openhab-addons.git/blob
0183bae04b1a2987a393947d9ffb3af60eaf5829
[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.bigassfan.internal.discovery;
14
15 import static org.openhab.binding.bigassfan.internal.BigAssFanBindingConstants.BAF_PORT;
16
17 import java.io.IOException;
18 import java.net.DatagramPacket;
19 import java.net.DatagramSocket;
20 import java.net.InetAddress;
21 import java.net.SocketException;
22 import java.net.SocketTimeoutException;
23 import java.net.UnknownHostException;
24 import java.nio.charset.StandardCharsets;
25
26 import org.eclipse.jdt.annotation.NonNullByDefault;
27 import org.eclipse.jdt.annotation.Nullable;
28 import org.slf4j.Logger;
29 import org.slf4j.LoggerFactory;
30
31 /**
32  * The {@link DiscoveryListener} is responsible for listening on the UDP socket for fan discovery messages.
33  *
34  * @author Mark Hilbush - Initial contribution
35  */
36 @NonNullByDefault
37 public class DiscoveryListener {
38     private final Logger logger = LoggerFactory.getLogger(DiscoveryListener.class);
39
40     private static final String BCAST_ADDRESS = "255.255.255.255";
41     private static final int SOCKET_RECEIVE_TIMEOUT = 500;
42     private static final String POLL_MESSAGE = "<ALL;DEVICE;ID;GET>";
43
44     @Nullable
45     DatagramSocket dSocket;
46     @Nullable
47     DatagramPacket rcvPacket;
48     byte[] rcvBuffer = new byte[0];
49     @Nullable
50     InetAddress bcastAddress;
51     byte[] bcastBuffer = new byte[0];
52     @Nullable
53     DatagramPacket bcastPacket;
54
55     BigAssFanDevice device;
56
57     public DiscoveryListener() throws IOException, SocketException {
58         logger.debug("DiscoveryListener opening UDP broadcast socket");
59         dSocket = null;
60         device = new BigAssFanDevice();
61         try {
62             // Create a socket on the UDP port and get send & receive buffers
63             DatagramSocket localDatagramSocket = new DatagramSocket(BAF_PORT);
64             localDatagramSocket.setSoTimeout(SOCKET_RECEIVE_TIMEOUT);
65             localDatagramSocket.setBroadcast(true);
66             dSocket = localDatagramSocket;
67             rcvBuffer = new byte[256];
68             rcvPacket = new DatagramPacket(rcvBuffer, rcvBuffer.length);
69             bcastAddress = InetAddress.getByName(BCAST_ADDRESS);
70             bcastBuffer = POLL_MESSAGE.getBytes(StandardCharsets.US_ASCII);
71             bcastPacket = new DatagramPacket(bcastBuffer, bcastBuffer.length, bcastAddress, BAF_PORT);
72         } catch (UnknownHostException | SocketException | SecurityException e) {
73             logger.warn("Unexpected exception sending poll request for fans: {}", e.getMessage(), e);
74         }
75     }
76
77     public BigAssFanDevice waitForMessage() throws IOException, SocketTimeoutException {
78         // Wait to receive a packet
79         DatagramPacket localPacket = rcvPacket;
80         DatagramSocket localDatagramSocket = dSocket;
81
82         if (localPacket != null) {
83             localPacket.setLength(rcvBuffer.length);
84         }
85
86         if (localDatagramSocket != null && localPacket != null) {
87             localDatagramSocket.receive(localPacket);
88
89             // Process the received packet
90             device.reset();
91
92             String address = localPacket.getAddress().getHostAddress();
93             device.setIpAddress(address != null ? address : "");
94
95             String message = (new String(rcvBuffer, 0, localPacket.getLength()));
96             device.setDiscoveryMessage(message);
97             logger.debug("RECEIVED packet of length {} from {}: {}", message.length(), device.getIpAddress(), message);
98         }
99
100         return device;
101     }
102
103     public void pollForDevices() {
104         DatagramSocket localDatagramSocket = dSocket;
105         if (localDatagramSocket == null) {
106             logger.debug("Socket is null in discoveryListener.pollForDevices()");
107             return;
108         }
109
110         logger.debug("Sending poll request for fans: {}", POLL_MESSAGE);
111         try {
112             localDatagramSocket.send(bcastPacket);
113         } catch (IllegalArgumentException | SecurityException | IOException e) {
114             logger.warn("Unexpected exception while sending poll request for fans: {}", e.getMessage(), e);
115         }
116     }
117
118     public void shutdown() {
119         logger.debug("DiscoveryListener closing socket");
120         DatagramSocket localDatagramSocket = dSocket;
121         if (localDatagramSocket != null) {
122             localDatagramSocket.close();
123             dSocket = null;
124         }
125     }
126 }