2 * Copyright (c) 2010-2022 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.dmx.internal.dmxoverethernet;
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;
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;
30 * The {@link DmxOverEthernetHandler} is an abstract class with base functions
31 * for DMX over Ethernet Bridges (ArtNet, sACN)
33 * @author Jan N. Klug - Initial contribution
36 public abstract class DmxOverEthernetHandler extends DmxBridgeHandler {
37 private final Logger logger = LoggerFactory.getLogger(DmxOverEthernetHandler.class);
39 protected DmxOverEthernetPacket packetTemplate;
40 protected IpNode senderNode = new IpNode();
41 protected List<IpNode> receiverNodes = new ArrayList<>();
43 protected boolean refreshAlways = false;
45 DatagramSocket socket = null;
46 private long lastSend = 0;
47 private int repeatCounter = 0;
48 private int sequenceNo = 0;
51 protected void openConnection() {
52 if (getThing().getStatus() != ThingStatus.ONLINE) {
54 if (senderNode.getAddress() == null) {
55 if (senderNode.getPort() == 0) {
56 socket = new DatagramSocket();
57 senderNode.setInetAddress(socket.getLocalAddress());
58 senderNode.setPort(socket.getLocalPort());
60 socket = new DatagramSocket(senderNode.getPort());
61 senderNode.setInetAddress(socket.getLocalAddress());
64 socket = new DatagramSocket(senderNode.getPort(), senderNode.getAddress());
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(),
71 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, "opening UDP socket failed");
77 protected void closeConnection() {
79 logger.debug("closing socket {} in bridge {}", senderNode, this.thing.getUID());
83 logger.debug("socket was already closed when calling closeConnection in bridge {}", this.thing.getUID());
85 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, "UDP socket closed");
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) {
97 } else if (now - lastSend > 800) {
99 } else if (repeatCounter < 3) {
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());
114 socket.send(sendPacket);
115 } catch (IOException e) {
116 logger.debug("Could not send to {} in {}: {}", receiverNode, this.thing.getUID(),
118 closeConnection(ThingStatusDetail.COMMUNICATION_ERROR, "could not send DMX data");
122 sequenceNo = (sequenceNo + 1) % 256;
129 public DmxOverEthernetHandler(Bridge sacnBridge) {