diff --git a/pom.xml b/pom.xml
index 5d7ea6b..a416f62 100644
--- a/pom.xml
+++ b/pom.xml
@@ -11,7 +11,7 @@
4.0.0
info.unterrainer.commons.udp-observer
udp-observer
- 0.1.9
+ 0.1.10
UdpObserver
jar
diff --git a/src/main/java/info/unterrainer/commons/udpobserver/UdpSender.java b/src/main/java/info/unterrainer/commons/udpobserver/UdpSender.java
new file mode 100644
index 0000000..99ff0db
--- /dev/null
+++ b/src/main/java/info/unterrainer/commons/udpobserver/UdpSender.java
@@ -0,0 +1,117 @@
+package info.unterrainer.commons.udpobserver;
+
+import java.io.IOException;
+import java.net.DatagramPacket;
+import java.net.DatagramSocket;
+import java.net.InetAddress;
+import java.net.InterfaceAddress;
+import java.net.NetworkInterface;
+import java.net.SocketException;
+import java.net.UnknownHostException;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.Objects;
+
+import info.unterrainer.commons.udpobserver.exceptions.UdpSendException;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+@RequiredArgsConstructor
+public class UdpSender {
+
+ private final int senderPort;
+ private DatagramSocket sendSocket;
+ private List broadcastAddresses;
+
+ protected List getBroadcastAddresses() {
+ if (broadcastAddresses != null)
+ return broadcastAddresses;
+
+ try {
+ broadcastAddresses = getAllBroadcastAddresses();
+ } catch (SocketException e) {
+ return List.of();
+ }
+ return broadcastAddresses;
+ }
+
+ protected DatagramSocket getSendSocket() {
+ if (sendSocket == null) {
+ try {
+ sendSocket = new DatagramSocket(senderPort, InetAddress.getLocalHost());
+ } catch (SocketException | UnknownHostException e) {
+ log.error("Error retrieving socket.", e);
+ throw new UdpSendException(e);
+ }
+ try {
+ sendSocket.setBroadcast(true);
+ } catch (SocketException e) {
+ log.error("Error setting broadcast-mode.", e);
+ throw new UdpSendException(e);
+ }
+ }
+ return sendSocket;
+ }
+
+ public void broadcast(final int targetPort, final String content) {
+ broadcast(targetPort, content.getBytes(StandardCharsets.UTF_8));
+ }
+
+ public void broadcast(final int targetPort, final byte[] bytes) {
+ for (InetAddress address : getBroadcastAddresses())
+ try {
+ send(address, targetPort, bytes);
+ } catch (Exception e) {
+ // NOOP
+ }
+ }
+
+ public void send(final InetAddress targetAddress, final int targetPort, final String content) {
+ send(targetAddress.getHostAddress(), targetPort, content);
+ }
+
+ public void send(final InetAddress targetAddress, final int targetPort, final byte[] bytes) {
+ send(targetAddress.getHostAddress(), targetPort, bytes);
+ }
+
+ public void send(final String targetAddress, final int targetPort, final String content) {
+ send(targetAddress, targetPort, content.getBytes(StandardCharsets.UTF_8));
+ }
+
+ public void send(final String targetAddress, final int targetPort, final byte[] bytes) {
+ DatagramPacket packet;
+ try {
+ packet = new DatagramPacket(bytes, bytes.length, InetAddress.getByName(targetAddress), targetPort);
+ } catch (UnknownHostException e) {
+ log.error("Error creating new packet.", e);
+ throw new UdpSendException(e);
+ }
+ try {
+ getSendSocket().send(packet);
+ } catch (IOException e) {
+ log.error("Error sending packet.", e);
+ throw new UdpSendException(e);
+ }
+ }
+
+ public List getAllBroadcastAddresses() throws SocketException {
+ List broadcastList = new ArrayList<>();
+ Enumeration interfaces = NetworkInterface.getNetworkInterfaces();
+ while (interfaces.hasMoreElements()) {
+ NetworkInterface networkInterface = interfaces.nextElement();
+
+ if (networkInterface.isLoopback() || !networkInterface.isUp())
+ continue;
+
+ networkInterface.getInterfaceAddresses()
+ .stream()
+ .map(InterfaceAddress::getBroadcast)
+ .filter(Objects::nonNull)
+ .forEach(broadcastList::add);
+ }
+ return broadcastList;
+ }
+}
diff --git a/src/main/java/info/unterrainer/commons/udpobserver/exceptions/UdpSendException.java b/src/main/java/info/unterrainer/commons/udpobserver/exceptions/UdpSendException.java
new file mode 100644
index 0000000..c24094c
--- /dev/null
+++ b/src/main/java/info/unterrainer/commons/udpobserver/exceptions/UdpSendException.java
@@ -0,0 +1,11 @@
+package info.unterrainer.commons.udpobserver.exceptions;
+
+public class UdpSendException extends RuntimeException {
+
+ private static final long serialVersionUID = 2243163797766428122L;
+
+ public UdpSendException(final Throwable cause) {
+ super(cause);
+ }
+
+}
diff --git a/src/main/java/info/unterrainer/commons/udpobserver/scripts/TestObserver.java b/src/main/java/info/unterrainer/commons/udpobserver/scripts/TestObserver.java
index c3026d4..a96f809 100644
--- a/src/main/java/info/unterrainer/commons/udpobserver/scripts/TestObserver.java
+++ b/src/main/java/info/unterrainer/commons/udpobserver/scripts/TestObserver.java
@@ -9,13 +9,10 @@
public class TestObserver {
- /**
- * STA:{"type":"ENOCEAN","adr":"fef2b30d","data":"eltako_button4","vendor":"eltako","state":{"BI":"pressed","BO":"released","AO":"released","AI":"released"}}
- */
private static DateTimeFormatter formatter = DateTimeFormatter.ISO_DATE_TIME;
public static void main(final String[] args) throws InterruptedException, IOException {
- UdpObserver observer = new UdpObserver(1901, 256, 1000);
+ UdpObserver observer = new UdpObserver(8001, 256, 1000);
observer.start();
System.out.println("listening for UDP packets...");
System.out.println("press to stop.");
diff --git a/src/main/java/info/unterrainer/commons/udpobserver/scripts/TestObserverSender.java b/src/main/java/info/unterrainer/commons/udpobserver/scripts/TestObserverSender.java
new file mode 100644
index 0000000..7432153
--- /dev/null
+++ b/src/main/java/info/unterrainer/commons/udpobserver/scripts/TestObserverSender.java
@@ -0,0 +1,29 @@
+package info.unterrainer.commons.udpobserver.scripts;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.util.List;
+
+import info.unterrainer.commons.udpobserver.UdpSender;
+
+public class TestObserverSender {
+
+ public static void main(final String[] args) throws InterruptedException, IOException {
+ UdpSender sender = new UdpSender(8002);
+
+ List broadcastAddresses = sender.getAllBroadcastAddresses();
+ System.out.println("found broadcast addresses:");
+ for (InetAddress address : broadcastAddresses)
+ System.out.println(" - " + address.getHostAddress());
+
+ System.out.println("sending UDP packets to port 8001...");
+ System.out.println("press to stop.");
+ while (System.in.available() == 0) {
+ sender.broadcast(8001, "TestPacket!");
+
+ System.out.println("Packet sent.");
+ Thread.sleep(1000L);
+ }
+ System.out.println("done.");
+ }
+}
diff --git a/src/main/java/info/unterrainer/commons/udpobserver/scripts/TestObserverShelly.java b/src/main/java/info/unterrainer/commons/udpobserver/scripts/TestObserverShelly.java
new file mode 100644
index 0000000..fb5d2be
--- /dev/null
+++ b/src/main/java/info/unterrainer/commons/udpobserver/scripts/TestObserverShelly.java
@@ -0,0 +1,35 @@
+package info.unterrainer.commons.udpobserver.scripts;
+
+import java.io.IOException;
+import java.time.format.DateTimeFormatter;
+import java.util.Collection;
+
+import info.unterrainer.commons.udpobserver.UdpDatagram;
+import info.unterrainer.commons.udpobserver.UdpObserver;
+
+public class TestObserverShelly {
+
+ /**
+ * STA:{"type":"ENOCEAN","adr":"fef2b30d","data":"eltako_button4","vendor":"eltako","state":{"BI":"pressed","BO":"released","AO":"released","AI":"released"}}
+ */
+ private static DateTimeFormatter formatter = DateTimeFormatter.ISO_DATE_TIME;
+
+ public static void main(final String[] args) throws InterruptedException, IOException {
+ UdpObserver observer = new UdpObserver(1901, 256, 1000);
+ observer.start();
+ System.out.println("listening for UDP packets...");
+ System.out.println("press to stop.");
+ while (System.in.available() == 0) {
+ Thread.sleep(100L);
+ outputList(observer.getReceivedDatagrams());
+ }
+ observer.close();
+ System.out.println("done.");
+ }
+
+ private static void outputList(final Collection list) {
+ for (UdpDatagram data : list)
+ System.out.println(
+ String.format("[%s] %s", data.getMetaData().getTimestamp().format(formatter), data.getContent()));
+ }
+}
diff --git a/start_test_observer.bat b/start_test_observer.bat
new file mode 100644
index 0000000..1b108b1
--- /dev/null
+++ b/start_test_observer.bat
@@ -0,0 +1 @@
+java -cp "target/libs/*;target/classes" info.unterrainer.commons.udpobserver.scripts.TestObserver
\ No newline at end of file
diff --git a/start_test_observer.sh b/start_test_observer.sh
new file mode 100644
index 0000000..1b108b1
--- /dev/null
+++ b/start_test_observer.sh
@@ -0,0 +1 @@
+java -cp "target/libs/*;target/classes" info.unterrainer.commons.udpobserver.scripts.TestObserver
\ No newline at end of file