]> git.basschouten.com Git - openhab-addons.git/blob
56826cb583ade42167545d15830de1024bb9c724
[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.yamahamusiccast.internal;
14
15 import java.io.IOException;
16 import java.net.DatagramPacket;
17 import java.net.DatagramSocket;
18 import java.net.InetSocketAddress;
19 import java.net.SocketException;
20 import java.net.SocketTimeoutException;
21 import java.util.UUID;
22 import java.util.concurrent.ExecutorService;
23 import java.util.concurrent.Executors;
24 import java.util.concurrent.Future;
25
26 import org.eclipse.jdt.annotation.NonNullByDefault;
27 import org.eclipse.jdt.annotation.Nullable;
28 import org.openhab.binding.yamahamusiccast.internal.dto.UdpMessage;
29 import org.openhab.core.common.NamedThreadFactory;
30 import org.openhab.core.thing.Bridge;
31 import org.openhab.core.thing.ChannelUID;
32 import org.openhab.core.thing.Thing;
33 import org.openhab.core.thing.ThingStatus;
34 import org.openhab.core.thing.ThingStatusInfo;
35 import org.openhab.core.thing.binding.BaseBridgeHandler;
36 import org.openhab.core.types.Command;
37 import org.slf4j.Logger;
38 import org.slf4j.LoggerFactory;
39
40 import com.google.gson.Gson;
41
42 /**
43  * The {@link YamahaMusiccastBridgeHandler} is responsible for dispatching UDP events to linked Things.
44  *
45  * @author Lennert Coopman - Initial contribution
46  */
47 @NonNullByDefault
48 public class YamahaMusiccastBridgeHandler extends BaseBridgeHandler {
49     private Gson gson = new Gson();
50     private final Logger logger = LoggerFactory.getLogger(YamahaMusiccastBridgeHandler.class);
51     private String threadname = getThing().getUID().getAsString();
52     private @Nullable ExecutorService executor;
53     private @Nullable Future<?> eventListenerJob;
54     private static final int UDP_PORT = 41100;
55     private static final int SOCKET_TIMEOUT_MILLISECONDS = 3000;
56     private static final int BUFFER_SIZE = 5120;
57     private @Nullable DatagramSocket socket;
58
59     private void receivePackets() {
60         try {
61             DatagramSocket s = new DatagramSocket(null);
62             s.setSoTimeout(SOCKET_TIMEOUT_MILLISECONDS);
63             s.setReuseAddress(true);
64             InetSocketAddress address = new InetSocketAddress(UDP_PORT);
65             s.bind(address);
66             socket = s;
67             logger.trace("UDP Listener got socket on port {} with timeout {}", UDP_PORT, SOCKET_TIMEOUT_MILLISECONDS);
68         } catch (SocketException e) {
69             logger.trace("UDP Listener got SocketException: {}", e.getMessage(), e);
70             socket = null;
71             return;
72         }
73
74         DatagramPacket packet = new DatagramPacket(new byte[BUFFER_SIZE], BUFFER_SIZE);
75         DatagramSocket localSocket = socket;
76         while (localSocket != null) {
77             try {
78                 localSocket.receive(packet);
79                 String received = new String(packet.getData(), 0, packet.getLength());
80                 String trackingID = UUID.randomUUID().toString().replace("-", "").substring(0, 32);
81                 logger.trace("Received packet: {} (Tracking: {})", received, trackingID);
82                 handleUDPEvent(received, trackingID);
83             } catch (SocketTimeoutException e) {
84                 // Nothing to do on socket timeout
85             } catch (IOException e) {
86                 logger.trace("UDP Listener got IOException waiting for datagram: {}", e.getMessage());
87                 localSocket = null;
88             }
89         }
90         logger.trace("UDP Listener exiting");
91     }
92
93     public YamahaMusiccastBridgeHandler(Bridge bridge) {
94         super(bridge);
95     }
96
97     @Override
98     public void handleCommand(ChannelUID channelUID, Command command) {
99     }
100
101     @Override
102     public void initialize() {
103         updateStatus(ThingStatus.ONLINE);
104         executor = Executors.newSingleThreadExecutor(new NamedThreadFactory(threadname));
105         Future<?> localEventListenerJob = eventListenerJob;
106         ExecutorService localExecutor = executor;
107         if (localEventListenerJob == null || localEventListenerJob.isCancelled()) {
108             if (localExecutor != null) {
109                 localEventListenerJob = localExecutor.submit(this::receivePackets);
110             }
111         }
112     }
113
114     @Override
115     public void dispose() {
116         super.dispose();
117         Future<?> localEventListenerJob = eventListenerJob;
118         ExecutorService localExecutor = executor;
119         if (localEventListenerJob != null) {
120             localEventListenerJob.cancel(true);
121             localEventListenerJob = null;
122         }
123         if (localExecutor != null) {
124             localExecutor.shutdownNow();
125             localExecutor = null;
126         }
127     }
128
129     public void handleUDPEvent(String json, String trackingID) {
130         String udpDeviceId = "";
131         Bridge bridge = (Bridge) thing;
132         for (Thing thing : bridge.getThings()) {
133             ThingStatusInfo statusInfo = thing.getStatusInfo();
134             switch (statusInfo.getStatus()) {
135                 case ONLINE:
136                     logger.trace("Thing Status: ONLINE - {}", thing.getLabel());
137                     YamahaMusiccastHandler handler = (YamahaMusiccastHandler) thing.getHandler();
138                     if (handler != null) {
139                         logger.trace("UDP: {} - {} ({} - Tracking: {})", json, handler.getDeviceId(), thing.getLabel(),
140                                 trackingID);
141
142                         @Nullable
143                         UdpMessage targetObject = gson.fromJson(json, UdpMessage.class);
144                         if (targetObject != null) {
145                             udpDeviceId = targetObject.getDeviceId();
146                             if (udpDeviceId.equals(handler.getDeviceId())) {
147                                 handler.processUDPEvent(json, trackingID);
148                             }
149                         }
150                     }
151                     break;
152                 default:
153                     logger.trace("Thing Status: NOT ONLINE - {} (Tracking: {})", thing.getLabel(), trackingID);
154                     break;
155             }
156         }
157     }
158 }