]> git.basschouten.com Git - openhab-addons.git/blob
53e094b757eb805809691ee8739ee292948f7ccf
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2022 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.dmx.internal.dmxoverethernet;
14
15 import java.io.IOException;
16 import java.net.DatagramPacket;
17 import java.net.DatagramSocket;
18 import java.net.SocketException;
19 import java.util.ArrayList;
20 import java.util.List;
21
22 import org.openhab.binding.dmx.internal.DmxBridgeHandler;
23 import org.openhab.core.thing.Bridge;
24 import org.openhab.core.thing.ThingStatus;
25 import org.openhab.core.thing.ThingStatusDetail;
26 import org.slf4j.Logger;
27 import org.slf4j.LoggerFactory;
28
29 /**
30  * The {@link DmxOverEthernetHandler} is an abstract class with base functions
31  * for DMX over Ethernet Bridges (ArtNet, sACN)
32  *
33  * @author Jan N. Klug - Initial contribution
34  */
35
36 public abstract class DmxOverEthernetHandler extends DmxBridgeHandler {
37     private final Logger logger = LoggerFactory.getLogger(DmxOverEthernetHandler.class);
38
39     protected DmxOverEthernetPacket packetTemplate;
40     protected IpNode senderNode = new IpNode();
41     protected List<IpNode> receiverNodes = new ArrayList<>();
42
43     protected boolean refreshAlways = false;
44
45     DatagramSocket socket = null;
46     private long lastSend = 0;
47     private int repeatCounter = 0;
48     private int sequenceNo = 0;
49
50     @Override
51     protected void openConnection() {
52         if (getThing().getStatus() != ThingStatus.ONLINE) {
53             try {
54                 if (senderNode.getAddress() == null) {
55                     if (senderNode.getPort() == 0) {
56                         socket = new DatagramSocket();
57                         senderNode.setInetAddress(socket.getLocalAddress());
58                         senderNode.setPort(socket.getLocalPort());
59                     } else {
60                         socket = new DatagramSocket(senderNode.getPort());
61                         senderNode.setInetAddress(socket.getLocalAddress());
62                     }
63                 } else {
64                     socket = new DatagramSocket(senderNode.getPort(), senderNode.getAddress());
65                 }
66                 updateStatus(ThingStatus.ONLINE);
67                 logger.debug("opened socket {} in bridge {}", senderNode, this.thing.getUID());
68             } catch (SocketException e) {
69                 logger.debug("could not open socket {} in bridge {}: {}", senderNode, this.thing.getUID(),
70                         e.getMessage());
71                 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, "opening UDP socket failed");
72             }
73         }
74     }
75
76     @Override
77     protected void closeConnection() {
78         if (socket != null) {
79             logger.debug("closing socket {} in bridge {}", senderNode, this.thing.getUID());
80             socket.close();
81             socket = null;
82         } else {
83             logger.debug("socket was already closed when calling closeConnection in bridge {}", this.thing.getUID());
84         }
85         updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, "UDP socket closed");
86     }
87
88     @Override
89     protected void sendDmxData() {
90         if (getThing().getStatus() == ThingStatus.ONLINE) {
91             boolean needsSending = false;
92             long now = System.currentTimeMillis();
93             universe.calculateBuffer(now);
94             if ((universe.getLastBufferChanged() > lastSend) || refreshAlways) {
95                 needsSending = true;
96                 repeatCounter = 0;
97             } else if (now - lastSend > 800) {
98                 needsSending = true;
99             } else if (repeatCounter < 3) {
100                 needsSending = true;
101                 repeatCounter++;
102             }
103             if (needsSending) {
104                 packetTemplate.setPayload(universe.getBuffer(), universe.getBufferSize());
105                 packetTemplate.setSequence(sequenceNo);
106                 DatagramPacket sendPacket = new DatagramPacket(packetTemplate.getRawPacket(),
107                         packetTemplate.getPacketLength());
108                 for (IpNode receiverNode : receiverNodes) {
109                     sendPacket.setAddress(receiverNode.getAddress());
110                     sendPacket.setPort(receiverNode.getPort());
111                     logger.trace("sending packet with length {} to {}", packetTemplate.getPacketLength(),
112                             receiverNode.toString());
113                     try {
114                         socket.send(sendPacket);
115                     } catch (IOException e) {
116                         logger.debug("Could not send to {} in {}: {}", receiverNode, this.thing.getUID(),
117                                 e.getMessage());
118                         closeConnection(ThingStatusDetail.COMMUNICATION_ERROR, "could not send DMX data");
119                     }
120                 }
121                 lastSend = now;
122                 sequenceNo = (sequenceNo + 1) % 256;
123             }
124         } else {
125             openConnection();
126         }
127     }
128
129     public DmxOverEthernetHandler(Bridge sacnBridge) {
130         super(sacnBridge);
131     }
132 }