]> git.basschouten.com Git - openhab-addons.git/blob
dab6c640fc4b0d8733b13d875d1f58f6e01440a4
[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.silvercrestwifisocket.internal.runnable;
14
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;
20
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;
27
28 /**
29  * This Thread is responsible to receive all Wifi Socket messages and redirect them to
30  * {@link SilvercrestWifiSocketMediator}.
31  *
32  * @author Jaime Vaz - Initial contribution
33  *
34  */
35 public class SilvercrestWifiSocketUpdateReceiverRunnable implements Runnable {
36
37     private static final int TIMEOUT_TO_DATAGRAM_RECEPTION = 10000;
38
39     private final Logger logger = LoggerFactory.getLogger(SilvercrestWifiSocketUpdateReceiverRunnable.class);
40
41     private DatagramSocket datagramSocket;
42     private final SilvercrestWifiSocketMediator mediator;
43     private final WifiSocketPacketConverter packetConverter = new WifiSocketPacketConverter();
44
45     private boolean shutdown;
46     private int listeningPort;
47
48     /**
49      * Constructor of the receiver runnable thread.
50      *
51      * @param mediator the {@link SilvercrestWifiSocketMediator}
52      * @param listeningPort the listening UDP port
53      * @throws SocketException is some problem occurs opening the socket.
54      */
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;
61
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...");
66
67         this.shutdown = false;
68     }
69
70     @Override
71     public void run() {
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];
79
80             // Create a packet to receive data into the buffer
81             DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
82             // Wait to receive a datagram
83             try {
84                 this.datagramSocket.receive(packet);
85
86                 logger.debug("Received packet from: {}. Will process the packet...",
87                         packet.getAddress().getHostAddress());
88
89                 // Do mediator something with it
90                 this.mediator.processReceivedPacket(this.packetConverter.decryptResponsePacket(packet));
91
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) {
100                 logger.debug(
101                         "The message received is not one response. Probably the message received is one broadcast message looking for the socket.");
102             }
103         }
104
105         // close the socket
106         if (datagramSocket != null) {
107             datagramSocket.close();
108         }
109     }
110
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;
115             try {
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());
123             }
124         }
125     }
126
127     /**
128      * Gracefully shutdown thread. Worst case takes TIMEOUT_TO_DATAGRAM_RECEPTION to shutdown.
129      */
130     public void shutdown() {
131         this.shutdown = true;
132     }
133 }