[Network] Added param to differentiate between mac and IP WOL Request (#11387)
* Added possiblity to send WOL Requests to configured Hostname, also removed unnecessary unit from Timeout Annotation in WakeOnLanPacketSenderTest * Introduced parameter to decide whether to send WOL via IP or MAC * Added two Methods for user clarity, marked old method as deprecated, adjusted README * Updated internal methods to use explicit calls as well, added deprecated method call to README Signed-off-by: Jonathan Saxen <jonathan@saxen.info>pull/11479/head
parent
3bd2939b6c
commit
1d07dbe1f5
|
@ -250,6 +250,11 @@ if (actions === null) {
|
|||
logInfo("actions", "Actions not found, check thing ID")
|
||||
return
|
||||
} else {
|
||||
actions.sendWakeOnLanPacket()
|
||||
// Send via MAC address
|
||||
actions.sendWakeOnLanPacketViaMac()
|
||||
actions.sendWakeOnLanPacket() // deprecated
|
||||
|
||||
// Send via IP address
|
||||
actions.sendWakeOnLanPacketViaIp()
|
||||
}
|
||||
```
|
||||
|
|
|
@ -54,21 +54,28 @@ public class WakeOnLanPacketSender {
|
|||
@Nullable
|
||||
private final Integer port;
|
||||
|
||||
private byte @Nullable [] magicPacket;
|
||||
private final Consumer<byte[]> magicPacketSender;
|
||||
private final Consumer<byte[]> magicPacketMacSender;
|
||||
private final Consumer<byte[]> magicPacketIpSender;
|
||||
|
||||
public WakeOnLanPacketSender(String macAddress, @Nullable String hostname, @Nullable Integer port) {
|
||||
logger.debug("initialized WOL Packet Sender (mac: {}, hostname: {}, port: {}", macAddress, hostname, port);
|
||||
this.macAddress = macAddress;
|
||||
this.hostname = hostname;
|
||||
this.port = port;
|
||||
this.magicPacketSender = this::sendMagicPacket;
|
||||
this.magicPacketMacSender = this::sendMagicPacketViaMac;
|
||||
this.magicPacketIpSender = this::sendMagicPacketViaIp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used for testing only.
|
||||
*/
|
||||
public WakeOnLanPacketSender(String macAddress) {
|
||||
logger.debug("initialized WOL Packet Sender (mac: {}", macAddress);
|
||||
this.macAddress = macAddress;
|
||||
this.hostname = null;
|
||||
this.port = null;
|
||||
this.magicPacketSender = this::sendMagicPacket;
|
||||
this.magicPacketMacSender = this::sendMagicPacketViaMac;
|
||||
this.magicPacketIpSender = this::sendMagicPacketViaIp;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -78,17 +85,28 @@ public class WakeOnLanPacketSender {
|
|||
this.macAddress = macAddress;
|
||||
this.hostname = null;
|
||||
this.port = null;
|
||||
this.magicPacketSender = magicPacketSender;
|
||||
this.magicPacketMacSender = magicPacketSender;
|
||||
this.magicPacketIpSender = this::sendMagicPacketViaIp;
|
||||
}
|
||||
|
||||
public void sendPacket() {
|
||||
byte[] localMagicPacket = magicPacket;
|
||||
if (localMagicPacket == null) {
|
||||
localMagicPacket = createMagicPacket(createMacBytes(macAddress));
|
||||
magicPacket = localMagicPacket;
|
||||
}
|
||||
public void sendWakeOnLanPacketViaMac() {
|
||||
byte[] magicPacket = createMagicPacket();
|
||||
this.magicPacketMacSender.accept(magicPacket);
|
||||
}
|
||||
|
||||
magicPacketSender.accept(localMagicPacket);
|
||||
public void sendWakeOnLanPacketViaIp() {
|
||||
byte[] magicPacket = createMagicPacket();
|
||||
this.magicPacketIpSender.accept(magicPacket);
|
||||
}
|
||||
|
||||
private byte[] createMagicPacket() {
|
||||
byte[] macBytes = createMacBytes(this.macAddress);
|
||||
byte[] magicPacket = new byte[MAGIC_PACKET_BYTE_SIZE];
|
||||
Arrays.fill(magicPacket, 0, PREFIX_BYTE_SIZE, (byte) 0xff);
|
||||
for (int i = PREFIX_BYTE_SIZE; i < MAGIC_PACKET_BYTE_SIZE; i += MAC_BYTE_SIZE) {
|
||||
System.arraycopy(macBytes, 0, magicPacket, i, macBytes.length);
|
||||
}
|
||||
return magicPacket;
|
||||
}
|
||||
|
||||
private byte[] createMacBytes(String macAddress) {
|
||||
|
@ -102,23 +120,24 @@ public class WakeOnLanPacketSender {
|
|||
return HexUtils.hexToBytes(hexString);
|
||||
}
|
||||
|
||||
private byte[] createMagicPacket(byte[] macBytes) {
|
||||
byte[] bytes = new byte[MAGIC_PACKET_BYTE_SIZE];
|
||||
Arrays.fill(bytes, 0, PREFIX_BYTE_SIZE, (byte) 0xff);
|
||||
for (int i = PREFIX_BYTE_SIZE; i < MAGIC_PACKET_BYTE_SIZE; i += MAC_BYTE_SIZE) {
|
||||
System.arraycopy(macBytes, 0, bytes, i, macBytes.length);
|
||||
private void sendMagicPacketViaMac(byte[] magicPacket) {
|
||||
try (DatagramSocket socket = new DatagramSocket()) {
|
||||
logger.debug("Sending Wake-on-LAN Packet via Broadcast");
|
||||
broadcastMagicPacket(magicPacket, socket);
|
||||
} catch (SocketException e) {
|
||||
logger.error("Failed to open Wake-on-LAN datagram socket", e);
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
private void sendMagicPacket(byte[] magicPacket) {
|
||||
private void sendMagicPacketViaIp(byte[] magicPacket) {
|
||||
try (DatagramSocket socket = new DatagramSocket()) {
|
||||
if (StringUtils.isEmpty(hostname)) {
|
||||
broadcastMagicPacket(magicPacket, socket);
|
||||
} else {
|
||||
if (!StringUtils.isEmpty(this.hostname)) {
|
||||
logger.debug("Sending Wake-on-LAN Packet via IP Address");
|
||||
SocketAddress socketAddress = new InetSocketAddress(this.hostname,
|
||||
Objects.requireNonNullElse(this.port, WOL_UDP_PORT));
|
||||
sendMagicPacketToIp(magicPacket, socket, socketAddress);
|
||||
} else {
|
||||
throw new IllegalStateException("Hostname is not set!");
|
||||
}
|
||||
} catch (SocketException e) {
|
||||
logger.error("Failed to open Wake-on-LAN datagram socket", e);
|
||||
|
@ -131,14 +150,14 @@ public class WakeOnLanPacketSender {
|
|||
DatagramPacket packet = new DatagramPacket(magicPacket, MAGIC_PACKET_BYTE_SIZE, broadcastAddress,
|
||||
WOL_UDP_PORT);
|
||||
socket.send(packet);
|
||||
logger.debug("Wake-on-LAN packet sent (MAC address: {}, broadcast address: {})", macAddress,
|
||||
logger.debug("Wake-on-LAN packet sent (MAC address: {}, broadcast address: {})", this.macAddress,
|
||||
broadcastAddress.getHostAddress());
|
||||
} catch (IOException e) {
|
||||
logger.debug("Failed to send Wake-on-LAN packet (MAC address: {}, broadcast address: {})", macAddress,
|
||||
broadcastAddress.getHostAddress(), e);
|
||||
logger.error("Failed to send Wake-on-LAN packet (MAC address: {}, broadcast address: {})",
|
||||
this.macAddress, broadcastAddress.getHostAddress(), e);
|
||||
}
|
||||
});
|
||||
logger.info("Wake-on-LAN packets sent (MAC address: {})", macAddress);
|
||||
logger.info("Wake-on-LAN packets sent (MAC address: {})", this.macAddress);
|
||||
}
|
||||
|
||||
private void sendMagicPacketToIp(byte[] magicPacket, DatagramSocket socket, SocketAddress ip) {
|
||||
|
@ -146,9 +165,9 @@ public class WakeOnLanPacketSender {
|
|||
try {
|
||||
socket.send(packet);
|
||||
} catch (IOException e) {
|
||||
logger.debug("Failed to send Wake-on-LAN packet (MAC address: {}, address: {})", macAddress, ip, e);
|
||||
logger.error("Failed to send Wake-on-LAN packet (IP address: {})", ip, e);
|
||||
}
|
||||
logger.info("Wake-on-LAN packets sent (MAC address: {}, IP address: {})", macAddress, ip);
|
||||
logger.info("Wake-on-LAN packets sent (IP address: {})", ip);
|
||||
}
|
||||
|
||||
private Stream<InetAddress> broadcastAddressStream() {
|
||||
|
@ -156,7 +175,7 @@ public class WakeOnLanPacketSender {
|
|||
try {
|
||||
return InetAddress.getByName(address);
|
||||
} catch (UnknownHostException e) {
|
||||
logger.debug("Failed to get broadcast address '{}' by name", address, e);
|
||||
logger.error("Failed to get broadcast address '{}' by name", address, e);
|
||||
return null;
|
||||
}
|
||||
}).filter(Objects::nonNull);
|
||||
|
|
|
@ -47,17 +47,36 @@ public class NetworkActions implements ThingActions {
|
|||
return handler;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use sendWakeOnLanPacketViaMac or sendWakeOnLanPacketViaIp instead.
|
||||
*/
|
||||
@Deprecated
|
||||
@RuleAction(label = "send a WoL packet", description = "Send a Wake-on-LAN packet to wake the device.")
|
||||
public void sendWakeOnLanPacket() {
|
||||
sendWakeOnLanPacketViaMac();
|
||||
}
|
||||
|
||||
@RuleAction(label = "send a WoL packet", description = "Send a Wake-on-LAN packet to wake the device via Mac.")
|
||||
public void sendWakeOnLanPacketViaMac() {
|
||||
NetworkHandler localHandler = handler;
|
||||
if (localHandler != null) {
|
||||
localHandler.sendWakeOnLanPacket();
|
||||
localHandler.sendWakeOnLanPacketViaMac();
|
||||
} else {
|
||||
logger.warn("Failed to send Wake-on-LAN packet (handler null)");
|
||||
}
|
||||
}
|
||||
|
||||
@RuleAction(label = "send a WoL packet", description = "Send a Wake-on-LAN packet to wake the device via IP.")
|
||||
public void sendWakeOnLanPacketViaIp() {
|
||||
NetworkHandler localHandler = handler;
|
||||
if (localHandler != null) {
|
||||
localHandler.sendWakeOnLanPacketViaIp();
|
||||
} else {
|
||||
logger.warn("Failed to send Wake-on-LAN packet (handler null)");
|
||||
}
|
||||
}
|
||||
|
||||
public static void sendWakeOnLanPacket(ThingActions actions) {
|
||||
((NetworkActions) actions).sendWakeOnLanPacket();
|
||||
((NetworkActions) actions).sendWakeOnLanPacketViaMac();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -242,11 +242,16 @@ public class NetworkHandler extends BaseThingHandler
|
|||
return Collections.singletonList(NetworkActions.class);
|
||||
}
|
||||
|
||||
public void sendWakeOnLanPacket() {
|
||||
public void sendWakeOnLanPacketViaIp() {
|
||||
// Hostname can't be null
|
||||
wakeOnLanPacketSender.sendWakeOnLanPacketViaIp();
|
||||
}
|
||||
|
||||
public void sendWakeOnLanPacketViaMac() {
|
||||
if (handlerConfiguration.macAddress.isEmpty()) {
|
||||
throw new IllegalStateException(
|
||||
"Cannot send WoL packet because the 'macAddress' is not configured for " + thing.getUID());
|
||||
}
|
||||
wakeOnLanPacketSender.sendPacket();
|
||||
wakeOnLanPacketSender.sendWakeOnLanPacketViaMac();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -53,7 +53,7 @@ public class WakeOnLanPacketSenderTest {
|
|||
WakeOnLanPacketSender sender = new WakeOnLanPacketSender("6f:70:65:6e:48:41",
|
||||
bytes -> System.arraycopy(bytes, 0, actualPacket, 0, bytes.length));
|
||||
|
||||
sender.sendPacket();
|
||||
sender.sendWakeOnLanPacketViaMac();
|
||||
|
||||
assertValidMagicPacket(HexUtils.hexToBytes("6f:70:65:6e:48:41", ":"), actualPacket);
|
||||
}
|
||||
|
@ -65,7 +65,7 @@ public class WakeOnLanPacketSenderTest {
|
|||
WakeOnLanPacketSender sender = new WakeOnLanPacketSender("6F-70-65-6E-48-41",
|
||||
bytes -> System.arraycopy(bytes, 0, actualPacket, 0, bytes.length));
|
||||
|
||||
sender.sendPacket();
|
||||
sender.sendWakeOnLanPacketViaMac();
|
||||
|
||||
assertValidMagicPacket(HexUtils.hexToBytes("6F-70-65-6E-48-41", "-"), actualPacket);
|
||||
}
|
||||
|
@ -77,7 +77,7 @@ public class WakeOnLanPacketSenderTest {
|
|||
WakeOnLanPacketSender sender = new WakeOnLanPacketSender("6f70656e4841",
|
||||
bytes -> System.arraycopy(bytes, 0, actualPacket, 0, bytes.length));
|
||||
|
||||
sender.sendPacket();
|
||||
sender.sendWakeOnLanPacketViaMac();
|
||||
|
||||
assertValidMagicPacket(HexUtils.hexToBytes("6f70656e4841"), actualPacket);
|
||||
}
|
||||
|
@ -93,13 +93,13 @@ public class WakeOnLanPacketSenderTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void sendWithHostnameNullAndPortNull() throws IOException, InterruptedException {
|
||||
sendWOLTest(null, null);
|
||||
public void sendWithHostnameNullAndPortNull() {
|
||||
assertThrows(IllegalStateException.class, () -> sendWOLTest(null, null));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void sendWithHostnameNull() throws IOException, InterruptedException {
|
||||
sendWOLTest(null, 4444);
|
||||
public void sendWithHostnameNull() {
|
||||
assertThrows(IllegalStateException.class, () -> sendWOLTest(null, 4444));
|
||||
}
|
||||
|
||||
private void sendWOLTest(String hostname, Integer port) throws InterruptedException, IOException {
|
||||
|
@ -112,36 +112,41 @@ public class WakeOnLanPacketSenderTest {
|
|||
Thread.sleep(100);
|
||||
}
|
||||
|
||||
WakeOnLanPacketSender sender = new WakeOnLanPacketSender("6f70656e4841", hostname, port);
|
||||
sender.sendPacket();
|
||||
try {
|
||||
WakeOnLanPacketSender sender = new WakeOnLanPacketSender("6f70656e4841", hostname, port);
|
||||
sender.sendWakeOnLanPacketViaIp();
|
||||
|
||||
// This Test is only applicable for IP Requests
|
||||
if (hostname != null && port != null) {
|
||||
socket.receive(datagramPacket);
|
||||
// This Test is only applicable for IP Requests
|
||||
if (hostname != null && port != null) {
|
||||
socket.receive(datagramPacket);
|
||||
}
|
||||
|
||||
Assertions.assertTrue(datagramPacket.getData().length > 0);
|
||||
} finally {
|
||||
socket.close();
|
||||
}
|
||||
|
||||
socket.close();
|
||||
|
||||
Assertions.assertTrue(datagramPacket.getData().length > 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void sendWithEmptyMacAddressThrowsException() {
|
||||
assertThrows(IllegalStateException.class, () -> new WakeOnLanPacketSender("").sendPacket());
|
||||
assertThrows(IllegalStateException.class, () -> new WakeOnLanPacketSender("").sendWakeOnLanPacketViaMac());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void sendWithTooShortMacAddressThrowsException() {
|
||||
assertThrows(IllegalStateException.class, () -> new WakeOnLanPacketSender("6f:70:65:6e:48").sendPacket());
|
||||
assertThrows(IllegalStateException.class,
|
||||
() -> new WakeOnLanPacketSender("6f:70:65:6e:48").sendWakeOnLanPacketViaMac());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void sendWithTooLongMacAddressThrowsException() {
|
||||
assertThrows(IllegalStateException.class, () -> new WakeOnLanPacketSender("6f:70:65:6e:48:41:42").sendPacket());
|
||||
assertThrows(IllegalStateException.class,
|
||||
() -> new WakeOnLanPacketSender("6f:70:65:6e:48:41:42").sendWakeOnLanPacketViaMac());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void sendWithUnsupportedSeparatorInMacAddressThrowsException() {
|
||||
assertThrows(IllegalStateException.class, () -> new WakeOnLanPacketSender("6f=70=65=6e=48=41").sendPacket());
|
||||
assertThrows(IllegalStateException.class,
|
||||
() -> new WakeOnLanPacketSender("6f=70=65=6e=48=41").sendWakeOnLanPacketViaMac());
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue