2 * Copyright (c) 2010-2023 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.bigassfan.internal.discovery;
15 import static org.openhab.binding.bigassfan.internal.BigAssFanBindingConstants.BAF_PORT;
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;
26 import org.eclipse.jdt.annotation.NonNullByDefault;
27 import org.eclipse.jdt.annotation.Nullable;
28 import org.slf4j.Logger;
29 import org.slf4j.LoggerFactory;
32 * The {@link DiscoveryListener} is responsible for listening on the UDP socket for fan discovery messages.
34 * @author Mark Hilbush - Initial contribution
37 public class DiscoveryListener {
38 private final Logger logger = LoggerFactory.getLogger(DiscoveryListener.class);
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>";
45 DatagramSocket dSocket;
47 DatagramPacket rcvPacket;
48 byte[] rcvBuffer = new byte[0];
50 InetAddress bcastAddress;
51 byte[] bcastBuffer = new byte[0];
53 DatagramPacket bcastPacket;
55 BigAssFanDevice device;
57 public DiscoveryListener() throws IOException, SocketException {
58 logger.debug("DiscoveryListener opening UDP broadcast socket");
60 device = new BigAssFanDevice();
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);
77 public BigAssFanDevice waitForMessage() throws IOException, SocketTimeoutException {
78 // Wait to receive a packet
79 DatagramPacket localPacket = rcvPacket;
80 DatagramSocket localDatagramSocket = dSocket;
82 if (localPacket != null) {
83 localPacket.setLength(rcvBuffer.length);
86 if (localDatagramSocket != null && localPacket != null) {
87 localDatagramSocket.receive(localPacket);
89 // Process the received packet
92 String address = localPacket.getAddress().getHostAddress();
93 device.setIpAddress(address != null ? address : "");
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);
103 public void pollForDevices() {
104 DatagramSocket localDatagramSocket = dSocket;
105 if (localDatagramSocket == null) {
106 logger.debug("Socket is null in discoveryListener.pollForDevices()");
110 logger.debug("Sending poll request for fans: {}", POLL_MESSAGE);
112 localDatagramSocket.send(bcastPacket);
113 } catch (IllegalArgumentException | SecurityException | IOException e) {
114 logger.warn("Unexpected exception while sending poll request for fans: {}", e.getMessage(), e);
118 public void shutdown() {
119 logger.debug("DiscoveryListener closing socket");
120 DatagramSocket localDatagramSocket = dSocket;
121 if (localDatagramSocket != null) {
122 localDatagramSocket.close();