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.silvercrestwifisocket.internal.runnable;
15 import java.io.IOException;
16 import java.net.DatagramPacket;
17 import java.net.DatagramSocket;
18 import java.net.SocketException;
19 import java.net.SocketTimeoutException;
21 import org.openhab.binding.silvercrestwifisocket.internal.exceptions.NotOneResponsePacketException;
22 import org.openhab.binding.silvercrestwifisocket.internal.exceptions.PacketIntegrityErrorException;
23 import org.openhab.binding.silvercrestwifisocket.internal.handler.SilvercrestWifiSocketMediator;
24 import org.openhab.binding.silvercrestwifisocket.internal.utils.WifiSocketPacketConverter;
25 import org.slf4j.Logger;
26 import org.slf4j.LoggerFactory;
29 * This Thread is responsible to receive all Wifi Socket messages and redirect them to
30 * {@link SilvercrestWifiSocketMediator}.
32 * @author Jaime Vaz - Initial contribution
35 public class SilvercrestWifiSocketUpdateReceiverRunnable implements Runnable {
37 private static final int TIMEOUT_TO_DATAGRAM_RECEPTION = 10000;
39 private final Logger logger = LoggerFactory.getLogger(SilvercrestWifiSocketUpdateReceiverRunnable.class);
41 private DatagramSocket datagramSocket;
42 private final SilvercrestWifiSocketMediator mediator;
43 private final WifiSocketPacketConverter packetConverter = new WifiSocketPacketConverter();
45 private boolean shutdown;
46 private int listeningPort;
49 * Constructor of the receiver runnable thread.
51 * @param mediator the {@link SilvercrestWifiSocketMediator}
52 * @param listeningPort the listening UDP port
53 * @throws SocketException is some problem occurs opening the socket.
55 public SilvercrestWifiSocketUpdateReceiverRunnable(final SilvercrestWifiSocketMediator mediator,
56 final int listeningPort) throws SocketException {
57 logger.debug("Starting Update Receiver Runnable...");
58 // Create a socket to listen on the port.
59 this.listeningPort = listeningPort;
60 this.mediator = mediator;
62 logger.debug("Opening socket and start listening UDP port: {}", listeningPort);
63 this.datagramSocket = new DatagramSocket(listeningPort);
64 this.datagramSocket.setSoTimeout(TIMEOUT_TO_DATAGRAM_RECEPTION);
65 logger.debug("Update Receiver Runnable and socket started with success...");
67 this.shutdown = false;
72 // Now loop forever, waiting to receive packets and redirect them to mediator.
73 while (!this.shutdown) {
74 datagramSocketHealthRoutine();
75 // Create a buffer to read datagrams into. If a
76 // packet is larger than this buffer, the
77 // excess will simply be discarded!
78 byte[] buffer = new byte[2048];
80 // Create a packet to receive data into the buffer
81 DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
82 // Wait to receive a datagram
84 this.datagramSocket.receive(packet);
86 logger.debug("Received packet from: {}. Will process the packet...",
87 packet.getAddress().getHostAddress());
89 // Do mediator something with it
90 this.mediator.processReceivedPacket(this.packetConverter.decryptResponsePacket(packet));
92 logger.debug("Message delivered with success to mediator.");
93 } catch (SocketTimeoutException e) {
94 logger.trace("Socket Timeout receiving packet.");
95 } catch (IOException e) {
96 logger.debug("One exception has occurred: {} ", e.getMessage());
97 } catch (PacketIntegrityErrorException e) {
98 logger.debug("Packet has one integrity error: {}", e.getMessage());
99 } catch (NotOneResponsePacketException e) {
101 "The message received is not one response. Probably the message received is one broadcast message looking for the socket.");
106 if (datagramSocket != null) {
107 datagramSocket.close();
111 private void datagramSocketHealthRoutine() {
112 if (datagramSocket == null || datagramSocket.isClosed()) {
113 logger.debug("Datagram Socket has been closed, will reconnect again...");
114 DatagramSocket newDatagramSocket = null;
116 newDatagramSocket = new DatagramSocket(listeningPort);
117 newDatagramSocket.setSoTimeout(TIMEOUT_TO_DATAGRAM_RECEPTION);
118 datagramSocket = newDatagramSocket;
119 logger.debug("Datagram Socket reconnected.");
120 } catch (SocketException exception) {
121 logger.error("Problem creating one new socket on port {}. Error: {}", listeningPort,
122 exception.getLocalizedMessage());
128 * Gracefully shutdown thread. Worst case takes TIMEOUT_TO_DATAGRAM_RECEPTION to shutdown.
130 public void shutdown() {
131 this.shutdown = true;