diff --git a/bundles/org.openhab.binding.anel/README.md b/bundles/org.openhab.binding.anel/README.md
index a587b952fbe02..e2189cb5c8f1a 100644
--- a/bundles/org.openhab.binding.anel/README.md
+++ b/bundles/org.openhab.binding.anel/README.md
@@ -10,13 +10,15 @@ Some NET-PwrCtrl devices also have 8 I/O ports which can either be used to direc
There are three kinds of devices ([overview on manufacturer's homepage](https://en.anel.eu/?src=/produkte/produkte.htm)):
-| [Anel NET-PwrCtrl HUT](https://en.anel.eu/?src=/produkte/hut_2/hut_2.htm) | [Anel NET-PwrCtrl IO](https://en.anel.eu/?src=/produkte/io/io.htm) | [Anel NET-PwrCtrl HOME](https://de.anel.eu/?src=produkte/home/home.htm) (only German version) |
+| [Anel NET-PwrCtrl HUT](https://en.anel.eu/?src=/produkte/hut_2/hut_2.htm)
( _advanced-firmware_ ) | [Anel NET-PwrCtrl IO](https://en.anel.eu/?src=/produkte/io/io.htm)
( _advanced-firmware_ ) | [Anel NET-PwrCtrl HOME](https://de.anel.eu/?src=produkte/home/home.htm)
( _home_ )
(only German version) |
| --- | --- | --- |
-| [![Anel NET-PwrCtrl HUT 2](https://de.anel.eu/image/leisten/HUT2LV-P_500.jpg)](https://de.anel.eu/?src=produkte/hut_2/hut_2.htm) | [![Anel NET-PwrCtrl IO](https://de.anel.eu/image/leisten/IO-Stecker.png)](https://de.anel.eu/?src=produkte/io/io.htm) | [![Anel NET-PwrCtrl HOME](https://de.anel.eu/image/leisten/HOME-DE-500.gif)](https://de.anel.eu/?src=produkte/home/home.htm)
+| [![Anel NET-PwrCtrl HUT 2](https://de.anel.eu/image/leisten/HUT2LV-P_500.jpg)](https://de.anel.eu/?src=produkte/hut_2/hut_2.htm) | [![Anel NET-PwrCtrl IO](https://de.anel.eu/image/leisten/IO-Stecker.png)](https://de.anel.eu/?src=produkte/io/io.htm) | [![Anel NET-PwrCtrl HOME](https://de.anel.eu/image/leisten/HOME-DE-500.gif)](https://de.anel.eu/?src=produkte/home/home.htm) |
-* The smallest device, the _HOME_, is the only one with only three power sockets and only available in Germany.
-* The _PRO_ and _REDUNDANT_ have eight power sockets and a similar (simplified) firmware as the _HOME_.
-* All others (_ADV_, _IO_, and the different _HUT_ variants) have eight power sockets / relays, eight IO ports, and an advanced firmware.
+Thing type IDs:
+
+* *home*: The smallest device, the _HOME_, is the only one with only three power sockets and only available in Germany.
+* *simple-firmware*: The _PRO_ and _REDUNDANT_ have eight power sockets and a similar (simplified) firmware as the _HOME_.
+* *advanced-firmware*: All others (_ADV_, _IO_, and the different _HUT_ variants) have eight power sockets / relays, eight IO ports, and an advanced firmware.
An [additional sensor](https://en.anel.eu/?src=/produkte/sensor_1/sensor_1.htm) may be used for monitoring temperature, humidity, and brightness.
The sensor can be attached to a _HUT_ device via an Ethernet cable (max length is 50m).
diff --git a/bundles/org.openhab.binding.anel/src/main/java/org/openhab/binding/anel/internal/AnelConfiguration.java b/bundles/org.openhab.binding.anel/src/main/java/org/openhab/binding/anel/internal/AnelConfiguration.java
index 6e1590834d482..a30f77f3dc9b6 100644
--- a/bundles/org.openhab.binding.anel/src/main/java/org/openhab/binding/anel/internal/AnelConfiguration.java
+++ b/bundles/org.openhab.binding.anel/src/main/java/org/openhab/binding/anel/internal/AnelConfiguration.java
@@ -23,6 +23,14 @@
@NonNullByDefault
public class AnelConfiguration {
+ public @Nullable String hostname;
+ public @Nullable String user;
+ public @Nullable String password;
+ /** Port to send data from openhab to device. */
+ public int udpSendPort = IAnelConstants.DEFAULT_SEND_PORT;
+ /** Openhab receives messages via this port from device. */
+ public int udpReceivePort = IAnelConstants.DEFAULT_RECEIVE_PORT;
+
public AnelConfiguration() {
}
@@ -35,17 +43,6 @@ public AnelConfiguration(@Nullable String hostname, @Nullable String user, @Null
this.udpReceivePort = receivePort;
}
- @Nullable
- public String hostname;
- @Nullable
- public String user;
- @Nullable
- public String password;
- /** Port to send data from openhab to device. */
- public int udpSendPort = IAnelConstants.DEFAULT_SEND_PORT;
- /** Openhab receives messages via this port from device. */
- public int udpReceivePort = IAnelConstants.DEFAULT_RECEIVE_PORT;
-
@Override
public String toString() {
final StringBuilder builder = new StringBuilder();
diff --git a/bundles/org.openhab.binding.anel/src/main/java/org/openhab/binding/anel/internal/AnelHandler.java b/bundles/org.openhab.binding.anel/src/main/java/org/openhab/binding/anel/internal/AnelHandler.java
index 61a4bc2f1280b..42a53b52364f2 100644
--- a/bundles/org.openhab.binding.anel/src/main/java/org/openhab/binding/anel/internal/AnelHandler.java
+++ b/bundles/org.openhab.binding.anel/src/main/java/org/openhab/binding/anel/internal/AnelHandler.java
@@ -123,6 +123,11 @@ private void initializeConnection() {
periodicRefreshTask = scheduler.scheduleWithFixedDelay(this::periodicRefresh, //
0, IAnelConstants.REFRESH_INTERVAL_SEC, TimeUnit.SECONDS);
+ } catch (InterruptedException e) {
+
+ // OH shutdown - don't log anything, just clean up
+ dispose();
+
} catch (Exception e) {
logger.debug("Connection to '{}' failed", config, e);
@@ -173,18 +178,17 @@ public void handleCommand(ChannelUID channelUID, Command command) {
if (udpConnector2 == null || !udpConnector2.isConnected() || getThing().getStatus() != ThingStatus.ONLINE) {
// don't log initial refresh commands because they may occur before thing is online
- if (!(command instanceof RefreshType) && getThing().getStatus() != ThingStatus.ONLINE) {
- logger.info("Cannot handle command '{}' for channel '{}' because thing ({}) is not (yet) connected: {}", //
+ if (!(command instanceof RefreshType)) {
+ logger.debug("Cannot handle command '{}' for channel '{}' because thing ({}) is not connected: {}", //
command, channelUID.getId(), getThing().getStatus(), config);
}
return;
}
- @Nullable
String anelCommand = null;
if (command instanceof RefreshType) {
- final @Nullable State update = stateUpdater.getChannelUpdate(channelUID.getId(), state);
+ final State update = stateUpdater.getChannelUpdate(channelUID.getId(), state);
if (update != null) {
updateState(channelUID, update);
@@ -203,7 +207,7 @@ public void handleCommand(ChannelUID channelUID, Command command) {
}
} else if (command instanceof OnOffType) {
- final @Nullable State lockedState;
+ final State lockedState;
synchronized (this) { // lock needed to update the state if needed
lockedState = commandHandler.getLockedState(state, channelUID.getId());
diff --git a/bundles/org.openhab.binding.anel/src/main/java/org/openhab/binding/anel/internal/AnelHandlerFactory.java b/bundles/org.openhab.binding.anel/src/main/java/org/openhab/binding/anel/internal/AnelHandlerFactory.java
index 0c9df4fbf6704..96a5d9e5e979b 100644
--- a/bundles/org.openhab.binding.anel/src/main/java/org/openhab/binding/anel/internal/AnelHandlerFactory.java
+++ b/bundles/org.openhab.binding.anel/src/main/java/org/openhab/binding/anel/internal/AnelHandlerFactory.java
@@ -22,8 +22,6 @@
import org.openhab.core.thing.binding.ThingHandler;
import org.openhab.core.thing.binding.ThingHandlerFactory;
import org.osgi.service.component.annotations.Component;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
/**
* The {@link AnelHandlerFactory} is responsible for creating things and thing
@@ -35,11 +33,8 @@
@Component(configurationPid = "binding.anel", service = ThingHandlerFactory.class)
public class AnelHandlerFactory extends BaseThingHandlerFactory {
- private final Logger logger = LoggerFactory.getLogger(AnelHandlerFactory.class);
-
@Override
public boolean supportsThingType(ThingTypeUID thingTypeUID) {
- logger.debug("asking to support '{}': {}", thingTypeUID, SUPPORTED_THING_TYPES_UIDS.contains(thingTypeUID));
return SUPPORTED_THING_TYPES_UIDS.contains(thingTypeUID);
}
diff --git a/bundles/org.openhab.binding.anel/src/main/java/org/openhab/binding/anel/internal/AnelUdpConnector.java b/bundles/org.openhab.binding.anel/src/main/java/org/openhab/binding/anel/internal/AnelUdpConnector.java
index 9990ed885b29c..e3cb01c3a0ca8 100644
--- a/bundles/org.openhab.binding.anel/src/main/java/org/openhab/binding/anel/internal/AnelUdpConnector.java
+++ b/bundles/org.openhab.binding.anel/src/main/java/org/openhab/binding/anel/internal/AnelUdpConnector.java
@@ -23,6 +23,7 @@
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
+import org.openhab.core.common.NamedThreadFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -51,16 +52,16 @@ public class AnelUdpConnector {
/** Service to spawn new threads for handling status updates. */
private final ExecutorService executorService;
+ /** Thread factory for UDP listening thread. */
+ private final NamedThreadFactory listeningThreadFactory = new NamedThreadFactory(IAnelConstants.BINDING_ID, true);
+
/** Socket for receiving UDP packages. */
- @Nullable
- private DatagramSocket receivingSocket = null;
+ private @Nullable DatagramSocket receivingSocket = null;
/** Socket for sending UDP packages. */
- @Nullable
- private DatagramSocket sendingSocket = null;
+ private @Nullable DatagramSocket sendingSocket = null;
/** The listener that gets notified upon newly received messages. */
- @Nullable
- private Consumer listener;
+ private @Nullable Consumer listener;
private int receiveFailures = 0;
private boolean listenerActive = false;
@@ -95,9 +96,11 @@ public AnelUdpConnector(String host, int udpReceivePort, int udpSendPort, Execut
/**
* Initialize socket connection to the UDP receive port for the given listener.
*
- * @throws SocketException
+ * @throws SocketException Is only thrown if logNotTHrowException = false
.
+ * @throws InterruptedException Typically happens during shutdown.
*/
- public void connect(Consumer listener, boolean logNotThrowExcpetion) throws SocketException {
+ public void connect(Consumer listener, boolean logNotThrowExcpetion)
+ throws SocketException, InterruptedException {
if (receivingSocket == null) {
try {
receivingSocket = new DatagramSocket(receivePort);
@@ -106,19 +109,16 @@ public void connect(Consumer listener, boolean logNotThrowExcpetion) thr
/*-
* Due to the issue with 4 concurrently listening threads [1], we should follow Kais suggestion [2]
- * to create our own listening thread.
+ * to create our own listening daemonized thread.
*
* [1] https://community.openhab.org/t/anel-net-pwrctrl-binding-for-oh3/123378
* [2] https://www.eclipse.org/forums/index.php/m/1775932/?#msg_1775429
*/
- new Thread(this::listen).start();
+ listeningThreadFactory.newThread(this::listen).start();
// wait for the listening thread to be active
- try {
- for (int i = 0; i < 20 && !listenerActive; i++) {
- Thread.sleep(100); // wait at most 20 * 100ms = 2sec for the listener to be active
- }
- } catch (InterruptedException e) {
+ for (int i = 0; i < 20 && !listenerActive; i++) {
+ Thread.sleep(100); // wait at most 20 * 100ms = 2sec for the listener to be active
}
if (!listenerActive) {
logger.warn(
@@ -144,6 +144,14 @@ public void connect(Consumer listener, boolean logNotThrowExcpetion) thr
}
private void listen() {
+ try {
+ listenUnhandledInterruption();
+ } catch (InterruptedException e) {
+ // OH shutdown - don't log anything, just quit
+ }
+ }
+
+ private void listenUnhandledInterruption() throws InterruptedException {
logger.info("Anel NET-PwrCtrl listener started for: '{}:{}'", host, receivePort);
final Consumer listener2 = listener;
@@ -194,12 +202,8 @@ private void listen() {
logger.debug(
"Unexpected error while listening on port {}; waiting 10sec before the next attempt to listen on that port.",
receivePort, e);
- try {
- for (int i = 0; i < 50 && receivingSocket != null; i++) {
- Thread.sleep(200); // 50 * 200ms = 10sec
- }
- } catch (InterruptedException ie) {
- // abort waiting on interrupted exception
+ for (int i = 0; i < 50 && receivingSocket != null; i++) {
+ Thread.sleep(200); // 50 * 200ms = 10sec
}
} else {
@@ -212,7 +216,7 @@ private void listen() {
/** Close the socket connection. */
public void disconnect() {
- logger.info("Anel NET-PwrCtrl listener stopped for: '{}:{}'", host, receivePort);
+ logger.debug("Anel NET-PwrCtrl listener stopped for: '{}:{}'", host, receivePort);
listener = null;
final DatagramSocket receivingSocket2 = receivingSocket;
if (receivingSocket2 != null) {
diff --git a/bundles/org.openhab.binding.anel/src/main/java/org/openhab/binding/anel/internal/IAnelConstants.java b/bundles/org.openhab.binding.anel/src/main/java/org/openhab/binding/anel/internal/IAnelConstants.java
index 5cb98a156fc48..c8aacb6d0a420 100644
--- a/bundles/org.openhab.binding.anel/src/main/java/org/openhab/binding/anel/internal/IAnelConstants.java
+++ b/bundles/org.openhab.binding.anel/src/main/java/org/openhab/binding/anel/internal/IAnelConstants.java
@@ -15,8 +15,6 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.thing.ThingTypeUID;
@@ -84,37 +82,29 @@ public interface IAnelConstants {
String CHANNEL_NAME = "prop#name";
String CHANNEL_TEMPERATURE = "prop#temperature";
- @SuppressWarnings("null")
- List CHANNEL_RELAY_NAME = Stream
- .of("r1#name", "r2#name", "r3#name", "r4#name", "r5#name", "r6#name", "r7#name", "r8#name")
- .collect(Collectors.toUnmodifiableList());
-
- @SuppressWarnings("null")
- List CHANNEL_RELAY_STATE = Stream
- // second character must be the index b/c it is parsed in AnelCommandHandler!
- .of("r1#state", "r2#state", "r3#state", "r4#state", "r5#state", "r6#state", "r7#state", "r8#state")
- .collect(Collectors.toUnmodifiableList());
-
- @SuppressWarnings("null")
- List CHANNEL_RELAY_LOCKED = Stream
- .of("r1#locked", "r2#locked", "r3#locked", "r4#locked", "r5#locked", "r6#locked", "r7#locked", "r8#locked")
- .collect(Collectors.toUnmodifiableList());
-
- @SuppressWarnings("null")
- List CHANNEL_IO_NAME = Stream
- .of("io1#name", "io2#name", "io3#name", "io4#name", "io5#name", "io6#name", "io7#name", "io8#name")
- .collect(Collectors.toUnmodifiableList());
-
- @SuppressWarnings("null")
- List CHANNEL_IO_MODE = Stream
- .of("io1#mode", "io2#mode", "io3#mode", "io4#mode", "io5#mode", "io6#mode", "io7#mode", "io8#mode")
- .collect(Collectors.toUnmodifiableList());
-
- @SuppressWarnings("null")
- List CHANNEL_IO_STATE = Stream
- // third character must be the index b/c it is parsed in AnelCommandHandler!
- .of("io1#state", "io2#state", "io3#state", "io4#state", "io5#state", "io6#state", "io7#state", "io8#state")
- .collect(Collectors.toUnmodifiableList());
+ List CHANNEL_RELAY_NAME = List.of("r1#name", "r2#name", "r3#name", "r4#name", "r5#name", "r6#name",
+ "r7#name", "r8#name");
+
+ // second character must be the index b/c it is parsed in AnelCommandHandler!
+ List CHANNEL_RELAY_STATE = List.of("r1#state", "r2#state", "r3#state", "r4#state", "r5#state", "r6#state",
+ "r7#state", "r8#state");
+
+ List CHANNEL_RELAY_LOCKED = List.of("r1#locked", "r2#locked", "r3#locked", "r4#locked", "r5#locked",
+ "r6#locked", "r7#locked", "r8#locked");
+
+ List CHANNEL_IO_NAME = List.of("io1#name", "io2#name", "io3#name", "io4#name", "io5#name", "io6#name",
+ "io7#name", "io8#name");
+
+ List CHANNEL_IO_MODE = List.of("io1#mode", "io2#mode", "io3#mode", "io4#mode", "io5#mode", "io6#mode",
+ "io7#mode", "io8#mode");
+
+ // third character must be the index b/c it is parsed in AnelCommandHandler!
+ List CHANNEL_IO_STATE = List.of("io1#state", "io2#state", "io3#state", "io4#state", "io5#state",
+ "io6#state", "io7#state", "io8#state");
+
+ String CHANNEL_SENSOR_TEMPERATURE = "sensor#temperature";
+ String CHANNEL_SENSOR_HUMIDITY = "sensor#humidity";
+ String CHANNEL_SENSOR_BRIGHTNESS = "sensor#brightness";
/**
* @param channelId A channel ID.
@@ -130,16 +120,4 @@ static int getIndexFromChannel(String channelId) {
}
return -1; // not a relay or io channel
}
-
- String CHANNEL_SENSOR_TEMPERATURE = "sensor#temperature";
- String CHANNEL_SENSOR_HUMIDITY = "sensor#humidity";
- String CHANNEL_SENSOR_BRIGHTNESS = "sensor#brightness";
-
- String CHANNEL_POWER_VOLTAGE_RMS = "power#voltageRMS";
- String CHANNEL_POWER_CURRENT_RMS = "power#currentRMS";
- String CHANNEL_POWER_LINE_FREQUENCY = "power#lineFrequency";
- String CHANNEL_POWER_ACTIVE_POWER = "power#activePower";
- String CHANNEL_POWER_APPARENT_POWER = "power#apparentPower";
- String CHANNEL_POWER_REACTIVE_POWER = "power#reactivePower";
- String CHANNEL_POWER_POWER_FACTOR = "power#powerFactor";
}
diff --git a/bundles/org.openhab.binding.anel/src/main/java/org/openhab/binding/anel/internal/auth/AnelAuthentication.java b/bundles/org.openhab.binding.anel/src/main/java/org/openhab/binding/anel/internal/auth/AnelAuthentication.java
index c6db711417d19..ea897e50c88ac 100644
--- a/bundles/org.openhab.binding.anel/src/main/java/org/openhab/binding/anel/internal/auth/AnelAuthentication.java
+++ b/bundles/org.openhab.binding.anel/src/main/java/org/openhab/binding/anel/internal/auth/AnelAuthentication.java
@@ -28,9 +28,9 @@
public class AnelAuthentication {
public enum AuthMethod {
- plain,
- base64,
- xorBase64;
+ PLAIN,
+ BASE64,
+ XORBASE64;
private static final Pattern NAME_AND_FIRMWARE_PATTERN = Pattern.compile(":NET-PWRCTRL_0?(\\d+\\.\\d)");
private static final Pattern LAST_SEGMENT_FIRMWARE_PATTERN = Pattern.compile(":(\\d+\\.\\d)$");
@@ -40,22 +40,22 @@ public enum AuthMethod {
public static AuthMethod of(String status) {
if (status.isEmpty()) {
- return plain; // fallback
+ return PLAIN; // fallback
}
if (status.trim().endsWith(":xor") || status.contains(":xor:")) {
- return xorBase64;
+ return XORBASE64;
}
final String firmwareVersion = getFirmwareVersion(status);
if (firmwareVersion == null) {
- return plain;
+ return PLAIN;
}
if (firmwareVersion.compareTo(MIN_FIRMWARE_XOR_BASE64) >= 0) {
- return xorBase64; // >= 6.1
+ return XORBASE64; // >= 6.1
}
if (firmwareVersion.compareTo(MIN_FIRMWARE_BASE64) >= 0) {
- return base64; // exactly 6.0
+ return BASE64; // exactly 6.0
}
- return plain; // fallback
+ return PLAIN; // fallback
}
private static @Nullable String getFirmwareVersion(String fullStatusStringOrFirmwareVersion) {
@@ -74,15 +74,15 @@ public static AuthMethod of(String status) {
public static String getUserPasswordString(@Nullable String user, @Nullable String password,
@Nullable AuthMethod authMethod) {
final String userPassword = (user == null ? "" : user) + (password == null ? "" : password);
- if (authMethod == null || authMethod == AuthMethod.plain) {
+ if (authMethod == null || authMethod == AuthMethod.PLAIN) {
return userPassword;
}
- if (authMethod == AuthMethod.base64 || password == null || password.isEmpty()) {
+ if (authMethod == AuthMethod.BASE64 || password == null || password.isEmpty()) {
return Base64.getEncoder().encodeToString(userPassword.getBytes());
}
- if (authMethod == AuthMethod.xorBase64) {
+ if (authMethod == AuthMethod.XORBASE64) {
final StringBuilder result = new StringBuilder();
// XOR
diff --git a/bundles/org.openhab.binding.anel/src/main/java/org/openhab/binding/anel/internal/discovery/AnelDiscoveryService.java b/bundles/org.openhab.binding.anel/src/main/java/org/openhab/binding/anel/internal/discovery/AnelDiscoveryService.java
index 78acce6d1c2ad..1c7c3d11e72b9 100644
--- a/bundles/org.openhab.binding.anel/src/main/java/org/openhab/binding/anel/internal/discovery/AnelDiscoveryService.java
+++ b/bundles/org.openhab.binding.anel/src/main/java/org/openhab/binding/anel/internal/discovery/AnelDiscoveryService.java
@@ -14,6 +14,7 @@
import java.io.IOException;
import java.net.BindException;
+import java.nio.channels.ClosedByInterruptException;
import java.util.Set;
import java.util.TreeSet;
@@ -22,6 +23,7 @@
import org.openhab.binding.anel.internal.AnelUdpConnector;
import org.openhab.binding.anel.internal.IAnelConstants;
import org.openhab.core.common.AbstractUID;
+import org.openhab.core.common.NamedThreadFactory;
import org.openhab.core.config.discovery.AbstractDiscoveryService;
import org.openhab.core.config.discovery.DiscoveryResult;
import org.openhab.core.config.discovery.DiscoveryResultBuilder;
@@ -55,7 +57,7 @@ public class AnelDiscoveryService extends AbstractDiscoveryService {
private final Logger logger = LoggerFactory.getLogger(AnelDiscoveryService.class);
- private boolean scanRunning = false;
+ private @Nullable Thread scanningThread = null;
public AnelDiscoveryService() throws IllegalArgumentException {
super(IAnelConstants.SUPPORTED_THING_TYPES_UIDS, DISCOVER_TIMEOUT_SECONDS);
@@ -71,109 +73,106 @@ protected void startScan() {
* Do not use the scheduler, otherwise further threads (for handling discovered things) are not started
* immediately but only after the scan is complete.
*/
- new Thread(this::doScan).start();
+ final Thread thread = new NamedThreadFactory(IAnelConstants.BINDING_ID, true).newThread(this::doScan);
+ thread.start();
+ scanningThread = thread;
}
private void doScan() {
logger.debug("Starting scan of Anel devices via UDP broadcast messages...");
- if (!scanRunning) {
- scanRunning = true;
+ try {
+ for (final String broadcastAddress : BROADCAST_ADDRESSES) {
- try {
- for (final String broadcastAddress : BROADCAST_ADDRESSES) {
+ // for each available broadcast network address try factory default ports first
+ scan(broadcastAddress, IAnelConstants.DEFAULT_SEND_PORT, IAnelConstants.DEFAULT_RECEIVE_PORT);
- // for each available broadcast network address try factory default ports first
- scan(broadcastAddress, IAnelConstants.DEFAULT_SEND_PORT, IAnelConstants.DEFAULT_RECEIVE_PORT);
+ // try reasonable ports...
+ for (int[] ports : DISCOVERY_PORTS) {
+ int sendPort = ports[0];
+ int receivePort = ports[1];
- // try reasonable ports...
- for (int[] ports : DISCOVERY_PORTS) {
- int sendPort = ports[0];
- int receivePort = ports[1];
-
- // ...and continue if a device was found, maybe there is yet another device on the next port
- while (scan(broadcastAddress, sendPort, receivePort) || sendPort == ports[0]) {
- sendPort++;
- receivePort++;
- }
+ // ...and continue if a device was found, maybe there is yet another device on the next port
+ while (scan(broadcastAddress, sendPort, receivePort) || sendPort == ports[0]) {
+ sendPort++;
+ receivePort++;
}
}
- } catch (Exception e) {
+ }
+ } catch (InterruptedException | ClosedByInterruptException e) {
- logger.warn("Unexpected exception during anel device scan", e);
+ return; // OH shutdown or scan was aborted
- } finally {
+ } catch (Exception e) {
- scanRunning = false;
- }
+ logger.warn("Unexpected exception during anel device scan", e);
+
+ } finally {
+
+ scanningThread = null;
}
logger.debug("Scan finished.");
}
/* @return Whether or not a device was found for the given broadcast address and port. */
- private boolean scan(String broadcastAddress, int sendPort, int receivePort) throws IOException {
- if (scanRunning) {
- logger.debug("Scanning {}:{}...", broadcastAddress, sendPort);
- final AnelUdpConnector udpConnector = new AnelUdpConnector(broadcastAddress, receivePort, sendPort,
- scheduler);
-
- try {
- final boolean[] deviceDiscovered = new boolean[] { false };
- udpConnector.connect(status -> {
- // avoid the same device to be discovered multiple times for multiple responses
- if (!deviceDiscovered[0]) {
- boolean discoverDevice = true;
- synchronized (this) {
- if (deviceDiscovered[0]) {
- discoverDevice = false; // already discovered by another thread
- } else {
- deviceDiscovered[0] = true; // we discover the device!
- }
- }
- if (discoverDevice) {
- // discover device outside synchronized-block
- deviceDiscovered(status, sendPort, receivePort);
+ private boolean scan(String broadcastAddress, int sendPort, int receivePort)
+ throws IOException, InterruptedException {
+ logger.debug("Scanning {}:{}...", broadcastAddress, sendPort);
+ final AnelUdpConnector udpConnector = new AnelUdpConnector(broadcastAddress, receivePort, sendPort, scheduler);
+
+ try {
+ final boolean[] deviceDiscovered = new boolean[] { false };
+ udpConnector.connect(status -> {
+ // avoid the same device to be discovered multiple times for multiple responses
+ if (!deviceDiscovered[0]) {
+ boolean discoverDevice = true;
+ synchronized (this) {
+ if (deviceDiscovered[0]) {
+ discoverDevice = false; // already discovered by another thread
+ } else {
+ deviceDiscovered[0] = true; // we discover the device!
}
}
- }, false);
-
- udpConnector.send(IAnelConstants.BROADCAST_DISCOVERY_MSG);
-
- // answer expected within 50-600ms on a regular network; wait up to 2sec just to make sure
- for (int delay = 0; delay < 10 && !deviceDiscovered[0]; delay++) {
- Thread.sleep(100 * DISCOVER_DEVICE_TIMEOUT_SECONDS); // wait 10 x 200ms = 2sec
+ if (discoverDevice) {
+ // discover device outside synchronized-block
+ deviceDiscovered(status, sendPort, receivePort);
+ }
}
+ }, false);
- return deviceDiscovered[0];
+ udpConnector.send(IAnelConstants.BROADCAST_DISCOVERY_MSG);
- } catch (BindException e) {
+ // answer expected within 50-600ms on a regular network; wait up to 2sec just to make sure
+ for (int delay = 0; delay < 10 && !deviceDiscovered[0]; delay++) {
+ Thread.sleep(100 * DISCOVER_DEVICE_TIMEOUT_SECONDS); // wait 10 x 200ms = 2sec
+ }
- // most likely socket is already in use, ignore this exception.
- logger.debug(
- "Invalid address {} or one of the ports {} or {} is already in use. Skipping scan of these ports.",
- broadcastAddress, sendPort, receivePort);
+ return deviceDiscovered[0];
- } catch (InterruptedException e) {
+ } catch (BindException e) {
- // interrupted...
+ // most likely socket is already in use, ignore this exception.
+ logger.debug(
+ "Invalid address {} or one of the ports {} or {} is already in use. Skipping scan of these ports.",
+ broadcastAddress, sendPort, receivePort);
- } finally {
+ } finally {
- udpConnector.disconnect();
- }
+ udpConnector.disconnect();
}
return false;
}
@Override
protected synchronized void stopScan() {
- scanRunning = false;
+ final Thread thread = scanningThread;
+ if (thread != null) {
+ thread.interrupt();
+ }
super.stopScan();
}
private void deviceDiscovered(String status, int sendPort, int receivePort) {
- logger.debug("Discovery result: {}", status);
-
final String[] segments = status.split(":");
if (segments.length >= 16) {
diff --git a/bundles/org.openhab.binding.anel/src/main/java/org/openhab/binding/anel/internal/state/AnelState.java b/bundles/org.openhab.binding.anel/src/main/java/org/openhab/binding/anel/internal/state/AnelState.java
index 861e56a85b87c..041a96e4fd9db 100644
--- a/bundles/org.openhab.binding.anel/src/main/java/org/openhab/binding/anel/internal/state/AnelState.java
+++ b/bundles/org.openhab.binding.anel/src/main/java/org/openhab/binding/anel/internal/state/AnelState.java
@@ -45,14 +45,11 @@ public class AnelState {
public final String status;
/** Device IP address; read-only. */
- @Nullable
- public final String ip;
+ public final @Nullable String ip;
/** Device name; read-only. */
- @Nullable
- public final String name;
+ public final @Nullable String name;
/** Device mac address; read-only. */
- @Nullable
- public final String mac;
+ public final @Nullable String mac;
/** Device relay names; read-only. */
public final String[] relayName = new String[8];
@@ -69,40 +66,14 @@ public class AnelState {
public final Boolean[] ioIsInput = new Boolean[8];
/** Device temperature (optional); read-only. */
- @Nullable
- public final String temperature;
-
- /** Power voltage, e.g. "226.2" (optional); read-only. */
- @Nullable
- public final String powerVoltageRMS;
- /** Power current, e.g. "0.0004" (optional); read-only. */
- @Nullable
- public final String powerCurrentRMS;
- /** Power line frequency, e.g. "50.044" (optional); read-only. */
- @Nullable
- public final String powerLineFrequency;
- /** Active power, e.g. "0.03" (optional); read-only. */
- @Nullable
- public final String powerActivePower;
- /** Apparent power, e.g. "0.00" (optional); read-only. */
- @Nullable
- public final String powerApparentPower;
- /** Reactive power, e.g. "0.05" (optional); read-only. */
- @Nullable
- public final String powerReactivePower;
- /** Power factor, e.g. "1.0000" (optional); read-only. */
- @Nullable
- public final String powerPowerFactor;
+ public final @Nullable String temperature;
/** Sensor temperature, e.g. "20.61" (optional); read-only. */
- @Nullable
- public final String sensorTemperature;
+ public final @Nullable String sensorTemperature;
/** Sensor Humidity, e.g. "40.7" (optional); read-only. */
- @Nullable
- public final String sensorHumidity;
+ public final @Nullable String sensorHumidity;
/** Sensor Brightness, e.g. "7.0" (optional); read-only. */
- @Nullable
- public final String sensorBrightness;
+ public final @Nullable String sensorBrightness;
private static final AnelState INVALID_STATE = new AnelState();
@@ -119,13 +90,6 @@ private AnelState() {
name = null;
mac = null;
temperature = null;
- powerVoltageRMS = null;
- powerCurrentRMS = null;
- powerLineFrequency = null;
- powerActivePower = null;
- powerApparentPower = null;
- powerReactivePower = null;
- powerPowerFactor = null;
sensorTemperature = null;
sensorHumidity = null;
sensorBrightness = null;
@@ -192,15 +156,6 @@ private AnelState(@Nullable String status) throws IllegalFormatException {
if (segments.length > 34 && "p".equals(segments[27])) {
- // optional power measurement (if device supports it and firmware >= 6.0)
- powerVoltageRMS = segments[28];
- powerCurrentRMS = segments[29];
- powerLineFrequency = segments[30];
- powerActivePower = segments[31];
- powerApparentPower = segments[32];
- powerReactivePower = segments[33];
- powerPowerFactor = segments[34];
-
// optional sensor (if device supports it and firmware >= 6.1) after power management
if (segments.length > 38 && "s".equals(segments[35])) {
sensorTemperature = segments[36];
@@ -214,15 +169,6 @@ private AnelState(@Nullable String status) throws IllegalFormatException {
} else if (segments.length > 31 && "n".equals(segments[27]) && "s".equals(segments[28])) {
- // no power measurement
- powerVoltageRMS = null;
- powerCurrentRMS = null;
- powerLineFrequency = null;
- powerActivePower = null;
- powerApparentPower = null;
- powerReactivePower = null;
- powerPowerFactor = null;
-
// but sensor! (if device supports it and firmware >= 6.1)
sensorTemperature = segments[29];
sensorHumidity = segments[30];
@@ -230,13 +176,6 @@ private AnelState(@Nullable String status) throws IllegalFormatException {
} else {
// firmware <= 6.0 or unknown format; skip rest
- powerVoltageRMS = null;
- powerCurrentRMS = null;
- powerLineFrequency = null;
- powerActivePower = null;
- powerApparentPower = null;
- powerReactivePower = null;
- powerPowerFactor = null;
sensorTemperature = null;
sensorBrightness = null;
sensorHumidity = null;
@@ -281,13 +220,6 @@ public int hashCode() {
result = prime * result + Arrays.hashCode(relayName);
result = prime * result + Arrays.hashCode(relayState);
result = prime * result + ((temperature == null) ? 0 : temperature.hashCode());
- result = prime * result + ((powerActivePower == null) ? 0 : powerActivePower.hashCode());
- result = prime * result + ((powerApparentPower == null) ? 0 : powerApparentPower.hashCode());
- result = prime * result + ((powerCurrentRMS == null) ? 0 : powerCurrentRMS.hashCode());
- result = prime * result + ((powerLineFrequency == null) ? 0 : powerLineFrequency.hashCode());
- result = prime * result + ((powerPowerFactor == null) ? 0 : powerPowerFactor.hashCode());
- result = prime * result + ((powerReactivePower == null) ? 0 : powerReactivePower.hashCode());
- result = prime * result + ((powerVoltageRMS == null) ? 0 : powerVoltageRMS.hashCode());
result = prime * result + ((sensorBrightness == null) ? 0 : sensorBrightness.hashCode());
result = prime * result + ((sensorHumidity == null) ? 0 : sensorHumidity.hashCode());
result = prime * result + ((sensorTemperature == null) ? 0 : sensorTemperature.hashCode());
@@ -338,55 +270,6 @@ public boolean equals(@Nullable Object obj) {
} else if (!name.equals(other.name)) {
return false;
}
- if (powerActivePower == null) {
- if (other.powerActivePower != null) {
- return false;
- }
- } else if (!powerActivePower.equals(other.powerActivePower)) {
- return false;
- }
- if (powerApparentPower == null) {
- if (other.powerApparentPower != null) {
- return false;
- }
- } else if (!powerApparentPower.equals(other.powerApparentPower)) {
- return false;
- }
- if (powerCurrentRMS == null) {
- if (other.powerCurrentRMS != null) {
- return false;
- }
- } else if (!powerCurrentRMS.equals(other.powerCurrentRMS)) {
- return false;
- }
- if (powerLineFrequency == null) {
- if (other.powerLineFrequency != null) {
- return false;
- }
- } else if (!powerLineFrequency.equals(other.powerLineFrequency)) {
- return false;
- }
- if (powerPowerFactor == null) {
- if (other.powerPowerFactor != null) {
- return false;
- }
- } else if (!powerPowerFactor.equals(other.powerPowerFactor)) {
- return false;
- }
- if (powerReactivePower == null) {
- if (other.powerReactivePower != null) {
- return false;
- }
- } else if (!powerReactivePower.equals(other.powerReactivePower)) {
- return false;
- }
- if (powerVoltageRMS == null) {
- if (other.powerVoltageRMS != null) {
- return false;
- }
- } else if (!powerVoltageRMS.equals(other.powerVoltageRMS)) {
- return false;
- }
if (sensorBrightness == null) {
if (other.sensorBrightness != null) {
return false;
diff --git a/bundles/org.openhab.binding.anel/src/main/java/org/openhab/binding/anel/internal/state/AnelStateUpdater.java b/bundles/org.openhab.binding.anel/src/main/java/org/openhab/binding/anel/internal/state/AnelStateUpdater.java
index 3a31108035dc1..fccf190a22ef2 100644
--- a/bundles/org.openhab.binding.anel/src/main/java/org/openhab/binding/anel/internal/state/AnelStateUpdater.java
+++ b/bundles/org.openhab.binding.anel/src/main/java/org/openhab/binding/anel/internal/state/AnelStateUpdater.java
@@ -22,17 +22,20 @@
import org.openhab.binding.anel.internal.IAnelConstants;
import org.openhab.core.library.types.DecimalType;
import org.openhab.core.library.types.OnOffType;
+import org.openhab.core.library.types.QuantityType;
import org.openhab.core.library.types.StringType;
import org.openhab.core.types.State;
import org.openhab.core.types.UnDefType;
+import tech.units.indriya.unit.Units;
+
/**
* Get updates for {@link AnelState}s.
*
* @author Patrick Koenemann - Initial contribution
*/
@NonNullByDefault
-public class AnelStateUpdater implements IAnelConstants {
+public class AnelStateUpdater {
public @Nullable State getChannelUpdate(String channelId, @Nullable AnelState state) {
if (state == null) {
@@ -66,11 +69,11 @@ public class AnelStateUpdater implements IAnelConstants {
return getStringState(state.name);
}
if (IAnelConstants.CHANNEL_TEMPERATURE.equals(channelId)) {
- return getDecimalState(state.temperature);
+ return getTemperatureState(state.temperature);
}
if (IAnelConstants.CHANNEL_SENSOR_TEMPERATURE.equals(channelId)) {
- return getDecimalState(state.sensorTemperature);
+ return getTemperatureState(state.sensorTemperature);
}
if (IAnelConstants.CHANNEL_SENSOR_HUMIDITY.equals(channelId)) {
return getDecimalState(state.sensorHumidity);
@@ -78,28 +81,6 @@ public class AnelStateUpdater implements IAnelConstants {
if (IAnelConstants.CHANNEL_SENSOR_BRIGHTNESS.equals(channelId)) {
return getDecimalState(state.sensorBrightness);
}
-
- if (IAnelConstants.CHANNEL_POWER_VOLTAGE_RMS.equals(channelId)) {
- return getDecimalState(state.powerVoltageRMS);
- }
- if (IAnelConstants.CHANNEL_POWER_CURRENT_RMS.equals(channelId)) {
- return getDecimalState(state.powerCurrentRMS);
- }
- if (IAnelConstants.CHANNEL_POWER_LINE_FREQUENCY.equals(channelId)) {
- return getDecimalState(state.powerLineFrequency);
- }
- if (IAnelConstants.CHANNEL_POWER_ACTIVE_POWER.equals(channelId)) {
- return getDecimalState(state.powerActivePower);
- }
- if (IAnelConstants.CHANNEL_POWER_APPARENT_POWER.equals(channelId)) {
- return getDecimalState(state.powerApparentPower);
- }
- if (IAnelConstants.CHANNEL_POWER_REACTIVE_POWER.equals(channelId)) {
- return getDecimalState(state.powerReactivePower);
- }
- if (IAnelConstants.CHANNEL_POWER_POWER_FACTOR.equals(channelId)) {
- return getDecimalState(state.powerPowerFactor);
- }
}
return null;
}
@@ -114,12 +95,12 @@ public Map getChannelUpdates(@Nullable AnelState oldState, AnelSt
// name and device temperature
final State newName = getNewStringState(oldState == null ? null : oldState.name, newState.name);
if (newName != null) {
- updates.put(CHANNEL_NAME, newName);
+ updates.put(IAnelConstants.CHANNEL_NAME, newName);
}
- final State newTemperature = getNewDecimalState(oldState == null ? null : oldState.temperature,
+ final State newTemperature = getNewTemperatureState(oldState == null ? null : oldState.temperature,
newState.temperature);
if (newTemperature != null) {
- updates.put(CHANNEL_TEMPERATURE, newTemperature);
+ updates.put(IAnelConstants.CHANNEL_TEMPERATURE, newTemperature);
}
// relay properties
@@ -127,19 +108,19 @@ public Map getChannelUpdates(@Nullable AnelState oldState, AnelSt
final State newRelayName = getNewStringState(oldState == null ? null : oldState.relayName[i],
newState.relayName[i]);
if (newRelayName != null) {
- updates.put(CHANNEL_RELAY_NAME.get(i), newRelayName);
+ updates.put(IAnelConstants.CHANNEL_RELAY_NAME.get(i), newRelayName);
}
final State newRelayState = getNewSwitchState(oldState == null ? null : oldState.relayState[i],
newState.relayState[i]);
if (newRelayState != null) {
- updates.put(CHANNEL_RELAY_STATE.get(i), newRelayState);
+ updates.put(IAnelConstants.CHANNEL_RELAY_STATE.get(i), newRelayState);
}
final State newRelayLocked = getNewSwitchState(oldState == null ? null : oldState.relayLocked[i],
newState.relayLocked[i]);
if (newRelayLocked != null) {
- updates.put(CHANNEL_RELAY_LOCKED.get(i), newRelayLocked);
+ updates.put(IAnelConstants.CHANNEL_RELAY_LOCKED.get(i), newRelayLocked);
}
}
@@ -147,74 +128,37 @@ public Map getChannelUpdates(@Nullable AnelState oldState, AnelSt
for (int i = 0; i < 8; i++) {
final State newIOName = getNewStringState(oldState == null ? null : oldState.ioName[i], newState.ioName[i]);
if (newIOName != null) {
- updates.put(CHANNEL_IO_NAME.get(i), newIOName);
+ updates.put(IAnelConstants.CHANNEL_IO_NAME.get(i), newIOName);
}
final State newIOIsInput = getNewSwitchState(oldState == null ? null : oldState.ioIsInput[i],
newState.ioIsInput[i]);
if (newIOIsInput != null) {
- updates.put(CHANNEL_IO_MODE.get(i), newIOIsInput);
+ updates.put(IAnelConstants.CHANNEL_IO_MODE.get(i), newIOIsInput);
}
final State newIOState = getNewSwitchState(oldState == null ? null : oldState.ioState[i],
newState.ioState[i]);
if (newIOState != null) {
- updates.put(CHANNEL_IO_STATE.get(i), newIOState);
+ updates.put(IAnelConstants.CHANNEL_IO_STATE.get(i), newIOState);
}
}
// sensor values
- final State newSensorTemperature = getNewDecimalState(oldState == null ? null : oldState.sensorTemperature,
+ final State newSensorTemperature = getNewTemperatureState(oldState == null ? null : oldState.sensorTemperature,
newState.sensorTemperature);
if (newSensorTemperature != null) {
- updates.put(CHANNEL_SENSOR_TEMPERATURE, newSensorTemperature);
+ updates.put(IAnelConstants.CHANNEL_SENSOR_TEMPERATURE, newSensorTemperature);
}
final State newSensorHumidity = getNewDecimalState(oldState == null ? null : oldState.sensorHumidity,
newState.sensorHumidity);
if (newSensorHumidity != null) {
- updates.put(CHANNEL_SENSOR_HUMIDITY, newSensorHumidity);
+ updates.put(IAnelConstants.CHANNEL_SENSOR_HUMIDITY, newSensorHumidity);
}
final State newSensorBrightness = getNewDecimalState(oldState == null ? null : oldState.sensorBrightness,
newState.sensorBrightness);
if (newSensorBrightness != null) {
- updates.put(CHANNEL_SENSOR_BRIGHTNESS, newSensorBrightness);
- }
-
- // power measurement
- final State newPowerVoltageRMS = getNewDecimalState(oldState == null ? null : oldState.powerVoltageRMS,
- newState.powerVoltageRMS);
- if (newPowerVoltageRMS != null) {
- updates.put(CHANNEL_POWER_VOLTAGE_RMS, newPowerVoltageRMS);
- }
- final State newPowerCurrentRMS = getNewDecimalState(oldState == null ? null : oldState.powerCurrentRMS,
- newState.powerCurrentRMS);
- if (newPowerCurrentRMS != null) {
- updates.put(CHANNEL_POWER_CURRENT_RMS, newPowerCurrentRMS);
- }
- final State newPowerLineFrequency = getNewDecimalState(oldState == null ? null : oldState.powerLineFrequency,
- newState.powerLineFrequency);
- if (newPowerLineFrequency != null) {
- updates.put(CHANNEL_POWER_LINE_FREQUENCY, newPowerLineFrequency);
- }
- final State newPowerActivePower = getNewDecimalState(oldState == null ? null : oldState.powerActivePower,
- newState.powerActivePower);
- if (newPowerActivePower != null) {
- updates.put(CHANNEL_POWER_ACTIVE_POWER, newPowerActivePower);
- }
- final State newPowerApparentPower = getNewDecimalState(oldState == null ? null : oldState.powerApparentPower,
- newState.powerApparentPower);
- if (newPowerApparentPower != null) {
- updates.put(CHANNEL_POWER_APPARENT_POWER, newPowerApparentPower);
- }
- final State newPowerReactivePower = getNewDecimalState(oldState == null ? null : oldState.powerReactivePower,
- newState.powerReactivePower);
- if (newPowerReactivePower != null) {
- updates.put(CHANNEL_POWER_REACTIVE_POWER, newPowerReactivePower);
- }
- final State newPowerPowerFactor = getNewDecimalState(oldState == null ? null : oldState.powerPowerFactor,
- newState.powerPowerFactor);
- if (newPowerPowerFactor != null) {
- updates.put(CHANNEL_POWER_POWER_FACTOR, newPowerPowerFactor);
+ updates.put(IAnelConstants.CHANNEL_SENSOR_BRIGHTNESS, newSensorBrightness);
}
return updates;
@@ -228,16 +172,28 @@ public Map getChannelUpdates(@Nullable AnelState oldState, AnelSt
return value == null ? null : new DecimalType(value);
}
+ private @Nullable State getTemperatureState(@Nullable String value) {
+ if (value == null || value.trim().isEmpty()) {
+ return null;
+ }
+ final float floatValue = Float.parseFloat(value);
+ return QuantityType.valueOf(floatValue, Units.CELSIUS);
+ }
+
private @Nullable State getSwitchState(@Nullable Boolean value) {
return value == null ? null : OnOffType.from(value.booleanValue());
}
private @Nullable State getNewStringState(@Nullable String oldValue, @Nullable String newValue) {
- return getNewState(oldValue, newValue, value -> new StringType(value));
+ return getNewState(oldValue, newValue, StringType::new);
}
private @Nullable State getNewDecimalState(@Nullable String oldValue, @Nullable String newValue) {
- return getNewState(oldValue, newValue, value -> new DecimalType(value));
+ return getNewState(oldValue, newValue, DecimalType::new);
+ }
+
+ private @Nullable State getNewTemperatureState(@Nullable String oldValue, @Nullable String newValue) {
+ return getNewState(oldValue, newValue, value -> QuantityType.valueOf(Float.parseFloat(value), Units.CELSIUS));
}
private @Nullable State getNewSwitchState(@Nullable Boolean oldValue, @Nullable Boolean newValue) {
diff --git a/bundles/org.openhab.binding.anel/src/main/resources/OH-INF/binding/binding.xml b/bundles/org.openhab.binding.anel/src/main/resources/OH-INF/binding/binding.xml
index a1a832e0c180d..1635ce3daf4df 100644
--- a/bundles/org.openhab.binding.anel/src/main/resources/OH-INF/binding/binding.xml
+++ b/bundles/org.openhab.binding.anel/src/main/resources/OH-INF/binding/binding.xml
@@ -5,6 +5,5 @@
Anel NET-PwrCtrl Binding
This is the binding for Anel NET-PwrCtrl devices.
- Patrick Koenemann
diff --git a/bundles/org.openhab.binding.anel/src/main/resources/OH-INF/thing/thing-types.xml b/bundles/org.openhab.binding.anel/src/main/resources/OH-INF/thing/thing-types.xml
index 47dbd98944ecb..d9e45864579bb 100644
--- a/bundles/org.openhab.binding.anel/src/main/resources/OH-INF/thing/thing-types.xml
+++ b/bundles/org.openhab.binding.anel/src/main/resources/OH-INF/thing/thing-types.xml
@@ -5,7 +5,7 @@
xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
-
+
Anel device with 3 controllable outlets without IO ports.
@@ -17,19 +17,17 @@
-
+
macAddress
-
+
Anel device with 8 controllable outlets without IO ports.
@@ -46,19 +44,17 @@
-
+
macAddress
-
+
Anel device with 8 controllable outlets / relays and possibly 8 IO ports.
@@ -84,27 +80,20 @@
-
-
-
-
+
macAddress
-
- Anel device properties
+
+ Device properties
@@ -138,23 +127,10 @@
-
-
- Optional power measurement values
-
-
-
-
-
-
-
-
-
-
String
-
+
The name of the Anel device
@@ -222,47 +198,4 @@
-
- Number
-
- Voltage RMS value of the optional power measurement
-
-
-
- Number
-
- Current RMS value of the optional power measurement
-
-
-
- Number
-
- Line frequency of the optional power measurement
-
-
-
- Number
-
- Active power of the optional power measurement
-
-
-
- Number
-
- Apparent power of the optional power measurement
-
-
-
- Number
-
- Reactive Power of the optional power measurement
-
-
-
- String
-
- Power factor of the optional power measurement
-
-
-
diff --git a/bundles/org.openhab.binding.anel/src/test/java/org/openhab/binding/anel/internal/AnelAuthenticationTest.java b/bundles/org.openhab.binding.anel/src/test/java/org/openhab/binding/anel/internal/AnelAuthenticationTest.java
index ca947f07ccd96..ca81fed646ffe 100644
--- a/bundles/org.openhab.binding.anel/src/test/java/org/openhab/binding/anel/internal/AnelAuthenticationTest.java
+++ b/bundles/org.openhab.binding.anel/src/test/java/org/openhab/binding/anel/internal/AnelAuthenticationTest.java
@@ -41,30 +41,30 @@ public class AnelAuthenticationTest {
@Test
public void authenticationMethod() {
- assertThat(AuthMethod.of(""), is(AuthMethod.plain));
- assertThat(AuthMethod.of(" \n"), is(AuthMethod.plain));
- assertThat(AuthMethod.of(STATUS_HUT_V4), is(AuthMethod.plain));
- assertThat(AuthMethod.of(STATUS_HUT_V5), is(AuthMethod.plain));
- assertThat(AuthMethod.of(STATUS_HOME_V4_6), is(AuthMethod.xorBase64));
- assertThat(AuthMethod.of(STATUS_UDP_SPEC_EXAMPLE_V7), is(AuthMethod.xorBase64));
- assertThat(AuthMethod.of(STATUS_PRO_EXAMPLE_V4_5), is(AuthMethod.xorBase64));
- assertThat(AuthMethod.of(STATUS_IO_EXAMPLE_V6_5), is(AuthMethod.xorBase64));
- assertThat(AuthMethod.of(STATUS_EXAMPLE_V6_0), is(AuthMethod.base64));
+ assertThat(AuthMethod.of(""), is(AuthMethod.PLAIN));
+ assertThat(AuthMethod.of(" \n"), is(AuthMethod.PLAIN));
+ assertThat(AuthMethod.of(STATUS_HUT_V4), is(AuthMethod.PLAIN));
+ assertThat(AuthMethod.of(STATUS_HUT_V5), is(AuthMethod.PLAIN));
+ assertThat(AuthMethod.of(STATUS_HOME_V4_6), is(AuthMethod.XORBASE64));
+ assertThat(AuthMethod.of(STATUS_UDP_SPEC_EXAMPLE_V7), is(AuthMethod.XORBASE64));
+ assertThat(AuthMethod.of(STATUS_PRO_EXAMPLE_V4_5), is(AuthMethod.XORBASE64));
+ assertThat(AuthMethod.of(STATUS_IO_EXAMPLE_V6_5), is(AuthMethod.XORBASE64));
+ assertThat(AuthMethod.of(STATUS_EXAMPLE_V6_0), is(AuthMethod.BASE64));
}
@Test
public void encodeUserPasswordPlain() {
- encodeUserPassword(AuthMethod.plain, (u, p) -> u + p);
+ encodeUserPassword(AuthMethod.PLAIN, (u, p) -> u + p);
}
@Test
public void encodeUserPasswordBase64() {
- encodeUserPassword(AuthMethod.base64, (u, p) -> base64(u + p));
+ encodeUserPassword(AuthMethod.BASE64, (u, p) -> base64(u + p));
}
@Test
public void encodeUserPasswordXorBase64() {
- encodeUserPassword(AuthMethod.xorBase64, (u, p) -> base64(xor(u + p, p)));
+ encodeUserPassword(AuthMethod.XORBASE64, (u, p) -> base64(xor(u + p, p)));
}
private void encodeUserPassword(AuthMethod authMethod, BiFunction expectedEncoding) {
diff --git a/bundles/org.openhab.binding.anel/src/test/java/org/openhab/binding/anel/internal/AnelStateTest.java b/bundles/org.openhab.binding.anel/src/test/java/org/openhab/binding/anel/internal/AnelStateTest.java
index c45e1fd9fedd2..a8a1a3fc97592 100644
--- a/bundles/org.openhab.binding.anel/src/test/java/org/openhab/binding/anel/internal/AnelStateTest.java
+++ b/bundles/org.openhab.binding.anel/src/test/java/org/openhab/binding/anel/internal/AnelStateTest.java
@@ -45,13 +45,6 @@ public void parseHomeV46Status() {
assertNull(state.ioState[i - 1]);
assertNull(state.ioIsInput[i - 1]);
}
- assertNull(state.powerVoltageRMS);
- assertNull(state.powerCurrentRMS);
- assertNull(state.powerLineFrequency);
- assertNull(state.powerActivePower);
- assertNull(state.powerApparentPower);
- assertNull(state.powerReactivePower);
- assertNull(state.powerPowerFactor);
assertNull(state.sensorTemperature);
assertNull(state.sensorBrightness);
assertNull(state.sensorHumidity);
@@ -87,13 +80,6 @@ public void parseHutV65Status() {
assertThat(state.ioState[i - 1], is(false));
assertThat(state.ioIsInput[i - 1], is(i >= 5));
}
- assertNull(state.powerVoltageRMS);
- assertNull(state.powerCurrentRMS);
- assertNull(state.powerLineFrequency);
- assertNull(state.powerActivePower);
- assertNull(state.powerApparentPower);
- assertNull(state.powerReactivePower);
- assertNull(state.powerPowerFactor);
assertNull(state.sensorTemperature);
assertNull(state.sensorBrightness);
assertNull(state.sensorHumidity);
@@ -116,20 +102,13 @@ public void parseHutV5Status() {
assertThat(state.ioState[i - 1], is(true));
assertThat(state.ioIsInput[i - 1], is(true));
}
- assertNull(state.powerVoltageRMS);
- assertNull(state.powerCurrentRMS);
- assertNull(state.powerLineFrequency);
- assertNull(state.powerActivePower);
- assertNull(state.powerApparentPower);
- assertNull(state.powerReactivePower);
- assertNull(state.powerPowerFactor);
assertNull(state.sensorTemperature);
assertNull(state.sensorBrightness);
assertNull(state.sensorHumidity);
}
@Test
- public void parseHutV61StatusWithPowerAndSensor() {
+ public void parseHutV61StatusAndSensor() {
final AnelState state = AnelState.of(STATUS_HUT_V61_POW_SENSOR);
assertThat(state.name, equalTo("NET-CONTROL"));
assertThat(state.ip, equalTo("192.168.178.148"));
@@ -145,20 +124,13 @@ public void parseHutV61StatusWithPowerAndSensor() {
assertThat(state.ioState[i - 1], is(false));
assertThat(state.ioIsInput[i - 1], is(false));
}
- assertThat(state.powerVoltageRMS, equalTo("225.9"));
- assertThat(state.powerCurrentRMS, equalTo("0.0004"));
- assertThat(state.powerLineFrequency, equalTo("50.056"));
- assertThat(state.powerActivePower, equalTo("0.04"));
- assertThat(state.powerApparentPower, equalTo("0.00"));
- assertThat(state.powerReactivePower, equalTo("0.0"));
- assertThat(state.powerPowerFactor, equalTo("1.0000"));
assertThat(state.sensorTemperature, equalTo("20.61"));
assertThat(state.sensorHumidity, equalTo("40.7"));
assertThat(state.sensorBrightness, equalTo("7.0"));
}
@Test
- public void parseHutV61StatusWithoutPowerWithSensor() {
+ public void parseHutV61StatusWithSensor() {
final AnelState state = AnelState.of(STATUS_HUT_V61_SENSOR);
assertThat(state.name, equalTo("NET-CONTROL"));
assertThat(state.ip, equalTo("192.168.178.148"));
@@ -174,20 +146,13 @@ public void parseHutV61StatusWithoutPowerWithSensor() {
assertThat(state.ioState[i - 1], is(false));
assertThat(state.ioIsInput[i - 1], is(false));
}
- assertNull(state.powerVoltageRMS);
- assertNull(state.powerCurrentRMS);
- assertNull(state.powerLineFrequency);
- assertNull(state.powerActivePower);
- assertNull(state.powerApparentPower);
- assertNull(state.powerReactivePower);
- assertNull(state.powerPowerFactor);
assertThat(state.sensorTemperature, equalTo("20.61"));
assertThat(state.sensorHumidity, equalTo("40.7"));
assertThat(state.sensorBrightness, equalTo("7.0"));
}
@Test
- public void parseHutV61StatusWithPowerWithoutSensor() {
+ public void parseHutV61StatusWithoutSensor() {
final AnelState state = AnelState.of(STATUS_HUT_V61_POW);
assertThat(state.name, equalTo("NET-CONTROL"));
assertThat(state.ip, equalTo("192.168.178.148"));
@@ -203,13 +168,6 @@ public void parseHutV61StatusWithPowerWithoutSensor() {
assertThat(state.ioState[i - 1], is(false));
assertThat(state.ioIsInput[i - 1], is(false));
}
- assertThat(state.powerVoltageRMS, equalTo("225.9"));
- assertThat(state.powerCurrentRMS, equalTo("0.0004"));
- assertThat(state.powerLineFrequency, equalTo("50.056"));
- assertThat(state.powerActivePower, equalTo("0.04"));
- assertThat(state.powerApparentPower, equalTo("0.00"));
- assertThat(state.powerReactivePower, equalTo("0.0"));
- assertThat(state.powerPowerFactor, equalTo("1.0000"));
assertNull(state.sensorTemperature);
assertNull(state.sensorBrightness);
assertNull(state.sensorHumidity);
diff --git a/bundles/org.openhab.binding.anel/src/test/java/org/openhab/binding/anel/internal/AnelStateUpdaterTest.java b/bundles/org.openhab.binding.anel/src/test/java/org/openhab/binding/anel/internal/AnelStateUpdaterTest.java
index 93a63f41674c0..3703b4c33d434 100644
--- a/bundles/org.openhab.binding.anel/src/test/java/org/openhab/binding/anel/internal/AnelStateUpdaterTest.java
+++ b/bundles/org.openhab.binding.anel/src/test/java/org/openhab/binding/anel/internal/AnelStateUpdaterTest.java
@@ -19,11 +19,13 @@
import java.util.Map;
import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
import org.junit.jupiter.api.Test;
import org.openhab.binding.anel.internal.state.AnelState;
import org.openhab.binding.anel.internal.state.AnelStateUpdater;
import org.openhab.core.library.types.DecimalType;
import org.openhab.core.library.types.OnOffType;
+import org.openhab.core.library.types.QuantityType;
import org.openhab.core.library.types.StringType;
import org.openhab.core.types.State;
@@ -33,7 +35,7 @@
* @author Patrick Koenemann - Initial contribution
*/
@NonNullByDefault
-public class AnelStateUpdaterTest implements IAnelTestStatus {
+public class AnelStateUpdaterTest implements IAnelTestStatus, IAnelConstants {
private final AnelStateUpdater stateUpdater = new AnelStateUpdater();
@@ -56,11 +58,11 @@ public void fromNullStateUpdatesHome() {
Map updates = stateUpdater.getChannelUpdates(null, newState);
// then
final Map expected = new HashMap<>();
- expected.put(IAnelConstants.CHANNEL_NAME, new StringType("NET-CONTROL"));
+ expected.put(CHANNEL_NAME, new StringType("NET-CONTROL"));
for (int i = 1; i <= 8; i++) {
- expected.put(IAnelConstants.CHANNEL_RELAY_NAME.get(i - 1), new StringType("Nr. " + i));
- expected.put(IAnelConstants.CHANNEL_RELAY_STATE.get(i - 1), OnOffType.from(i % 2 == 1));
- expected.put(IAnelConstants.CHANNEL_RELAY_LOCKED.get(i - 1), OnOffType.from(i > 3));
+ expected.put(CHANNEL_RELAY_NAME.get(i - 1), new StringType("Nr. " + i));
+ expected.put(CHANNEL_RELAY_STATE.get(i - 1), OnOffType.from(i % 2 == 1));
+ expected.put(CHANNEL_RELAY_LOCKED.get(i - 1), OnOffType.from(i > 3));
}
assertThat(updates, equalTo(expected));
}
@@ -72,30 +74,24 @@ public void fromNullStateUpdatesHutPowerSensor() {
// when
Map updates = stateUpdater.getChannelUpdates(null, newState);
// then
- final Map expected = new HashMap<>();
- expected.put(IAnelConstants.CHANNEL_NAME, new StringType("NET-CONTROL"));
- expected.put(IAnelConstants.CHANNEL_TEMPERATURE, new DecimalType("27.7"));
+ assertThat(updates.size(), is(5 + 8 * 6));
+ assertThat(updates.get(CHANNEL_NAME), equalTo(new StringType("NET-CONTROL")));
+ assertTemperature(updates.get(CHANNEL_TEMPERATURE), 27.7);
+
+ assertThat(updates.get(CHANNEL_SENSOR_BRIGHTNESS), equalTo(new DecimalType("7")));
+ assertThat(updates.get(CHANNEL_SENSOR_HUMIDITY), equalTo(new DecimalType("40.7")));
+ assertTemperature(updates.get(CHANNEL_SENSOR_TEMPERATURE), 20.61);
+
for (int i = 1; i <= 8; i++) {
- expected.put(IAnelConstants.CHANNEL_RELAY_NAME.get(i - 1), new StringType("Nr. " + i));
- expected.put(IAnelConstants.CHANNEL_RELAY_STATE.get(i - 1), OnOffType.from(i <= 3 || i >= 7));
- expected.put(IAnelConstants.CHANNEL_RELAY_LOCKED.get(i - 1), OnOffType.OFF);
+ assertThat(updates.get(CHANNEL_RELAY_NAME.get(i - 1)), equalTo(new StringType("Nr. " + i)));
+ assertThat(updates.get(CHANNEL_RELAY_STATE.get(i - 1)), equalTo(OnOffType.from(i <= 3 || i >= 7)));
+ assertThat(updates.get(CHANNEL_RELAY_LOCKED.get(i - 1)), equalTo(OnOffType.OFF));
}
for (int i = 1; i <= 8; i++) {
- expected.put(IAnelConstants.CHANNEL_IO_NAME.get(i - 1), new StringType("IO-" + i));
- expected.put(IAnelConstants.CHANNEL_IO_STATE.get(i - 1), OnOffType.OFF);
- expected.put(IAnelConstants.CHANNEL_IO_MODE.get(i - 1), OnOffType.OFF);
+ assertThat(updates.get(CHANNEL_IO_NAME.get(i - 1)), equalTo(new StringType("IO-" + i)));
+ assertThat(updates.get(CHANNEL_IO_STATE.get(i - 1)), equalTo(OnOffType.OFF));
+ assertThat(updates.get(CHANNEL_IO_MODE.get(i - 1)), equalTo(OnOffType.OFF));
}
- expected.put(IAnelConstants.CHANNEL_POWER_VOLTAGE_RMS, new DecimalType("225.9"));
- expected.put(IAnelConstants.CHANNEL_POWER_CURRENT_RMS, new DecimalType("0.0004"));
- expected.put(IAnelConstants.CHANNEL_POWER_LINE_FREQUENCY, new DecimalType("50.056"));
- expected.put(IAnelConstants.CHANNEL_POWER_ACTIVE_POWER, new DecimalType("0.04"));
- expected.put(IAnelConstants.CHANNEL_POWER_APPARENT_POWER, new DecimalType("0"));
- expected.put(IAnelConstants.CHANNEL_POWER_REACTIVE_POWER, new DecimalType("0"));
- expected.put(IAnelConstants.CHANNEL_POWER_POWER_FACTOR, new DecimalType("1"));
- expected.put(IAnelConstants.CHANNEL_SENSOR_TEMPERATURE, new DecimalType("20.61"));
- expected.put(IAnelConstants.CHANNEL_SENSOR_HUMIDITY, new DecimalType("40.7"));
- expected.put(IAnelConstants.CHANNEL_SENSOR_BRIGHTNESS, new DecimalType("7"));
- assertThat(updates, equalTo(expected));
}
@Test
@@ -107,7 +103,7 @@ public void singleRelayStateChange() {
Map updates = stateUpdater.getChannelUpdates(oldState, newState);
// then
final Map expected = new HashMap<>();
- expected.put(IAnelConstants.CHANNEL_RELAY_STATE.get(3), OnOffType.ON);
+ expected.put(CHANNEL_RELAY_STATE.get(3), OnOffType.ON);
assertThat(updates, equalTo(expected));
}
@@ -119,9 +115,8 @@ public void temperatureChange() {
// when
Map updates = stateUpdater.getChannelUpdates(oldState, newState);
// then
- final Map expected = new HashMap<>();
- expected.put(IAnelConstants.CHANNEL_TEMPERATURE, new DecimalType("27.1"));
- assertThat(updates, equalTo(expected));
+ assertThat(updates.size(), is(1));
+ assertTemperature(updates.get(CHANNEL_TEMPERATURE), 27.1);
}
@Test
@@ -132,10 +127,16 @@ public void singleSensorStatesChange() {
// when
Map updates = stateUpdater.getChannelUpdates(oldState, newState);
// then
- final Map expected = new HashMap<>();
- expected.put(IAnelConstants.CHANNEL_SENSOR_TEMPERATURE, new DecimalType("20.6"));
- expected.put(IAnelConstants.CHANNEL_SENSOR_HUMIDITY, new DecimalType("40"));
- expected.put(IAnelConstants.CHANNEL_SENSOR_BRIGHTNESS, new DecimalType("7.1"));
- assertThat(updates, equalTo(expected));
+ assertThat(updates.size(), is(3));
+ assertThat(updates.get(CHANNEL_SENSOR_BRIGHTNESS), equalTo(new DecimalType("7.1")));
+ assertThat(updates.get(CHANNEL_SENSOR_HUMIDITY), equalTo(new DecimalType("40")));
+ assertTemperature(updates.get(CHANNEL_SENSOR_TEMPERATURE), 20.6);
+ }
+
+ private void assertTemperature(@Nullable State state, double value) {
+ assertThat(state, isA(QuantityType.class));
+ if (state instanceof QuantityType>) {
+ assertThat(((QuantityType>) state).doubleValue(), closeTo(value, 0.0001d));
+ }
}
}