diff --git a/bundles/org.openhab.binding.lcn/README.md b/bundles/org.openhab.binding.lcn/README.md
index 15afd6d6b..35fa8c774 100644
--- a/bundles/org.openhab.binding.lcn/README.md
+++ b/bundles/org.openhab.binding.lcn/README.md
@@ -1,19 +1,21 @@
# LCN Binding
-[Local Control Network (LCN)](https://www.lcn.eu) is a building automation system for small and very large installations.
+[Local Control Network (LCN)](https://www.lcn.eu) is a building automation system.
It is capable of controlling lights, shutters, access control etc. and can process data from several sensor types.
-It has been introduced in 1992.
+It was introduced in 1992.
A broad range of glass key panels, displays, remote controls, sensors and in- and outputs exist.
The system can handle up to 30,000 bus members, called modules.
-LCN modules are available for DIN rail and in-wall mounting and feature versatile interfaces. The bus modules and most of the accessories are developed, manufactured and assembled in Germany.
+LCN modules are available for DIN rail and in-wall mounting and feature versatile interfaces.
+The bus modules and most of the accessories are developed, manufactured and assembled in Germany.
-Bus members are inter-connected via a free wire in the standard NYM cable. Wireless components are available, though.
+Bus members are inter-connected via a free wire in the standard NYM cable.
+Wireless components are available, though.

-This binding uses TCP/IP to access the LCN bus via the software LCN-PCHK (Windows/Linux) or the DIN rail device LCN-PKE.
-**This means 1 unused LCN-PCHK license or a LCN-PKE is required**
+This binding uses TCP/IP to access the LCN bus via the software LCN-PCHK (Windows/Linux) or the DIN rail device LCN-VISU.
+**This means 1 unused LCN-PCHK license or a LCN-VISU is required**
## Supported Things
@@ -21,8 +23,7 @@ This binding uses TCP/IP to access the LCN bus via the software LCN-PCHK (Window
Any LCN module that should be controlled or visualized, need to be added to openHAB as a *Thing*.
-LCN modules with firmware versions 120612 (2008) and 170602 (2013) were tested with this binding.
-No known features/changes that need special handling were added until now (2020).
+LCN modules with firmware versions 120612 (2008), 170602 (2013) and 1F080A (2021) were tested with this binding.
Modules with older and newer firmware should work, too.
The module hardware types (e.g. LCN-SH, LCN-HU, LCN-UPP, ...) are compatible to each other and can therefore be handled all in the same way.
@@ -39,13 +40,13 @@ See [Discover LCN Modules](#discover-lcn-modules).
### Bridge: LCN PCK Gateway
PCK is the protocol spoken over TCP/IP with a PCK gateway to communicate with the LCN bus.
-Examples for PCK gateways are the *LCN-PCHK* software running on Windows or Linux and the DIN rail mounting device *LCN-PKE*.
+Examples for PCK gateways are the *LCN-PCHK* software running on Windows or Linux and the DIN rail mounting device *LCN-VISU*.
For each LCN bus, interfaced to openHAB, a PCK gateway needs to be added to openHAB as a *Thing*.
Several PCK gateways can be added to openHAB to control multiple LCN busses in distinct locations.
-The minimum recommended version is LCN-PCHK 2.8 (older versions will also work, but lack some functionality).
+The minimum recommended version is LCN-PCHK 3.3 (older versions will also work, but lack some functionality).
Visit [https://www.lcn.eu](https://www.lcn.eu) for updates.
Thing Type ID: `pckGateway`
@@ -130,14 +131,18 @@ If a special command is needed, the [Hit Key](#hit-key) action (German: "Sende T
| LCN Feature (English) | LCN Feature (German) | Channel | IDs | Type | Description |
|---------------------------------|----------------------------------|------------------------|------|--------------------------------|-------------------------------------------------------------------------------------------------------------------------------|
| Dimmer Output Control Single | Ausgang | output | 1-4 | Dimmer, Switch | Sets the dimming value of an output with a given ramp. |
+| Dimmer Output Control Color | Ausgang Farbe | output | color | Color, Switch | Sets the outputs 1-4 to control an RGBW lamp. |
+| Tunable White Mode | Tunable White Modus | output | tunablewhite | String | Sets the module's tunable white mode: `DISABLE`: Tunable white disabled. `OUTPUT1`: Output 1 is used for controlling. Output 2 is adjusted automatically. `BOTH`: Output 1 is used to control the brightness. Output 2 controls the temperature. |
| Relay | Relais | relay | 1-8 | Switch | Controls a relay and visualizes its state. |
-| Visualize Binary Sensor | Binärsensor anzeigen | binarysensor | 1-8 | Contact | Visualizes the state of a binary sensor (special channel mapping for some devices). |
-| LED Control | LED-Steuerung | led | 1-12 | Text (ON, OFF, BLINK, FLICKER) | Controls an LED and visualizes its current state. |
-| Visualize Logic Operations | Logik Funktion anzeigen | logic | 1-4 | Text (NOT, OR, AND) | Visualizes the result of the logic operation. |
+| Visualize Binary Sensor | Binärsensor anzeigen | binarysensor | 1-8 | Contact | Visualizes the state of a binary sensor (special channel mapping for some devices). |
+| LED Control | LED-Steuerung | led | 1-12 | String | Controls an LED and visualizes its current state: `ON`, `OFF`, `BLINK`, `FLICKER` |
+| Visualize Logic Operations | Logik Funktion anzeigen | logic | 1-4 | String | Visualizes the result of the logic operation: `NOT`, `OR`, `AND` |
| Motor/Shutter on Dimmer Outputs | Motor/Rollladen an Ausgängen | rollershutteroutput | 1-4 | Rollershutter | Control roller shutters on dimmer outputs |
-| Motor/Shutter on Relays | Motor/Rollladen an Relais | rollershutterrelay | 1-4 | Rollershutter | Control roller shutters on relays |
+| Motor/Shutter on Relays | Motor/Rollladen an Relais | rollershutterrelay | 1-4 | Rollershutter, Dimmer | Control position of roller shutters on relays (Supports UpDown, StopMove, Percent) |
+| Shutter Slat Angle on Relays | Rollladenlamellen an Relais | rollershutterrelayslat | 1-4 | Rollershutter, Dimmer | Control slat angle of roller shutters on relays (Supports UpDown, StopMove, Percent) |
| Variables | Variable anzeigen | variable | 1-12 | Number | Sets and visualizes the value of a variable. |
| Regulator Set Setpoint | Regler Sollwert ändern | rvarsetpoint | 1-2 | Number | Sets and visualizes the setpoint of a regulator. |
+| Regulator Set Mode | Reglerverhalten ändern | rvarmode | 1-2 | String | Sets the mode of the regulator: `HEATING` or `COOLING` |
| Regulator Lock | Regler sperren | rvarlock | 1-2 | Switch | Locks a regulator and visualizes its locking state. |
| Set Thresholds in Register 1 | Schwellwert in Register 1 ändern | thresholdregister1 | 1-4 | Number | Sets and visualizes a threshold in the given threshold register. |
| Set Thresholds in Register 2 | Schwellwert in Register 2 ändern | thresholdregister2 | 1-4 | Number | Sets and visualizes a threshold in the given threshold register. |
@@ -158,8 +163,12 @@ If a special command is needed, the [Hit Key](#hit-key) action (German: "Sende T
| Access Control | Zutrittskontrolle | code#remotecontrolcode | | Trigger | Receive serial numbers from remote control |
| Remote Control Battery Low | Fernbedienung Batterie schwach | code#remotecontrolbatterylow | | Trigger | Triggered when the sending remote control has a low battery |
| Host Command (Send Keys) | Kommando an Host (Sende Tasten) | hostcommand#sendKeys | - | Trigger | Receive *send keys* command from LCN module |
+| Operating Hours Counter Outputs | Betriebsstundenzähler Ausgänge | operatinghourscounter | output[1-4] | Number:Time | Visualize Operating Hours Counter for outputs |
+| Operating Hours Counter Outputs (rel. Work) | Betriebsstundenzähler Ausgänge (rel. Arbeit) | operatinghourscounter | outputrelativework[1-4] | Number:Time | Visualize Operating Hours Counter for outputs (relative work) |
+| Operating Hours Counter Relays | Betriebsstundenzähler Relais | operatinghourscounter | relay[1-8] | Number:Time | Visualize Operating Hours Counter for relays |
+| Operating Hours Counter Binary Sensor | Betriebsstundenzähler Binärsensoren | operatinghourscounter | binarysensor[1-8] | Number:Time | Visualize Operating Hours Counter for binary sensors |
| Status Message | Statusmeldungen | - | - | - | Automatically done by openHAB Binding |
-| Audio Beep | Audio Piepen | - | - | - | Not implemented |
+| Audio Beep | Audio Piepen | N/A | N/A | N/A | Action: "beep" (see below) |
| Audio LCN-MRS | Audio LCN-MRS | - | - | - | Not implemented |
| Count/Compute | Zählen/Rechnen | - | - | - | Not implemented |
| DALI | DALI | - | - | - | Not implemented |
@@ -180,7 +189,7 @@ If a special command is needed, the [Hit Key](#hit-key) action (German: "Sende T
| Lock Relays | Sperre Relais | - | - | - | Not implemented |
| Lock Thresholds | Sperre Schwellwerte | - | - | - | Not implemented |
| Motor Position | Motor Position | - | - | - | Not implemented |
-| Relay Timer | Relais-Timer | N/A | N/A | N/A | Action: "startRelayTimer": Starts a relay timer for the given relay number with the given duration in milliseconds. |
+| Relay Timer | Relais-Timer | N/A | N/A | N/A | Action: "startRelayTimer" (see below) |
| Send Keys Delayed | Sende Tasten verzögert | - | - | - | Not implemented |
| Set S0 Counters | S0-Zähler setzen | - | - | - | Not implemented |
| Status Command | Statuskommandos | - | - | - | Not implemented |
@@ -415,10 +424,43 @@ when
then
val actions = getActions("lcn","lcn:module:b827ebfea4bb:17B4196847")
// relayNumber=3, duration=90
- actions.startRelayTimer(3,90)
+ actions.startRelayTimer(3, 90)
end
```
+### Beep
+
+This *Action* realizes the LCN commmand "audio" (German: "Piepen").
+It lets the beeper connected to the LCN module beep.
+
+When programming an "audio" *Action*, the following parameters can be set:
+
+*volume* - Sound volume in percent (if null, the previous volume will be used)
+*tonality* - The tonality as a String. You need to use quotes. See below.
+*count* - Number of beeps (max. 50)
+
+Tonalities:
+
+- "N"=push button hit (normal)
+- "S"=special
+- "1"=push button make
+- "2"=push button break
+- "3"=standard
+- "4"=special
+- "5"=special short
+- "6"=error
+- "7"=long
+
+```
+rule "Beep when dummy switch changed"
+when
+ Item Dummy_Switch changed
+then
+ val actions = getActions("lcn","lcn:module:b827ebfea4bb:b0b029b920")
+ // volume=100, tonality="6", count=2
+ actions.beep(100, "6", 2)
+end
+```
## Caveat and Limitations
@@ -469,6 +511,7 @@ Switch M10_Relay1 {channel="lcn:module:b827ebfea4bb:S000M010:relay#1"}
// Roller Shutter on Relays 1+2
Rollershutter M10_RollershutterRelay1 {channel="lcn:module:b827ebfea4bb:S000M010:rollershutterrelay#1"}
+Dimmer M10_RollershutterRelay1Slats {channel="lcn:module:68b8462b:S000M012:rollershutterrelayslat#1"}
// LEDs
String M10_LED1 {channel="lcn:module:b827ebfea4bb:S000M010:led#1"}
@@ -545,6 +588,8 @@ sitemap lcn label="My home automation" {
// Roller Shutter on Relays
Default item=M10_RollershutterRelay1 label="Roller Shutter on Relay 1-2"
+ Dimmer item=M10_RollershutterRelay1 label="Roller Shutter Position on Relay 1-2"
+ Default item=M10_RollershutterRelay1Slats label="Roller Shutter Slat Angle on Relay 1-2"
// LEDs
Switch item=M10_LED1 label="LED 1" mappings=[ON=ON, OFF=OFF] // Don't display "Blink" or "Flicker"
diff --git a/bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/LcnBindingConstants.java b/bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/LcnBindingConstants.java
index 6576cb8be..2879316f7 100644
--- a/bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/LcnBindingConstants.java
+++ b/bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/LcnBindingConstants.java
@@ -12,6 +12,8 @@
*/
package org.openhab.binding.lcn.internal;
+import java.util.Collection;
+import java.util.Set;
import java.util.regex.Pattern;
import org.eclipse.jdt.annotation.NonNullByDefault;
@@ -39,9 +41,12 @@ public class LcnBindingConstants {
public static final ThingTypeUID THING_TYPE_MODULE = new ThingTypeUID(BINDING_ID, "module");
public static final ThingTypeUID THING_TYPE_GROUP = new ThingTypeUID(BINDING_ID, "group");
/** Regex for address in PCK protocol */
- public static final String ADDRESS_REGEX = "[:=%]M(?\\d{3})(?\\d{3})";
+ public static final String ADDRESS_WITHOUT_PREFIX = "M(?\\d{3})(?\\d{3})";
+ public static final String ADDRESS_REGEX = "[:=%]" + ADDRESS_WITHOUT_PREFIX;
public static final Pattern MEASUREMENT_PATTERN_BEFORE_2013 = Pattern
.compile(LcnBindingConstants.ADDRESS_REGEX + "\\.(?\\d{5})");
/** LCN coding for ACK */
public static final int CODE_ACK = -1;
+ public static final Collection ALLOWED_BEEP_TONALITIES = Set.of("N", "S", "1", "2", "3", "4", "5", "6",
+ "7");
}
diff --git a/bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/LcnModuleActions.java b/bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/LcnModuleActions.java
index 1cfa8bf9f..60299dcc0 100644
--- a/bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/LcnModuleActions.java
+++ b/bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/LcnModuleActions.java
@@ -40,6 +40,8 @@ import org.slf4j.LoggerFactory;
@NonNullByDefault
public class LcnModuleActions implements ThingActions {
private final Logger logger = LoggerFactory.getLogger(LcnModuleActions.class);
+ private static final int MAX_BEEP_VOLUME = 100;
+ private static final int MAX_BEEP_COUNT = 50;
private static final int DYN_TEXT_CHUNK_COUNT = 5;
private static final int DYN_TEXT_HEADER_LENGTH = 6;
private static final int DYN_TEXT_CHUNK_LENGTH = 12;
@@ -173,6 +175,42 @@ public class LcnModuleActions implements ThingActions {
}
}
+ /**
+ * Let the beeper connected to the LCN module beep.
+ *
+ * @param volume sound volume in percent. Can be null. Then, the last volume is used.
+ * @param tonality N=normal, S=special, 1-7 tonalities 1-7. Can be null. Then, normal tonality is used.
+ * @param count number of beeps. Can be null. Then, number of beeps is one.
+ */
+ @RuleAction(label = "let the module's beeper beep", description = "Lets the beeper connected to the LCN module beep")
+ public void beep(
+ @ActionInput(name = "volume", required = false, type = "java.lang.Double", label = "Sound Volume", description = "The sound volume in percent.") @Nullable Double soundVolume,
+ @ActionInput(name = "tonality", required = false, type = "java.lang.String", label = "Tonality", description = "Tonality (N, S, 1-7)") @Nullable String tonality,
+ @ActionInput(name = "count", required = false, type = "java.lang.Integer", label = "Count", description = "Number of beeps") @Nullable Integer count) {
+ try {
+ if (soundVolume != null) {
+ if (soundVolume < 0) {
+ throw new LcnException("Volume cannot be negative: " + soundVolume);
+ }
+ getHandler().sendPck(PckGenerator.setBeepVolume(Math.min(soundVolume, MAX_BEEP_VOLUME)));
+ }
+
+ Integer localCount = count;
+ if (localCount == null) {
+ localCount = 1;
+ }
+
+ String filteredTonality = LcnBindingConstants.ALLOWED_BEEP_TONALITIES.stream() //
+ .filter(t -> t.equals(tonality)) //
+ .findAny() //
+ .orElse("N");
+
+ getHandler().sendPck(PckGenerator.beep(filteredTonality, Math.min(localCount, MAX_BEEP_COUNT)));
+ } catch (LcnException e) {
+ logger.warn("Could not send beep command: {}", e.getMessage());
+ }
+ }
+
/** Static alias to support the old DSL rules engine and make the action available there. */
public static void hitKey(ThingActions actions, @Nullable String table, int key, @Nullable String action) {
((LcnModuleActions) actions).hitKey(table, key, action);
@@ -193,6 +231,11 @@ public class LcnModuleActions implements ThingActions {
((LcnModuleActions) actions).startRelayTimer(relaynumber, duration);
}
+ /** Static alias to support the old DSL rules engine and make the action available there. */
+ public static void beep(ThingActions actions, Double soundVolume, String tonality, Integer count) {
+ ((LcnModuleActions) actions).beep(soundVolume, tonality, count);
+ }
+
private LcnModuleHandler getHandler() throws LcnException {
LcnModuleHandler localModuleHandler = moduleHandler;
if (localModuleHandler != null) {
diff --git a/bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/LcnModuleHandler.java b/bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/LcnModuleHandler.java
index 91c0108a3..13633b0c3 100644
--- a/bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/LcnModuleHandler.java
+++ b/bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/LcnModuleHandler.java
@@ -218,7 +218,7 @@ public class LcnModuleHandler extends BaseThingHandler {
} else if (command instanceof PercentType) {
subHandler.handleCommandPercent((PercentType) command, channelGroup, channelUid.getIdWithoutGroup());
} else if (command instanceof StringType) {
- subHandler.handleCommandString((StringType) command, number.get());
+ subHandler.handleCommandString((StringType) command, number.orElse(0));
} else if (command instanceof DecimalType) {
DecimalType decimalType = (DecimalType) command;
DecimalType nativeValue = getConverter(channelUid).onCommandFromItem(decimalType.doubleValue());
diff --git a/bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/PckGatewayHandler.java b/bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/PckGatewayHandler.java
index aa7651546..6dc16f75d 100644
--- a/bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/PckGatewayHandler.java
+++ b/bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/PckGatewayHandler.java
@@ -65,7 +65,7 @@ public class PckGatewayHandler extends BaseBridgeHandler {
public synchronized void initialize() {
PckGatewayConfiguration localConfig = config = getConfigAs(PckGatewayConfiguration.class);
- String errorMessage = "Could not connect to LCN-PCHK/PKE: " + localConfig.getHostname() + ": ";
+ String errorMessage = "Could not connect to LCN-PCHK/VISU: " + localConfig.getHostname() + ": ";
try {
OutputPortDimMode dimMode;
diff --git a/bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/common/LcnChannelGroup.java b/bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/common/LcnChannelGroup.java
index f3b8f2e53..8bc38994b 100644
--- a/bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/common/LcnChannelGroup.java
+++ b/bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/common/LcnChannelGroup.java
@@ -24,11 +24,14 @@ import org.openhab.binding.lcn.internal.subhandler.LcnModuleHostCommandSubHandle
import org.openhab.binding.lcn.internal.subhandler.LcnModuleKeyLockTableSubHandler;
import org.openhab.binding.lcn.internal.subhandler.LcnModuleLedSubHandler;
import org.openhab.binding.lcn.internal.subhandler.LcnModuleLogicSubHandler;
+import org.openhab.binding.lcn.internal.subhandler.LcnModuleOperatingHoursCounterSubHandler;
import org.openhab.binding.lcn.internal.subhandler.LcnModuleOutputSubHandler;
import org.openhab.binding.lcn.internal.subhandler.LcnModuleRelaySubHandler;
import org.openhab.binding.lcn.internal.subhandler.LcnModuleRollershutterOutputSubHandler;
-import org.openhab.binding.lcn.internal.subhandler.LcnModuleRollershutterRelaySubHandler;
+import org.openhab.binding.lcn.internal.subhandler.LcnModuleRollershutterRelayPositionSubHandler;
+import org.openhab.binding.lcn.internal.subhandler.LcnModuleRollershutterRelaySlatAngleSubHandler;
import org.openhab.binding.lcn.internal.subhandler.LcnModuleRvarLockSubHandler;
+import org.openhab.binding.lcn.internal.subhandler.LcnModuleRvarModeSubHandler;
import org.openhab.binding.lcn.internal.subhandler.LcnModuleRvarSetpointSubHandler;
import org.openhab.binding.lcn.internal.subhandler.LcnModuleS0CounterSubHandler;
import org.openhab.binding.lcn.internal.subhandler.LcnModuleThresholdSubHandler;
@@ -44,12 +47,14 @@ public enum LcnChannelGroup {
OUTPUT(4, LcnModuleOutputSubHandler::new),
ROLLERSHUTTEROUTPUT(1, LcnModuleRollershutterOutputSubHandler::new),
RELAY(8, LcnModuleRelaySubHandler::new),
- ROLLERSHUTTERRELAY(4, LcnModuleRollershutterRelaySubHandler::new),
+ ROLLERSHUTTERRELAY(4, LcnModuleRollershutterRelayPositionSubHandler::new),
+ ROLLERSHUTTERRELAYSLAT(4, LcnModuleRollershutterRelaySlatAngleSubHandler::new),
LED(12, LcnModuleLedSubHandler::new),
LOGIC(4, LcnModuleLogicSubHandler::new),
BINARYSENSOR(8, LcnModuleBinarySensorSubHandler::new),
VARIABLE(12, LcnModuleVariableSubHandler::new),
RVARSETPOINT(2, LcnModuleRvarSetpointSubHandler::new),
+ RVARMODE(2, LcnModuleRvarModeSubHandler::new),
RVARLOCK(2, LcnModuleRvarLockSubHandler::new),
THRESHOLDREGISTER1(5, LcnModuleThresholdSubHandler::new),
THRESHOLDREGISTER2(4, LcnModuleThresholdSubHandler::new),
@@ -61,6 +66,7 @@ public enum LcnChannelGroup {
KEYLOCKTABLEC(8, LcnModuleKeyLockTableSubHandler::new),
KEYLOCKTABLED(8, LcnModuleKeyLockTableSubHandler::new),
CODE(0, LcnModuleCodeSubHandler::new),
+ OPERATINGHOURS(0, LcnModuleOperatingHoursCounterSubHandler::new),
HOSTCOMMAND(0, LcnModuleHostCommandSubHandler::new);
private int count;
diff --git a/bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/common/LcnDefs.java b/bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/common/LcnDefs.java
index 993437a6e..da72b52f6 100644
--- a/bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/common/LcnDefs.java
+++ b/bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/common/LcnDefs.java
@@ -56,7 +56,7 @@ public final class LcnDefs {
public static final String LCNCONNSTATE_CONNECTED = "$io:#LCN:connected";
/** LCN-PK/PKU is disconnected. */
public static final String LCNCONNSTATE_DISCONNECTED = "$io:#LCN:disconnected";
- /** LCN-PCHK/PKE has not enough licenses to handle this connection. */
+ /** LCN-PCHK/VISU has not enough licenses to handle this connection. */
public static final String INSUFFICIENT_LICENSES = "$err:(license?)";
/**
diff --git a/bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/common/PckGenerator.java b/bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/common/PckGenerator.java
index a495ee935..62bd7b8f2 100644
--- a/bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/common/PckGenerator.java
+++ b/bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/common/PckGenerator.java
@@ -136,6 +136,21 @@ public final class PckGenerator {
}
}
+ /**
+ * Generates a command for setting the tunable white mode.
+ *
+ * @param mode 0..2
+ * @return the PCK command (without address header) as text
+ * @throws LcnException if out of range
+ */
+ public static String setTunableWhiteMode(int mode) throws LcnException {
+ if (mode < 0 || mode > 2) {
+ throw new LcnException();
+ }
+
+ return String.format("AW%d", mode);
+ }
+
/**
* Generates a dim command for all output-ports.
*
@@ -332,6 +347,42 @@ public final class PckGenerator {
return ret.toString();
}
+ /**
+ * Generates a command to control the position of roller shutters on relays.
+ *
+ * @param motorNumber of the roller shutter (0-based)
+ * @param percent of the entire roller shutter height
+ * @return the PCK command (without address header) as text
+ * @throws LcnException if out of range
+ */
+ public static String controlShutterPosition(int motorNumber, int percent) throws LcnException {
+ return controlShutter(motorNumber, percent, "JH");
+ }
+
+ /**
+ * Generates a command to control the slat angle of roller shutters on relays.
+ *
+ * @param motorNumber of the roller shutter (0-based)
+ * @param percent of the slat angle
+ * @return the PCK command (without address header) as text
+ * @throws LcnException if out of range
+ */
+ public static String controlShutterSlatAngle(int motorNumber, int percent) throws LcnException {
+ return controlShutter(motorNumber, percent, "JW");
+ }
+
+ private static String controlShutter(int motorNumber, int percent, String command) throws LcnException {
+ if (motorNumber < 0 || motorNumber >= 4) {
+ throw new LcnException("Roller shutter (relay) motor number out of range: " + motorNumber);
+ }
+
+ if (percent < 0 || percent > 100) {
+ throw new LcnException("Roller shutter (relay) position/angle out of range (percent): " + percent);
+ }
+
+ return String.format("%s%03d%03d", command, percent, 1 << motorNumber);
+ }
+
/**
* Generates a binary-sensors status request.
*
@@ -365,6 +416,30 @@ public final class PckGenerator {
return String.format("X2%03d%03d%03d", 30, b1, b2);
}
+ /**
+ * Generates a command to change the regulator mode.
+ *
+ * @param number regulator number 0..1
+ * @param cooling true=cooling, false=heating
+ * @return the PCK command (without address header) as text
+ * @throws LcnException
+ */
+ public static String setRVarMode(int number, boolean cooling) throws LcnException {
+ String regulator;
+ switch (number) {
+ case 0:
+ regulator = "A";
+ break;
+ case 1:
+ regulator = "B";
+ break;
+ default:
+ throw new LcnException();
+ }
+
+ return "RE" + regulator + "T" + (cooling ? "C" : "H");
+ }
+
/**
* Generates a command to change the value of a variable.
*
@@ -751,6 +826,41 @@ public final class PckGenerator {
return command.toString();
}
+ /**
+ * Generates a command to set the beeping sound volume.
+ *
+ * @param volume the sound volume
+ * @return the PCK command (without address header) as text
+ * @throws LcnException if out of range
+ */
+ public static String setBeepVolume(double volume) throws LcnException {
+ if (volume < 0 || volume > 100) {
+ throw new LcnException();
+ }
+
+ return String.format("PIV%03d", Math.round(volume));
+ }
+
+ /**
+ * Generates a command to let the beeper connected to the LCN module beep.
+ *
+ * @param volume the sound volume
+ * @return the PCK command (without address header) as text
+ * @throws LcnException if out of range
+ */
+ public static String beep(String tonality, int count) throws LcnException {
+ LcnBindingConstants.ALLOWED_BEEP_TONALITIES.stream() //
+ .filter(t -> t.equals(tonality)) //
+ .findAny() //
+ .orElseThrow(LcnException::new);
+
+ if (count < 0) {
+ throw new LcnException();
+ }
+
+ return String.format("PI%s%d", tonality, Math.min(count, 50));
+ }
+
/**
* Generates a null command, used for broadcast messages.
*
diff --git a/bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/connection/AbstractConnectionState.java b/bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/connection/AbstractConnectionState.java
index bd953e6a6..640f2fa11 100644
--- a/bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/connection/AbstractConnectionState.java
+++ b/bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/connection/AbstractConnectionState.java
@@ -80,7 +80,7 @@ public abstract class AbstractConnectionState extends AbstractState[" + POSITION + "|" + ANGLE + "])(?\\d)(?\\d{3})");
+
+ public AbstractLcnModuleRollershutterRelaySubHandler(LcnModuleHandler handler, ModInfo info) {
super(handler, info);
}
@@ -68,11 +75,21 @@ public class LcnModuleRollershutterRelaySubHandler extends AbstractLcnModuleSubH
@Override
public void handleStatusMessage(Matcher matcher) {
- // status messages of roller shutters on relays are handled in the relay sub handler
+ int shutterNumber = Integer.parseInt(matcher.group("shutterNumber")) - 1;
+ int percent = Integer.parseInt(matcher.group("percent"));
+
+ LcnChannelGroup group;
+ if (POSITION.equals(matcher.group("type"))) {
+ group = LcnChannelGroup.ROLLERSHUTTERRELAY;
+ } else {
+ group = LcnChannelGroup.ROLLERSHUTTERRELAYSLAT;
+ }
+
+ fireUpdate(group, shutterNumber, new PercentType(percent));
}
@Override
public Collection getPckStatusMessagePatterns() {
- return Collections.emptyList();
+ return Collections.singleton(PATTERN);
}
}
diff --git a/bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/subhandler/AbstractLcnModuleSubHandler.java b/bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/subhandler/AbstractLcnModuleSubHandler.java
index 89638aac9..ea7b5e517 100644
--- a/bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/subhandler/AbstractLcnModuleSubHandler.java
+++ b/bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/subhandler/AbstractLcnModuleSubHandler.java
@@ -13,7 +13,6 @@
package org.openhab.binding.lcn.internal.subhandler;
import java.util.Arrays;
-import java.util.Optional;
import java.util.regex.Matcher;
import org.eclipse.jdt.annotation.NonNullByDefault;
@@ -121,17 +120,17 @@ public abstract class AbstractLcnModuleSubHandler implements ILcnModuleSubHandle
* @return true, if the message could be processed successfully
*/
public void tryParse(String pck) {
- Optional firstSuccessfulMatcher = getPckStatusMessagePatterns().stream().map(p -> p.matcher(pck))
- .filter(Matcher::matches).filter(m -> handler.isMyAddress(m.group("segId"), m.group("modId")))
- .findAny();
-
- firstSuccessfulMatcher.ifPresent(matcher -> {
- try {
- handleStatusMessage(matcher);
- } catch (LcnException e) {
- logger.warn("Parse error: {}", e.getMessage());
- }
- });
+ getPckStatusMessagePatterns().stream() //
+ .map(p -> p.matcher(pck)) //
+ .filter(Matcher::matches) //
+ .filter(m -> handler.isMyAddress(m.group("segId"), m.group("modId"))) //
+ .forEach(matcher -> {
+ try {
+ handleStatusMessage(matcher);
+ } catch (LcnException e) {
+ logger.warn("Parse error: {}", e.getMessage());
+ }
+ });
}
/**
diff --git a/bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/subhandler/LcnModuleOperatingHoursCounterSubHandler.java b/bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/subhandler/LcnModuleOperatingHoursCounterSubHandler.java
new file mode 100644
index 000000000..2fa8de3a9
--- /dev/null
+++ b/bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/subhandler/LcnModuleOperatingHoursCounterSubHandler.java
@@ -0,0 +1,86 @@
+/**
+ * Copyright (c) 2010-2022 Contributors to the openHAB project
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ */
+package org.openhab.binding.lcn.internal.subhandler;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.openhab.binding.lcn.internal.LcnBindingConstants;
+import org.openhab.binding.lcn.internal.LcnModuleHandler;
+import org.openhab.binding.lcn.internal.common.LcnChannelGroup;
+import org.openhab.binding.lcn.internal.connection.ModInfo;
+import org.openhab.core.library.types.QuantityType;
+import org.openhab.core.library.unit.Units;
+
+/**
+ * Handles Commands and State changes of operating hours counters of an LCN module.
+ *
+ * @author Fabian Wolter - Initial contribution
+ */
+@NonNullByDefault
+public class LcnModuleOperatingHoursCounterSubHandler extends AbstractLcnModuleSubHandler {
+ private static final Pattern PATTERN = Pattern.compile("\\$" + LcnBindingConstants.ADDRESS_WITHOUT_PREFIX + //
+ "(?[" + Type.createPattern() + "])(?\\d)(?\\d+)");
+
+ private enum Type {
+ OUTPUT("A", "output"),
+ RELAY("R", "relay"),
+ BINARY_INPUT("B", "binarysensor"),
+ OUTPUT_RELATIVE_WORK("I", "outputrelativework");
+
+ String pattern;
+ String id;
+
+ private Type(String pattern, String id) {
+ this.pattern = pattern;
+ this.id = id;
+ }
+
+ public static String getId(String pattern) {
+ return Stream.of(values()).filter(t -> t.pattern.equals(pattern)).findAny().get().id;
+ }
+
+ public static String createPattern() {
+ return Stream.of(values()).map(t -> t.pattern).collect(Collectors.joining("|"));
+ }
+ }
+
+ public LcnModuleOperatingHoursCounterSubHandler(LcnModuleHandler handler, ModInfo info) {
+ super(handler, info);
+ }
+
+ @Override
+ public void handleRefresh(LcnChannelGroup channelGroup, int number) {
+ // nothing
+ }
+
+ @Override
+ public Collection getPckStatusMessagePatterns() {
+ return Arrays.asList(PATTERN);
+ }
+
+ @Override
+ public void handleStatusMessage(Matcher matcher) {
+ String number = matcher.group("number");
+ String type = matcher.group("type");
+ long durationSec = Long.parseLong(matcher.group("durationSec"));
+
+ handler.updateChannel(LcnChannelGroup.OPERATINGHOURS, Type.getId(type) + number,
+ QuantityType.valueOf(durationSec, Units.SECOND));
+ }
+}
diff --git a/bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/subhandler/LcnModuleOutputSubHandler.java b/bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/subhandler/LcnModuleOutputSubHandler.java
index a87c103c3..2c1431441 100644
--- a/bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/subhandler/LcnModuleOutputSubHandler.java
+++ b/bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/subhandler/LcnModuleOutputSubHandler.java
@@ -29,6 +29,7 @@ import org.openhab.binding.lcn.internal.connection.ModInfo;
import org.openhab.core.library.types.HSBType;
import org.openhab.core.library.types.OnOffType;
import org.openhab.core.library.types.PercentType;
+import org.openhab.core.library.types.StringType;
import org.openhab.core.library.types.UpDownType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -53,8 +54,8 @@ public class LcnModuleOutputSubHandler extends AbstractLcnModuleSubHandler {
}
static {
- PERCENT_PATTERN = Pattern.compile(LcnBindingConstants.ADDRESS_REGEX + "A(?\\d)(?\\d+)");
- NATIVE_PATTERN = Pattern.compile(LcnBindingConstants.ADDRESS_REGEX + "O(?\\d)(?\\d+)");
+ PERCENT_PATTERN = Pattern.compile(LcnBindingConstants.ADDRESS_REGEX + "A(?\\d)(?\\d{3})");
+ NATIVE_PATTERN = Pattern.compile(LcnBindingConstants.ADDRESS_REGEX + "O(?\\d)(?\\d{3})");
}
@Override
@@ -142,6 +143,25 @@ public class LcnModuleOutputSubHandler extends AbstractLcnModuleSubHandler {
}
}
+ @Override
+ public void handleCommandString(StringType command, int number) throws LcnException {
+ int mode = 0;
+
+ switch (command.toString()) {
+ case "DISABLE":
+ mode = 0;
+ break;
+ case "OUTPUT1":
+ mode = 1;
+ break;
+ case "BOTH":
+ mode = 2;
+ break;
+ }
+
+ handler.sendPck(PckGenerator.setTunableWhiteMode(mode));
+ }
+
@Override
public void handleStatusMessage(Matcher matcher) {
int outputId = Integer.parseInt(matcher.group("outputId")) - 1;
diff --git a/bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/subhandler/LcnModuleRollershutterRelayPositionSubHandler.java b/bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/subhandler/LcnModuleRollershutterRelayPositionSubHandler.java
new file mode 100644
index 000000000..ca172ffc3
--- /dev/null
+++ b/bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/subhandler/LcnModuleRollershutterRelayPositionSubHandler.java
@@ -0,0 +1,39 @@
+/**
+ * Copyright (c) 2010-2022 Contributors to the openHAB project
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ */
+package org.openhab.binding.lcn.internal.subhandler;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.openhab.binding.lcn.internal.LcnModuleHandler;
+import org.openhab.binding.lcn.internal.common.LcnChannelGroup;
+import org.openhab.binding.lcn.internal.common.LcnException;
+import org.openhab.binding.lcn.internal.common.PckGenerator;
+import org.openhab.binding.lcn.internal.connection.ModInfo;
+import org.openhab.core.library.types.PercentType;
+
+/**
+ * Handles Commands and State changes of roller shutters connected to relay outputs of an LCN module.
+ *
+ * @author Fabian Wolter - Initial Contribution
+ */
+@NonNullByDefault
+public class LcnModuleRollershutterRelayPositionSubHandler extends AbstractLcnModuleRollershutterRelaySubHandler {
+ public LcnModuleRollershutterRelayPositionSubHandler(LcnModuleHandler handler, ModInfo info) {
+ super(handler, info);
+ }
+
+ @Override
+ public void handleCommandPercent(PercentType command, LcnChannelGroup channelGroup, int number)
+ throws LcnException {
+ handler.sendPck(PckGenerator.controlShutterPosition(number, command.intValue()));
+ }
+}
diff --git a/bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/subhandler/LcnModuleRollershutterRelaySlatAngleSubHandler.java b/bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/subhandler/LcnModuleRollershutterRelaySlatAngleSubHandler.java
new file mode 100644
index 000000000..61dfa6161
--- /dev/null
+++ b/bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/subhandler/LcnModuleRollershutterRelaySlatAngleSubHandler.java
@@ -0,0 +1,39 @@
+/**
+ * Copyright (c) 2010-2022 Contributors to the openHAB project
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ */
+package org.openhab.binding.lcn.internal.subhandler;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.openhab.binding.lcn.internal.LcnModuleHandler;
+import org.openhab.binding.lcn.internal.common.LcnChannelGroup;
+import org.openhab.binding.lcn.internal.common.LcnException;
+import org.openhab.binding.lcn.internal.common.PckGenerator;
+import org.openhab.binding.lcn.internal.connection.ModInfo;
+import org.openhab.core.library.types.PercentType;
+
+/**
+ * Handles Commands and State changes of roller shutters connected to relay outputs of an LCN module.
+ *
+ * @author Fabian Wolter - Initial Contribution
+ */
+@NonNullByDefault
+public class LcnModuleRollershutterRelaySlatAngleSubHandler extends AbstractLcnModuleRollershutterRelaySubHandler {
+ public LcnModuleRollershutterRelaySlatAngleSubHandler(LcnModuleHandler handler, ModInfo info) {
+ super(handler, info);
+ }
+
+ @Override
+ public void handleCommandPercent(PercentType command, LcnChannelGroup channelGroup, int number)
+ throws LcnException {
+ handler.sendPck(PckGenerator.controlShutterSlatAngle(number, command.intValue()));
+ }
+}
diff --git a/bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/subhandler/LcnModuleRvarModeSubHandler.java b/bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/subhandler/LcnModuleRvarModeSubHandler.java
new file mode 100644
index 000000000..3dac5c44c
--- /dev/null
+++ b/bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/subhandler/LcnModuleRvarModeSubHandler.java
@@ -0,0 +1,64 @@
+/**
+ * Copyright (c) 2010-2022 Contributors to the openHAB project
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ */
+package org.openhab.binding.lcn.internal.subhandler;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.openhab.binding.lcn.internal.LcnModuleHandler;
+import org.openhab.binding.lcn.internal.common.LcnException;
+import org.openhab.binding.lcn.internal.common.PckGenerator;
+import org.openhab.binding.lcn.internal.connection.ModInfo;
+import org.openhab.core.library.types.StringType;
+
+/**
+ * Handles the heating/cooling mode of a regulator.
+ *
+ * @author Fabian Wolter - Initial contribution
+ */
+@NonNullByDefault
+public class LcnModuleRvarModeSubHandler extends AbstractLcnModuleVariableSubHandler {
+ public LcnModuleRvarModeSubHandler(LcnModuleHandler handler, ModInfo info) {
+ super(handler, info);
+ }
+
+ @Override
+ public void handleStatusMessage(Matcher matcher) throws LcnException {
+ // nothing
+ }
+
+ @Override
+ public void handleCommandString(StringType command, int number) throws LcnException {
+ boolean cooling;
+ switch (command.toString()) {
+ case "HEATING":
+ cooling = false;
+ break;
+ case "COOLING":
+ cooling = true;
+ break;
+ default:
+ throw new LcnException();
+ }
+
+ handler.sendPck(PckGenerator.setRVarMode(number, cooling));
+ }
+
+ @Override
+ public Collection getPckStatusMessagePatterns() {
+ return Collections.emptyList();
+ }
+}
diff --git a/bundles/org.openhab.binding.lcn/src/main/resources/OH-INF/i18n/lcn.properties b/bundles/org.openhab.binding.lcn/src/main/resources/OH-INF/i18n/lcn.properties
index a9443bbbc..af7307cb5 100644
--- a/bundles/org.openhab.binding.lcn/src/main/resources/OH-INF/i18n/lcn.properties
+++ b/bundles/org.openhab.binding.lcn/src/main/resources/OH-INF/i18n/lcn.properties
@@ -10,7 +10,7 @@ thing-type.lcn.group.description = An LCN group with multiple modules, configure
thing-type.lcn.module.label = LCN Module
thing-type.lcn.module.description = An LCN bus module, e.g. LCN-UPP, LCN-SH, LCN-HU
thing-type.lcn.pckGateway.label = LCN-PCHK Gateway
-thing-type.lcn.pckGateway.description = An LCN gateway speaking the PCK language. E.g. LCN-PCHK software or the DIN rail device LCN-PKE.
+thing-type.lcn.pckGateway.description = An LCN gateway speaking the PCK language. E.g. LCN-PCHK software or the DIN rail device LCN-VISU.
# thing types config
@@ -107,6 +107,31 @@ channel-group-type.lcn.logics.channel.1.label = Logic Operation 1
channel-group-type.lcn.logics.channel.2.label = Logic Operation 2
channel-group-type.lcn.logics.channel.3.label = Logic Operation 3
channel-group-type.lcn.logics.channel.4.label = Logic Operation 4
+channel-group-type.lcn.operatinghourscounters.label = Operating Hours Counters
+channel-group-type.lcn.operatinghourscounters.channel.binarysensor1.label = Binary Sensor 1
+channel-group-type.lcn.operatinghourscounters.channel.binarysensor2.label = Binary Sensor 2
+channel-group-type.lcn.operatinghourscounters.channel.binarysensor3.label = Binary Sensor 3
+channel-group-type.lcn.operatinghourscounters.channel.binarysensor4.label = Binary Sensor 4
+channel-group-type.lcn.operatinghourscounters.channel.binarysensor5.label = Binary Sensor 5
+channel-group-type.lcn.operatinghourscounters.channel.binarysensor6.label = Binary Sensor 6
+channel-group-type.lcn.operatinghourscounters.channel.binarysensor7.label = Binary Sensor 7
+channel-group-type.lcn.operatinghourscounters.channel.binarysensor8.label = Binary Sensor 8
+channel-group-type.lcn.operatinghourscounters.channel.output1.label = Output 1
+channel-group-type.lcn.operatinghourscounters.channel.output2.label = Output 2
+channel-group-type.lcn.operatinghourscounters.channel.output3.label = Output 3
+channel-group-type.lcn.operatinghourscounters.channel.output4.label = Output 4
+channel-group-type.lcn.operatinghourscounters.channel.outputrelativework1.label = Output 1 Relative Work
+channel-group-type.lcn.operatinghourscounters.channel.outputrelativework2.label = Output 2 Relative Work
+channel-group-type.lcn.operatinghourscounters.channel.outputrelativework3.label = Output 3 Relative Work
+channel-group-type.lcn.operatinghourscounters.channel.outputrelativework4.label = Output 4 Relative Work
+channel-group-type.lcn.operatinghourscounters.channel.relay1.label = Relay 1
+channel-group-type.lcn.operatinghourscounters.channel.relay2.label = Relay 2
+channel-group-type.lcn.operatinghourscounters.channel.relay3.label = Relay 3
+channel-group-type.lcn.operatinghourscounters.channel.relay4.label = Relay 4
+channel-group-type.lcn.operatinghourscounters.channel.relay5.label = Relay 5
+channel-group-type.lcn.operatinghourscounters.channel.relay6.label = Relay 6
+channel-group-type.lcn.operatinghourscounters.channel.relay7.label = Relay 7
+channel-group-type.lcn.operatinghourscounters.channel.relay8.label = Relay 8
channel-group-type.lcn.outputs.label = Dimmer Outputs
channel-group-type.lcn.outputs.channel.1.label = Output 1
channel-group-type.lcn.outputs.channel.2.label = Output 2
@@ -124,14 +149,22 @@ channel-group-type.lcn.relays.channel.7.label = Relay 7
channel-group-type.lcn.relays.channel.8.label = Relay 8
channel-group-type.lcn.rollershutteroutputs.label = Roller Shutter (Dimmer)
channel-group-type.lcn.rollershutteroutputs.channel.1.label = Shutter 1-2
-channel-group-type.lcn.rollershutterrelays.label = Roller Shutter (Relay)
-channel-group-type.lcn.rollershutterrelays.channel.1.label = Shutter 1-2
-channel-group-type.lcn.rollershutterrelays.channel.2.label = Shutter 3-4
-channel-group-type.lcn.rollershutterrelays.channel.3.label = Shutter 5-6
-channel-group-type.lcn.rollershutterrelays.channel.4.label = Shutter 7-8
+channel-group-type.lcn.rollershutterrelays.label = Shutter (Relay)
+channel-group-type.lcn.rollershutterrelays.channel.1.label = Position 1-2
+channel-group-type.lcn.rollershutterrelays.channel.2.label = Position 3-4
+channel-group-type.lcn.rollershutterrelays.channel.3.label = Position 5-6
+channel-group-type.lcn.rollershutterrelays.channel.4.label = Position 7-8
+channel-group-type.lcn.rollershutterrelayslats.label = Shutter Slat Angle (Relay)
+channel-group-type.lcn.rollershutterrelayslats.channel.1.label = Slat Angle 1-2
+channel-group-type.lcn.rollershutterrelayslats.channel.2.label = Slat Angle 3-4
+channel-group-type.lcn.rollershutterrelayslats.channel.3.label = Slat Angle 5-6
+channel-group-type.lcn.rollershutterrelayslats.channel.4.label = Slat Angle 7-8
channel-group-type.lcn.rvarlocks.label = RVar Lock State
channel-group-type.lcn.rvarlocks.channel.1.label = R1Var Lock
channel-group-type.lcn.rvarlocks.channel.2.label = R2Var Lock
+channel-group-type.lcn.rvarmodes.label = RVar Heating/Cooling
+channel-group-type.lcn.rvarmodes.channel.1.label = R1Var Mode
+channel-group-type.lcn.rvarmodes.channel.2.label = R2Var Mode
channel-group-type.lcn.rvarsetpoints.label = RVar Setpoints
channel-group-type.lcn.rvarsetpoints.channel.1.label = R1Var Setpoint
channel-group-type.lcn.rvarsetpoints.channel.2.label = R2Var Setpoint
@@ -191,6 +224,7 @@ channel-type.lcn.logic.label = Logic Operation
channel-type.lcn.logic.state.option.NOT = Not (not fulfilled)
channel-type.lcn.logic.state.option.OR = Or (partly fulfilled)
channel-type.lcn.logic.state.option.AND = And (fulfilled)
+channel-type.lcn.operatinghourscounter.label = Operating Hours Counter
channel-type.lcn.output.label = Output
channel-type.lcn.relay.label = Relay
channel-type.lcn.remotecontrolcodes.label = Remote Control (Codes)
@@ -198,8 +232,15 @@ channel-type.lcn.remotecontrolkeys.label = Remote Control (Keys)
channel-type.lcn.remotecontrolsbatterylow.label = Low Battery
channel-type.lcn.rollershutter.label = Roller Shutter
channel-type.lcn.rvarlock.label = RVar Lock State
+channel-type.lcn.rvarmode.label = RVar Heating/Cooling
+channel-type.lcn.rvarmode.state.option.HEATING = Heating
+channel-type.lcn.rvarmode.state.option.COOLING = Cooling
channel-type.lcn.sendKeys.label = Send Keys
channel-type.lcn.transponders.label = Transponder Codes
+channel-type.lcn.tunablewhite.label = Tunable White Mode
+channel-type.lcn.tunablewhite.state.option.DISABLE = Tunable White Disabled
+channel-type.lcn.tunablewhite.state.option.OUTPUT1 = Control Output 1 (Output 2 is auto)
+channel-type.lcn.tunablewhite.state.option.BOTH = Output 1 Brightness/Output 2 Temperature
channel-type.lcn.variable.label = Variable
# channel types config
diff --git a/bundles/org.openhab.binding.lcn/src/main/resources/OH-INF/thing/thing-types.xml b/bundles/org.openhab.binding.lcn/src/main/resources/OH-INF/thing/thing-types.xml
index 21ff3e598..20e9f64fe 100644
--- a/bundles/org.openhab.binding.lcn/src/main/resources/OH-INF/thing/thing-types.xml
+++ b/bundles/org.openhab.binding.lcn/src/main/resources/OH-INF/thing/thing-types.xml
@@ -5,7 +5,7 @@
- An LCN gateway speaking the PCK language. E.g. LCN-PCHK software or the DIN rail device LCN-PKE.
+ An LCN gateway speaking the PCK language. E.g. LCN-PCHK software or the DIN rail device LCN-VISU.
@@ -24,10 +24,12 @@
+
+
@@ -39,6 +41,7 @@
+
@@ -91,6 +94,19 @@
veto
+
+ String
+
+
+
+
+
+
+
+
+ recommend
+
+
@@ -109,6 +125,7 @@
+
@@ -151,7 +168,7 @@
Rollershutter
- veto
+ veto
@@ -163,19 +180,37 @@
-
+
-
+
-
+
-
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -378,6 +413,30 @@
+
+ String
+
+
+
+
+
+
+
+ recommend
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Switch
@@ -664,6 +723,90 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Number:Time
+
+
+
+
trigger
diff --git a/bundles/org.openhab.binding.lcn/src/test/java/org/openhab/binding/lcn/internal/ModuleActionsTest.java b/bundles/org.openhab.binding.lcn/src/test/java/org/openhab/binding/lcn/internal/ModuleActionsTest.java
index 57ad336e8..b36127470 100644
--- a/bundles/org.openhab.binding.lcn/src/test/java/org/openhab/binding/lcn/internal/ModuleActionsTest.java
+++ b/bundles/org.openhab.binding.lcn/src/test/java/org/openhab/binding/lcn/internal/ModuleActionsTest.java
@@ -200,4 +200,44 @@ public class ModuleActionsTest {
verify(handler).sendPck("TS---L00100000");
}
+
+ @Test
+ public void testBeepNull() throws LcnException {
+ a.beep(null, null, null);
+
+ verify(handler).sendPck("PIN1");
+ verify(handler, times(1)).sendPck(anyString());
+ }
+
+ @Test
+ public void testBeepSpecial() throws LcnException {
+ a.beep(null, "S", 5);
+
+ verify(handler).sendPck("PIS5");
+ verify(handler, times(1)).sendPck(anyString());
+ }
+
+ @Test
+ public void testBeepVolume() throws LcnException {
+ a.beep(50d, "3", 5);
+
+ verify(handler).sendPck("PIV050");
+ verify(handler).sendPck("PI35");
+ verify(handler, times(2)).sendPck(anyString());
+ }
+
+ @Test
+ public void testBeepInvalidVolume() throws LcnException {
+ a.beep(-1d, "3", 5);
+
+ verify(handler, times(0)).sendPck(anyString());
+ }
+
+ @Test
+ public void testBeepInvalidTonality() throws LcnException {
+ a.beep(null, "X", 5);
+
+ verify(handler).sendPck("PIN5");
+ verify(handler, times(1)).sendPck(anyString());
+ }
}
diff --git a/bundles/org.openhab.binding.lcn/src/test/java/org/openhab/binding/lcn/internal/subhandler/LcnModuleRollershutterRelaySubHandlerTest.java b/bundles/org.openhab.binding.lcn/src/test/java/org/openhab/binding/lcn/internal/subhandler/AbstractLcnModuleRollershutterRelaySubHandlerTest.java
similarity index 67%
rename from bundles/org.openhab.binding.lcn/src/test/java/org/openhab/binding/lcn/internal/subhandler/LcnModuleRollershutterRelaySubHandlerTest.java
rename to bundles/org.openhab.binding.lcn/src/test/java/org/openhab/binding/lcn/internal/subhandler/AbstractLcnModuleRollershutterRelaySubHandlerTest.java
index 3bac04e89..5443798eb 100644
--- a/bundles/org.openhab.binding.lcn/src/test/java/org/openhab/binding/lcn/internal/subhandler/LcnModuleRollershutterRelaySubHandlerTest.java
+++ b/bundles/org.openhab.binding.lcn/src/test/java/org/openhab/binding/lcn/internal/subhandler/AbstractLcnModuleRollershutterRelaySubHandlerTest.java
@@ -12,6 +12,7 @@
*/
package org.openhab.binding.lcn.internal.subhandler;
+import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.verify;
import org.eclipse.jdt.annotation.NonNullByDefault;
@@ -19,6 +20,7 @@ import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.openhab.binding.lcn.internal.common.LcnChannelGroup;
import org.openhab.binding.lcn.internal.common.LcnException;
+import org.openhab.core.library.types.PercentType;
import org.openhab.core.library.types.StopMoveType;
import org.openhab.core.library.types.UpDownType;
@@ -28,15 +30,16 @@ import org.openhab.core.library.types.UpDownType;
* @author Fabian Wolter - Initial contribution
*/
@NonNullByDefault
-public class LcnModuleRollershutterRelaySubHandlerTest extends AbstractTestLcnModuleSubHandler {
- private @NonNullByDefault({}) LcnModuleRollershutterRelaySubHandler l;
+public class AbstractLcnModuleRollershutterRelaySubHandlerTest extends AbstractTestLcnModuleSubHandler {
+ private @NonNullByDefault({}) AbstractLcnModuleRollershutterRelaySubHandler l;
@Override
@BeforeEach
public void setUp() {
super.setUp();
- l = new LcnModuleRollershutterRelaySubHandler(handler, info);
+ l = new AbstractLcnModuleRollershutterRelaySubHandler(handler, info) {
+ };
}
@Test
@@ -98,4 +101,32 @@ public class LcnModuleRollershutterRelaySubHandlerTest extends AbstractTestLcnMo
l.handleCommandStopMove(StopMoveType.MOVE, LcnChannelGroup.ROLLERSHUTTERRELAY, 3);
verify(handler).sendPck("R8------1-");
}
+
+ @Test
+ public void testShutter1Percent0Position() {
+ tryParseAllHandlers(":M000005P1000");
+ verify(handler).updateChannel(LcnChannelGroup.ROLLERSHUTTERRELAY, "1", new PercentType(0));
+ verify(handler).updateChannel(any(), any(), any());
+ }
+
+ @Test
+ public void testShutter4Percent100Position() {
+ tryParseAllHandlers(":M000005P4100");
+ verify(handler).updateChannel(LcnChannelGroup.ROLLERSHUTTERRELAY, "4", new PercentType(100));
+ verify(handler).updateChannel(any(), any(), any());
+ }
+
+ @Test
+ public void testShutter1Percent0Angle() {
+ tryParseAllHandlers(":M000005W1000");
+ verify(handler).updateChannel(LcnChannelGroup.ROLLERSHUTTERRELAYSLAT, "1", new PercentType(0));
+ verify(handler).updateChannel(any(), any(), any());
+ }
+
+ @Test
+ public void testShutter4Percent100Angle() {
+ tryParseAllHandlers(":M000005W4100");
+ verify(handler).updateChannel(LcnChannelGroup.ROLLERSHUTTERRELAYSLAT, "4", new PercentType(100));
+ verify(handler).updateChannel(any(), any(), any());
+ }
}
diff --git a/bundles/org.openhab.binding.lcn/src/test/java/org/openhab/binding/lcn/internal/subhandler/AbstractTestLcnModuleSubHandler.java b/bundles/org.openhab.binding.lcn/src/test/java/org/openhab/binding/lcn/internal/subhandler/AbstractTestLcnModuleSubHandler.java
index 665f6dda4..54160eea2 100644
--- a/bundles/org.openhab.binding.lcn/src/test/java/org/openhab/binding/lcn/internal/subhandler/AbstractTestLcnModuleSubHandler.java
+++ b/bundles/org.openhab.binding.lcn/src/test/java/org/openhab/binding/lcn/internal/subhandler/AbstractTestLcnModuleSubHandler.java
@@ -14,6 +14,9 @@ package org.openhab.binding.lcn.internal.subhandler;
import static org.mockito.Mockito.when;
+import java.util.ArrayList;
+import java.util.Collection;
+
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
@@ -35,8 +38,35 @@ public class AbstractTestLcnModuleSubHandler {
protected @Mock @NonNullByDefault({}) LcnModuleHandler handler;
protected @Mock @NonNullByDefault({}) ModInfo info;
+ private @NonNullByDefault({}) Collection allHandlers;
public void setUp() {
when(handler.isMyAddress("000", "005")).thenReturn(true);
+
+ allHandlers = new ArrayList<>();
+ allHandlers.add(new LcnModuleBinarySensorSubHandler(handler, info));
+ allHandlers.add(new LcnModuleCodeSubHandler(handler, info));
+ allHandlers.add(new LcnModuleHostCommandSubHandler(handler, info));
+ allHandlers.add(new LcnModuleKeyLockTableSubHandler(handler, info));
+ allHandlers.add(new LcnModuleLedSubHandler(handler, info));
+ allHandlers.add(new LcnModuleLogicSubHandler(handler, info));
+ allHandlers.add(new LcnModuleMetaAckSubHandler(handler, info));
+ allHandlers.add(new LcnModuleMetaFirmwareSubHandler(handler, info));
+ allHandlers.add(new LcnModuleOperatingHoursCounterSubHandler(handler, info));
+ allHandlers.add(new LcnModuleOutputSubHandler(handler, info));
+ allHandlers.add(new LcnModuleRelaySubHandler(handler, info));
+ allHandlers.add(new LcnModuleRollershutterOutputSubHandler(handler, info));
+ allHandlers.add(new AbstractLcnModuleRollershutterRelaySubHandler(handler, info) {
+ });
+ allHandlers.add(new LcnModuleRvarLockSubHandler(handler, info));
+ allHandlers.add(new LcnModuleRvarModeSubHandler(handler, info));
+ allHandlers.add(new LcnModuleRvarSetpointSubHandler(handler, info));
+ allHandlers.add(new LcnModuleS0CounterSubHandler(handler, info));
+ allHandlers.add(new LcnModuleThresholdSubHandler(handler, info));
+ allHandlers.add(new LcnModuleVariableSubHandler(handler, info));
+ }
+
+ protected void tryParseAllHandlers(String pck) {
+ allHandlers.forEach(h -> h.tryParse(pck));
}
}
diff --git a/bundles/org.openhab.binding.lcn/src/test/java/org/openhab/binding/lcn/internal/subhandler/LcnModuleBinarySensorSubHandlerTest.java b/bundles/org.openhab.binding.lcn/src/test/java/org/openhab/binding/lcn/internal/subhandler/LcnModuleBinarySensorSubHandlerTest.java
index fccc7340e..6ca0932ad 100644
--- a/bundles/org.openhab.binding.lcn/src/test/java/org/openhab/binding/lcn/internal/subhandler/LcnModuleBinarySensorSubHandlerTest.java
+++ b/bundles/org.openhab.binding.lcn/src/test/java/org/openhab/binding/lcn/internal/subhandler/LcnModuleBinarySensorSubHandlerTest.java
@@ -12,7 +12,8 @@
*/
package org.openhab.binding.lcn.internal.subhandler;
-import static org.mockito.Mockito.verify;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.*;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.junit.jupiter.api.BeforeEach;
@@ -27,19 +28,15 @@ import org.openhab.core.library.types.OpenClosedType;
*/
@NonNullByDefault
public class LcnModuleBinarySensorSubHandlerTest extends AbstractTestLcnModuleSubHandler {
- private @NonNullByDefault({}) LcnModuleBinarySensorSubHandler l;
-
@Override
@BeforeEach
public void setUp() {
super.setUp();
-
- l = new LcnModuleBinarySensorSubHandler(handler, info);
}
@Test
public void testStatusAllClosed() {
- l.tryParse("=M000005Bx000");
+ tryParseAllHandlers("=M000005Bx000");
verify(handler).updateChannel(LcnChannelGroup.BINARYSENSOR, "1", OpenClosedType.CLOSED);
verify(handler).updateChannel(LcnChannelGroup.BINARYSENSOR, "2", OpenClosedType.CLOSED);
verify(handler).updateChannel(LcnChannelGroup.BINARYSENSOR, "3", OpenClosedType.CLOSED);
@@ -48,11 +45,12 @@ public class LcnModuleBinarySensorSubHandlerTest extends AbstractTestLcnModuleSu
verify(handler).updateChannel(LcnChannelGroup.BINARYSENSOR, "6", OpenClosedType.CLOSED);
verify(handler).updateChannel(LcnChannelGroup.BINARYSENSOR, "7", OpenClosedType.CLOSED);
verify(handler).updateChannel(LcnChannelGroup.BINARYSENSOR, "8", OpenClosedType.CLOSED);
+ verify(handler, times(8)).updateChannel(any(), any(), any());
}
@Test
public void testStatusAllOpen() {
- l.tryParse("=M000005Bx255");
+ tryParseAllHandlers("=M000005Bx255");
verify(handler).updateChannel(LcnChannelGroup.BINARYSENSOR, "1", OpenClosedType.OPEN);
verify(handler).updateChannel(LcnChannelGroup.BINARYSENSOR, "2", OpenClosedType.OPEN);
verify(handler).updateChannel(LcnChannelGroup.BINARYSENSOR, "3", OpenClosedType.OPEN);
@@ -60,11 +58,12 @@ public class LcnModuleBinarySensorSubHandlerTest extends AbstractTestLcnModuleSu
verify(handler).updateChannel(LcnChannelGroup.BINARYSENSOR, "6", OpenClosedType.OPEN);
verify(handler).updateChannel(LcnChannelGroup.BINARYSENSOR, "7", OpenClosedType.OPEN);
verify(handler).updateChannel(LcnChannelGroup.BINARYSENSOR, "8", OpenClosedType.OPEN);
+ verify(handler, times(8)).updateChannel(any(), any(), any());
}
@Test
public void testStatus1And7Closed() {
- l.tryParse("=M000005Bx065");
+ tryParseAllHandlers("=M000005Bx065");
verify(handler).updateChannel(LcnChannelGroup.BINARYSENSOR, "1", OpenClosedType.OPEN);
verify(handler).updateChannel(LcnChannelGroup.BINARYSENSOR, "2", OpenClosedType.CLOSED);
verify(handler).updateChannel(LcnChannelGroup.BINARYSENSOR, "3", OpenClosedType.CLOSED);
@@ -73,5 +72,6 @@ public class LcnModuleBinarySensorSubHandlerTest extends AbstractTestLcnModuleSu
verify(handler).updateChannel(LcnChannelGroup.BINARYSENSOR, "6", OpenClosedType.CLOSED);
verify(handler).updateChannel(LcnChannelGroup.BINARYSENSOR, "7", OpenClosedType.OPEN);
verify(handler).updateChannel(LcnChannelGroup.BINARYSENSOR, "8", OpenClosedType.CLOSED);
+ verify(handler, times(8)).updateChannel(any(), any(), any());
}
}
diff --git a/bundles/org.openhab.binding.lcn/src/test/java/org/openhab/binding/lcn/internal/subhandler/LcnModuleHostCommandSubHandlerTest.java b/bundles/org.openhab.binding.lcn/src/test/java/org/openhab/binding/lcn/internal/subhandler/LcnModuleHostCommandSubHandlerTest.java
index 26183f60f..eb1d0fd30 100644
--- a/bundles/org.openhab.binding.lcn/src/test/java/org/openhab/binding/lcn/internal/subhandler/LcnModuleHostCommandSubHandlerTest.java
+++ b/bundles/org.openhab.binding.lcn/src/test/java/org/openhab/binding/lcn/internal/subhandler/LcnModuleHostCommandSubHandlerTest.java
@@ -12,7 +12,8 @@
*/
package org.openhab.binding.lcn.internal.subhandler;
-import static org.mockito.Mockito.verify;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.*;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.junit.jupiter.api.BeforeEach;
@@ -26,48 +27,49 @@ import org.openhab.binding.lcn.internal.common.LcnChannelGroup;
*/
@NonNullByDefault
public class LcnModuleHostCommandSubHandlerTest extends AbstractTestLcnModuleSubHandler {
- private @NonNullByDefault({}) LcnModuleHostCommandSubHandler subHandler;
-
@Override
@BeforeEach
public void setUp() {
super.setUp();
-
- subHandler = new LcnModuleHostCommandSubHandler(handler, info);
}
@Test
public void testA1Hit() {
- subHandler.tryParse("+M004000005.STH065001");
+ tryParseAllHandlers("+M004000005.STH065001");
verify(handler).triggerChannel(LcnChannelGroup.HOSTCOMMAND, "sendKeys", "A1:HIT");
+ verify(handler).triggerChannel(any(), any(), any());
}
@Test
public void testA1Make() {
- subHandler.tryParse("+M004000005.STH066001");
+ tryParseAllHandlers("+M004000005.STH066001");
verify(handler).triggerChannel(LcnChannelGroup.HOSTCOMMAND, "sendKeys", "A1:MAKE");
+ verify(handler).triggerChannel(any(), any(), any());
}
@Test
public void testC8Break() {
- subHandler.tryParse("+M004000005.STH112128");
+ tryParseAllHandlers("+M004000005.STH112128");
verify(handler).triggerChannel(LcnChannelGroup.HOSTCOMMAND, "sendKeys", "C8:BREAK");
+ verify(handler).triggerChannel(any(), any(), any());
}
@Test
public void testC1Hit() {
- subHandler.tryParse("+M004000005.STH080001");
+ tryParseAllHandlers("+M004000005.STH080001");
verify(handler).triggerChannel(LcnChannelGroup.HOSTCOMMAND, "sendKeys", "C1:HIT");
+ verify(handler).triggerChannel(any(), any(), any());
}
@Test
public void testMultiple() {
- subHandler.tryParse("+M004000005.STH121034");
+ tryParseAllHandlers("+M004000005.STH121034");
verify(handler).triggerChannel(LcnChannelGroup.HOSTCOMMAND, "sendKeys", "A2:HIT");
verify(handler).triggerChannel(LcnChannelGroup.HOSTCOMMAND, "sendKeys", "A6:HIT");
verify(handler).triggerChannel(LcnChannelGroup.HOSTCOMMAND, "sendKeys", "B2:MAKE");
verify(handler).triggerChannel(LcnChannelGroup.HOSTCOMMAND, "sendKeys", "B6:MAKE");
verify(handler).triggerChannel(LcnChannelGroup.HOSTCOMMAND, "sendKeys", "C2:BREAK");
verify(handler).triggerChannel(LcnChannelGroup.HOSTCOMMAND, "sendKeys", "C6:BREAK");
+ verify(handler, times(6)).triggerChannel(any(), any(), any());
}
}
diff --git a/bundles/org.openhab.binding.lcn/src/test/java/org/openhab/binding/lcn/internal/subhandler/LcnModuleKeyLockTableSubHandlerTest.java b/bundles/org.openhab.binding.lcn/src/test/java/org/openhab/binding/lcn/internal/subhandler/LcnModuleKeyLockTableSubHandlerTest.java
index 8c184019b..d96a40071 100644
--- a/bundles/org.openhab.binding.lcn/src/test/java/org/openhab/binding/lcn/internal/subhandler/LcnModuleKeyLockTableSubHandlerTest.java
+++ b/bundles/org.openhab.binding.lcn/src/test/java/org/openhab/binding/lcn/internal/subhandler/LcnModuleKeyLockTableSubHandlerTest.java
@@ -12,7 +12,8 @@
*/
package org.openhab.binding.lcn.internal.subhandler;
-import static org.mockito.Mockito.verify;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.*;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.junit.jupiter.api.BeforeEach;
@@ -40,7 +41,7 @@ public class LcnModuleKeyLockTableSubHandlerTest extends AbstractTestLcnModuleSu
@Test
public void testStatus() {
- l.tryParse("=M000005.TX098036000255");
+ tryParseAllHandlers("=M000005.TX098036000255");
verify(handler).updateChannel(LcnChannelGroup.KEYLOCKTABLEA, "1", OnOffType.OFF);
verify(handler).updateChannel(LcnChannelGroup.KEYLOCKTABLEA, "2", OnOffType.ON);
verify(handler).updateChannel(LcnChannelGroup.KEYLOCKTABLEA, "3", OnOffType.OFF);
@@ -73,6 +74,7 @@ public class LcnModuleKeyLockTableSubHandlerTest extends AbstractTestLcnModuleSu
verify(handler).updateChannel(LcnChannelGroup.KEYLOCKTABLED, "6", OnOffType.ON);
verify(handler).updateChannel(LcnChannelGroup.KEYLOCKTABLED, "7", OnOffType.ON);
verify(handler).updateChannel(LcnChannelGroup.KEYLOCKTABLED, "8", OnOffType.ON);
+ verify(handler, times(32)).updateChannel(any(), any(), any());
}
@Test
diff --git a/bundles/org.openhab.binding.lcn/src/test/java/org/openhab/binding/lcn/internal/subhandler/LcnModuleLogicSubHandlerTest.java b/bundles/org.openhab.binding.lcn/src/test/java/org/openhab/binding/lcn/internal/subhandler/LcnModuleLogicSubHandlerTest.java
index 5e2b99999..1607f45e9 100644
--- a/bundles/org.openhab.binding.lcn/src/test/java/org/openhab/binding/lcn/internal/subhandler/LcnModuleLogicSubHandlerTest.java
+++ b/bundles/org.openhab.binding.lcn/src/test/java/org/openhab/binding/lcn/internal/subhandler/LcnModuleLogicSubHandlerTest.java
@@ -12,7 +12,8 @@
*/
package org.openhab.binding.lcn.internal.subhandler;
-import static org.mockito.Mockito.verify;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.*;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.junit.jupiter.api.BeforeEach;
@@ -34,19 +35,16 @@ public class LcnModuleLogicSubHandlerTest extends AbstractTestLcnModuleSubHandle
private static final StringType NOT = new StringType("NOT");
private static final StringType OR = new StringType("OR");
private static final StringType AND = new StringType("AND");
- private @NonNullByDefault({}) LcnModuleLogicSubHandler l;
@Override
@BeforeEach
public void setUp() {
super.setUp();
-
- l = new LcnModuleLogicSubHandler(handler, info);
}
@Test
public void testStatusLedOffLogicNot() {
- l.tryParse("=M000005.TLAAAAAAAAAAAANNNN");
+ tryParseAllHandlers("=M000005.TLAAAAAAAAAAAANNNN");
verify(handler).updateChannel(LcnChannelGroup.LED, "1", OFF);
verify(handler).updateChannel(LcnChannelGroup.LED, "2", OFF);
verify(handler).updateChannel(LcnChannelGroup.LED, "3", OFF);
@@ -63,11 +61,12 @@ public class LcnModuleLogicSubHandlerTest extends AbstractTestLcnModuleSubHandle
verify(handler).updateChannel(LcnChannelGroup.LOGIC, "2", NOT);
verify(handler).updateChannel(LcnChannelGroup.LOGIC, "3", NOT);
verify(handler).updateChannel(LcnChannelGroup.LOGIC, "4", NOT);
+ verify(handler, times(16)).updateChannel(any(), any(), any());
}
@Test
public void testStatusMixed() {
- l.tryParse("=M000005.TLAEBFAAAAAAAFNVNT");
+ tryParseAllHandlers("=M000005.TLAEBFAAAAAAAFNVNT");
verify(handler).updateChannel(LcnChannelGroup.LED, "1", OFF);
verify(handler).updateChannel(LcnChannelGroup.LED, "2", ON);
verify(handler).updateChannel(LcnChannelGroup.LED, "3", BLINK);
@@ -84,23 +83,27 @@ public class LcnModuleLogicSubHandlerTest extends AbstractTestLcnModuleSubHandle
verify(handler).updateChannel(LcnChannelGroup.LOGIC, "2", AND);
verify(handler).updateChannel(LcnChannelGroup.LOGIC, "3", NOT);
verify(handler).updateChannel(LcnChannelGroup.LOGIC, "4", OR);
+ verify(handler, times(16)).updateChannel(any(), any(), any());
}
@Test
public void testStatusSingleLogic1Not() {
- l.tryParse("=M000005S1000");
+ tryParseAllHandlers("=M000005S1000");
verify(handler).updateChannel(LcnChannelGroup.LOGIC, "1", NOT);
+ verify(handler).updateChannel(any(), any(), any());
}
@Test
public void testStatusSingleLogic4Or() {
- l.tryParse("=M000005S4025");
+ tryParseAllHandlers("=M000005S4025");
verify(handler).updateChannel(LcnChannelGroup.LOGIC, "4", OR);
+ verify(handler).updateChannel(any(), any(), any());
}
@Test
public void testStatusSingleLogic3And() {
- l.tryParse("=M000005S3050");
+ tryParseAllHandlers("=M000005S3050");
verify(handler).updateChannel(LcnChannelGroup.LOGIC, "3", AND);
+ verify(handler).updateChannel(any(), any(), any());
}
}
diff --git a/bundles/org.openhab.binding.lcn/src/test/java/org/openhab/binding/lcn/internal/subhandler/LcnModuleOperatingHoursCounterSubHandlerTest.java b/bundles/org.openhab.binding.lcn/src/test/java/org/openhab/binding/lcn/internal/subhandler/LcnModuleOperatingHoursCounterSubHandlerTest.java
new file mode 100644
index 000000000..611c4b0cc
--- /dev/null
+++ b/bundles/org.openhab.binding.lcn/src/test/java/org/openhab/binding/lcn/internal/subhandler/LcnModuleOperatingHoursCounterSubHandlerTest.java
@@ -0,0 +1,99 @@
+/**
+ * Copyright (c) 2010-2022 Contributors to the openHAB project
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ */
+package org.openhab.binding.lcn.internal.subhandler;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.verify;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.openhab.binding.lcn.internal.common.LcnChannelGroup;
+import org.openhab.core.library.types.QuantityType;
+import org.openhab.core.library.unit.Units;
+
+/**
+ * Test class.
+ *
+ * @author Fabian Wolter - Initial contribution
+ */
+@NonNullByDefault
+public class LcnModuleOperatingHoursCounterSubHandlerTest extends AbstractTestLcnModuleSubHandler {
+ @Override
+ @BeforeEach
+ public void setUp() {
+ super.setUp();
+ }
+
+ @Test
+ public void testStatusOutput1Duration0() {
+ tryParseAllHandlers("$M000005A10000000000");
+ verify(handler).updateChannel(LcnChannelGroup.OPERATINGHOURS, "output1", QuantityType.valueOf(0, Units.SECOND));
+ verify(handler).updateChannel(any(), any(), any());
+ }
+
+ @Test
+ public void testStatusOutput1Duration9999999999() {
+ tryParseAllHandlers("$M000005A49999999999");
+ verify(handler).updateChannel(LcnChannelGroup.OPERATINGHOURS, "output4",
+ QuantityType.valueOf(9999999999L, Units.SECOND));
+ verify(handler).updateChannel(any(), any(), any());
+ }
+
+ @Test
+ public void testStatusOutputRelativeWork1Duration0() {
+ tryParseAllHandlers("$M000005I10000000000");
+ verify(handler).updateChannel(LcnChannelGroup.OPERATINGHOURS, "outputrelativework1",
+ QuantityType.valueOf(0, Units.SECOND));
+ verify(handler).updateChannel(any(), any(), any());
+ }
+
+ @Test
+ public void testStatusOutputRelativeWork1Duration9999999999() {
+ tryParseAllHandlers("$M000005I49999999999");
+ verify(handler).updateChannel(LcnChannelGroup.OPERATINGHOURS, "outputrelativework4",
+ QuantityType.valueOf(9999999999L, Units.SECOND));
+ verify(handler).updateChannel(any(), any(), any());
+ }
+
+ @Test
+ public void testStatusRelay1Duration0() {
+ tryParseAllHandlers("$M000005R10000000000");
+ verify(handler).updateChannel(LcnChannelGroup.OPERATINGHOURS, "relay1", QuantityType.valueOf(0, Units.SECOND));
+ verify(handler).updateChannel(any(), any(), any());
+ }
+
+ @Test
+ public void testStatusRelay1Duration9999999999() {
+ tryParseAllHandlers("$M000005R49999999999");
+ verify(handler).updateChannel(LcnChannelGroup.OPERATINGHOURS, "relay4",
+ QuantityType.valueOf(9999999999L, Units.SECOND));
+ verify(handler).updateChannel(any(), any(), any());
+ }
+
+ @Test
+ public void testStatusBinarySensor1Duration0() {
+ tryParseAllHandlers("$M000005B10000000000");
+ verify(handler).updateChannel(LcnChannelGroup.OPERATINGHOURS, "binarysensor1",
+ QuantityType.valueOf(0, Units.SECOND));
+ verify(handler).updateChannel(any(), any(), any());
+ }
+
+ @Test
+ public void testStatusBinarySensor1Duration9999999999() {
+ tryParseAllHandlers("$M000005B49999999999");
+ verify(handler).updateChannel(LcnChannelGroup.OPERATINGHOURS, "binarysensor4",
+ QuantityType.valueOf(9999999999L, Units.SECOND));
+ verify(handler).updateChannel(any(), any(), any());
+ }
+}
diff --git a/bundles/org.openhab.binding.lcn/src/test/java/org/openhab/binding/lcn/internal/subhandler/LcnModuleOutputSubHandlerTest.java b/bundles/org.openhab.binding.lcn/src/test/java/org/openhab/binding/lcn/internal/subhandler/LcnModuleOutputSubHandlerTest.java
index 2a8a56ed3..98cf5d93e 100644
--- a/bundles/org.openhab.binding.lcn/src/test/java/org/openhab/binding/lcn/internal/subhandler/LcnModuleOutputSubHandlerTest.java
+++ b/bundles/org.openhab.binding.lcn/src/test/java/org/openhab/binding/lcn/internal/subhandler/LcnModuleOutputSubHandlerTest.java
@@ -12,7 +12,8 @@
*/
package org.openhab.binding.lcn.internal.subhandler;
-import static org.mockito.Mockito.verify;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.*;
import java.math.BigDecimal;
@@ -25,6 +26,8 @@ import org.openhab.binding.lcn.internal.common.LcnDefs;
import org.openhab.binding.lcn.internal.common.LcnException;
import org.openhab.core.library.types.OnOffType;
import org.openhab.core.library.types.PercentType;
+import org.openhab.core.library.types.StringType;
+import org.openhab.core.library.types.UpDownType;
/**
* Test class.
@@ -45,62 +48,78 @@ public class LcnModuleOutputSubHandlerTest extends AbstractTestLcnModuleSubHandl
@Test
public void testStatusOutput1OffPercent() {
- l.tryParse("=M000005A1000");
+ tryParseAllHandlers(":M000005A1000");
verify(handler).updateChannel(LcnChannelGroup.OUTPUT, "1", new PercentType(0));
+ verify(handler).updateChannel(any(), any(), any());
}
@Test
public void testStatusOutput2OffPercent() {
- l.tryParse("=M000005A2000");
+ tryParseAllHandlers(":M000005A2000");
verify(handler).updateChannel(LcnChannelGroup.OUTPUT, "2", new PercentType(0));
+ verify(handler).updateChannel(any(), any(), any());
}
@Test
public void testStatusOutput1OffNative() {
- l.tryParse("=M000005O1000");
+ tryParseAllHandlers(":M000005O1000");
verify(handler).updateChannel(LcnChannelGroup.OUTPUT, "1", new PercentType(0));
+ verify(handler).updateChannel(any(), any(), any());
}
@Test
public void testStatusOutput2OffNative() {
- l.tryParse("=M000005O2000");
+ tryParseAllHandlers(":M000005O2000");
verify(handler).updateChannel(LcnChannelGroup.OUTPUT, "2", new PercentType(0));
+ verify(handler).updateChannel(any(), any(), any());
}
@Test
public void testStatusOutput1OnPercent() {
- l.tryParse("=M000005A1100");
+ tryParseAllHandlers(":M000005A1100");
verify(handler).updateChannel(LcnChannelGroup.OUTPUT, "1", new PercentType(100));
+ verify(handler).updateChannel(LcnChannelGroup.ROLLERSHUTTEROUTPUT, "1", UpDownType.UP);
+ verify(handler, times(2)).updateChannel(any(), any(), any());
}
@Test
public void testStatusOutput2OnPercent() {
- l.tryParse("=M000005A2100");
+ tryParseAllHandlers(":M000005A2100");
verify(handler).updateChannel(LcnChannelGroup.OUTPUT, "2", new PercentType(100));
+ verify(handler).updateChannel(LcnChannelGroup.ROLLERSHUTTEROUTPUT, "1", UpDownType.DOWN);
+ verify(handler, times(2)).updateChannel(any(), any(), any());
}
@Test
public void testStatusOutput1OnNative() {
- l.tryParse("=M000005O1200");
+ tryParseAllHandlers(":M000005O1200");
verify(handler).updateChannel(LcnChannelGroup.OUTPUT, "1", new PercentType(100));
+ verify(handler).updateChannel(LcnChannelGroup.ROLLERSHUTTEROUTPUT, "1", UpDownType.UP);
+ verify(handler, times(2)).updateChannel(any(), any(), any());
}
@Test
public void testStatusOutput2OnNative() {
- l.tryParse("=M000005O2200");
+ tryParseAllHandlers(":M000005O2200");
verify(handler).updateChannel(LcnChannelGroup.OUTPUT, "2", new PercentType(100));
+ verify(handler).updateChannel(LcnChannelGroup.ROLLERSHUTTEROUTPUT, "1", UpDownType.DOWN);
+ verify(handler, times(2)).updateChannel(any(), any(), any());
}
@Test
public void testStatusOutput2On50Percent() {
- l.tryParse("=M000005A2050");
+ tryParseAllHandlers(":M000005A2050");
verify(handler).updateChannel(LcnChannelGroup.OUTPUT, "2", new PercentType(50));
+ verify(handler).updateChannel(LcnChannelGroup.ROLLERSHUTTEROUTPUT, "1", UpDownType.DOWN);
+ verify(handler, times(2)).updateChannel(any(), any(), any());
}
@Test
public void testStatusOutput1On50Native() {
- l.tryParse("=M000005O1100");
+ tryParseAllHandlers(":M000005O1100");
verify(handler).updateChannel(LcnChannelGroup.OUTPUT, "1", new PercentType(50));
+ verify(handler).updateChannel(LcnChannelGroup.ROLLERSHUTTEROUTPUT, "1", UpDownType.UP);
+ verify(handler, times(2)).updateChannel(any(), any(), any());
}
@Test
@@ -195,4 +214,22 @@ public class LcnModuleOutputSubHandlerTest extends AbstractTestLcnModuleSubHandl
l.handleCommandDimmerOutput(new DimmerOutputCommand(BigDecimal.valueOf(40), false, true, 0), 0);
verify(handler).sendPck("AY040040");
}
+
+ @Test
+ public void testHandleCommandTuneableWhite0() throws LcnException {
+ l.handleCommandString(new StringType("DISABLE"), 0);
+ verify(handler).sendPck("AW0");
+ }
+
+ @Test
+ public void testHandleCommandTuneableWhite1() throws LcnException {
+ l.handleCommandString(new StringType("OUTPUT1"), 0);
+ verify(handler).sendPck("AW1");
+ }
+
+ @Test
+ public void testHandleCommandTuneableWhite2() throws LcnException {
+ l.handleCommandString(new StringType("BOTH"), 0);
+ verify(handler).sendPck("AW2");
+ }
}
diff --git a/bundles/org.openhab.binding.lcn/src/test/java/org/openhab/binding/lcn/internal/subhandler/LcnModuleRelaySubHandlerTest.java b/bundles/org.openhab.binding.lcn/src/test/java/org/openhab/binding/lcn/internal/subhandler/LcnModuleRelaySubHandlerTest.java
index 30bac3228..bb7bb517d 100644
--- a/bundles/org.openhab.binding.lcn/src/test/java/org/openhab/binding/lcn/internal/subhandler/LcnModuleRelaySubHandlerTest.java
+++ b/bundles/org.openhab.binding.lcn/src/test/java/org/openhab/binding/lcn/internal/subhandler/LcnModuleRelaySubHandlerTest.java
@@ -12,7 +12,8 @@
*/
package org.openhab.binding.lcn.internal.subhandler;
-import static org.mockito.Mockito.verify;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.*;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.junit.jupiter.api.BeforeEach;
@@ -21,6 +22,7 @@ import org.openhab.binding.lcn.internal.common.LcnChannelGroup;
import org.openhab.binding.lcn.internal.common.LcnException;
import org.openhab.core.library.types.OnOffType;
import org.openhab.core.library.types.PercentType;
+import org.openhab.core.library.types.UpDownType;
/**
* Test class.
@@ -41,7 +43,7 @@ public class LcnModuleRelaySubHandlerTest extends AbstractTestLcnModuleSubHandle
@Test
public void testStatusAllOff() {
- l.tryParse("=M000005Rx000");
+ tryParseAllHandlers("=M000005Rx000");
verify(handler).updateChannel(LcnChannelGroup.RELAY, "1", OnOffType.OFF);
verify(handler).updateChannel(LcnChannelGroup.RELAY, "2", OnOffType.OFF);
verify(handler).updateChannel(LcnChannelGroup.RELAY, "3", OnOffType.OFF);
@@ -50,11 +52,16 @@ public class LcnModuleRelaySubHandlerTest extends AbstractTestLcnModuleSubHandle
verify(handler).updateChannel(LcnChannelGroup.RELAY, "6", OnOffType.OFF);
verify(handler).updateChannel(LcnChannelGroup.RELAY, "7", OnOffType.OFF);
verify(handler).updateChannel(LcnChannelGroup.RELAY, "8", OnOffType.OFF);
+ verify(handler).updateChannel(LcnChannelGroup.ROLLERSHUTTERRELAY, "1", UpDownType.UP);
+ verify(handler).updateChannel(LcnChannelGroup.ROLLERSHUTTERRELAY, "2", UpDownType.UP);
+ verify(handler).updateChannel(LcnChannelGroup.ROLLERSHUTTERRELAY, "3", UpDownType.UP);
+ verify(handler).updateChannel(LcnChannelGroup.ROLLERSHUTTERRELAY, "4", UpDownType.UP);
+ verify(handler, times(12)).updateChannel(any(), any(), any());
}
@Test
public void testStatusAllOn() {
- l.tryParse("=M000005Rx255");
+ tryParseAllHandlers("=M000005Rx255");
verify(handler).updateChannel(LcnChannelGroup.RELAY, "1", OnOffType.ON);
verify(handler).updateChannel(LcnChannelGroup.RELAY, "2", OnOffType.ON);
verify(handler).updateChannel(LcnChannelGroup.RELAY, "3", OnOffType.ON);
@@ -62,11 +69,16 @@ public class LcnModuleRelaySubHandlerTest extends AbstractTestLcnModuleSubHandle
verify(handler).updateChannel(LcnChannelGroup.RELAY, "6", OnOffType.ON);
verify(handler).updateChannel(LcnChannelGroup.RELAY, "7", OnOffType.ON);
verify(handler).updateChannel(LcnChannelGroup.RELAY, "8", OnOffType.ON);
+ verify(handler).updateChannel(LcnChannelGroup.ROLLERSHUTTERRELAY, "1", UpDownType.DOWN);
+ verify(handler).updateChannel(LcnChannelGroup.ROLLERSHUTTERRELAY, "2", UpDownType.DOWN);
+ verify(handler).updateChannel(LcnChannelGroup.ROLLERSHUTTERRELAY, "3", UpDownType.DOWN);
+ verify(handler).updateChannel(LcnChannelGroup.ROLLERSHUTTERRELAY, "4", UpDownType.DOWN);
+ verify(handler, times(12)).updateChannel(any(), any(), any());
}
@Test
public void testStatusRelay1Relay7On() {
- l.tryParse("=M000005Rx065");
+ tryParseAllHandlers("=M000005Rx065");
verify(handler).updateChannel(LcnChannelGroup.RELAY, "1", OnOffType.ON);
verify(handler).updateChannel(LcnChannelGroup.RELAY, "2", OnOffType.OFF);
verify(handler).updateChannel(LcnChannelGroup.RELAY, "3", OnOffType.OFF);
@@ -75,6 +87,11 @@ public class LcnModuleRelaySubHandlerTest extends AbstractTestLcnModuleSubHandle
verify(handler).updateChannel(LcnChannelGroup.RELAY, "6", OnOffType.OFF);
verify(handler).updateChannel(LcnChannelGroup.RELAY, "7", OnOffType.ON);
verify(handler).updateChannel(LcnChannelGroup.RELAY, "8", OnOffType.OFF);
+ verify(handler).updateChannel(LcnChannelGroup.ROLLERSHUTTERRELAY, "1", UpDownType.UP);
+ verify(handler).updateChannel(LcnChannelGroup.ROLLERSHUTTERRELAY, "2", UpDownType.UP);
+ verify(handler).updateChannel(LcnChannelGroup.ROLLERSHUTTERRELAY, "3", UpDownType.UP);
+ verify(handler).updateChannel(LcnChannelGroup.ROLLERSHUTTERRELAY, "4", UpDownType.UP);
+ verify(handler, times(12)).updateChannel(any(), any(), any());
}
@Test
diff --git a/bundles/org.openhab.binding.lcn/src/test/java/org/openhab/binding/lcn/internal/subhandler/LcnModuleRollershutterRelayPositionSubHandlerTest.java b/bundles/org.openhab.binding.lcn/src/test/java/org/openhab/binding/lcn/internal/subhandler/LcnModuleRollershutterRelayPositionSubHandlerTest.java
new file mode 100644
index 000000000..7260c099c
--- /dev/null
+++ b/bundles/org.openhab.binding.lcn/src/test/java/org/openhab/binding/lcn/internal/subhandler/LcnModuleRollershutterRelayPositionSubHandlerTest.java
@@ -0,0 +1,80 @@
+/**
+ * Copyright (c) 2010-2022 Contributors to the openHAB project
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ */
+package org.openhab.binding.lcn.internal.subhandler;
+
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.mockito.Mockito.verify;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.openhab.binding.lcn.internal.common.LcnChannelGroup;
+import org.openhab.binding.lcn.internal.common.LcnException;
+import org.openhab.binding.lcn.internal.common.PckGenerator;
+import org.openhab.core.library.types.PercentType;
+
+/**
+ * Test class.
+ *
+ * @author Fabian Wolter - Initial contribution
+ */
+@NonNullByDefault
+public class LcnModuleRollershutterRelayPositionSubHandlerTest extends AbstractTestLcnModuleSubHandler {
+ private @NonNullByDefault({}) AbstractLcnModuleRollershutterRelaySubHandler l;
+
+ @Override
+ @BeforeEach
+ public void setUp() {
+ super.setUp();
+
+ l = new LcnModuleRollershutterRelayPositionSubHandler(handler, info);
+ }
+
+ @Test
+ public void testMotor1percent0() throws LcnException {
+ l.handleCommandPercent(PercentType.ZERO, LcnChannelGroup.ROLLERSHUTTERRELAY, 0);
+ verify(handler).sendPck("JH000001");
+ }
+
+ @Test
+ public void testMotor1percent100() throws LcnException {
+ l.handleCommandPercent(PercentType.HUNDRED, LcnChannelGroup.ROLLERSHUTTERRELAY, 0);
+ verify(handler).sendPck("JH100001");
+ }
+
+ @Test
+ public void testMotor1percent50() throws LcnException {
+ l.handleCommandPercent(new PercentType(50), LcnChannelGroup.ROLLERSHUTTERRELAY, 0);
+ verify(handler).sendPck("JH050001");
+ }
+
+ @Test
+ public void testMotor4percent50() throws LcnException {
+ l.handleCommandPercent(new PercentType(50), LcnChannelGroup.ROLLERSHUTTERRELAY, 3);
+ verify(handler).sendPck("JH050008");
+ }
+
+ @Test
+ public void testInvalidMotor() throws LcnException {
+ assertThrows(LcnException.class, () -> {
+ l.handleCommandPercent(new PercentType(50), LcnChannelGroup.ROLLERSHUTTERRELAY, 4);
+ });
+ }
+
+ @Test
+ public void testInvalidPercent() throws LcnException {
+ assertThrows(LcnException.class, () -> {
+ PckGenerator.controlShutterPosition(0, 101);
+ });
+ }
+}
diff --git a/bundles/org.openhab.binding.lcn/src/test/java/org/openhab/binding/lcn/internal/subhandler/LcnModuleRollershutterRelaySlatAngleSubHandlerTest.java b/bundles/org.openhab.binding.lcn/src/test/java/org/openhab/binding/lcn/internal/subhandler/LcnModuleRollershutterRelaySlatAngleSubHandlerTest.java
new file mode 100644
index 000000000..307ce292c
--- /dev/null
+++ b/bundles/org.openhab.binding.lcn/src/test/java/org/openhab/binding/lcn/internal/subhandler/LcnModuleRollershutterRelaySlatAngleSubHandlerTest.java
@@ -0,0 +1,64 @@
+/**
+ * Copyright (c) 2010-2022 Contributors to the openHAB project
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ */
+package org.openhab.binding.lcn.internal.subhandler;
+
+import static org.mockito.Mockito.verify;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.openhab.binding.lcn.internal.common.LcnChannelGroup;
+import org.openhab.binding.lcn.internal.common.LcnException;
+import org.openhab.core.library.types.PercentType;
+
+/**
+ * Test class.
+ *
+ * @author Fabian Wolter - Initial contribution
+ */
+@NonNullByDefault
+public class LcnModuleRollershutterRelaySlatAngleSubHandlerTest extends AbstractTestLcnModuleSubHandler {
+ private @NonNullByDefault({}) AbstractLcnModuleRollershutterRelaySubHandler l;
+
+ @Override
+ @BeforeEach
+ public void setUp() {
+ super.setUp();
+
+ l = new LcnModuleRollershutterRelaySlatAngleSubHandler(handler, info);
+ }
+
+ @Test
+ public void testMotor1percent0() throws LcnException {
+ l.handleCommandPercent(PercentType.ZERO, LcnChannelGroup.ROLLERSHUTTERRELAYSLAT, 0);
+ verify(handler).sendPck("JW000001");
+ }
+
+ @Test
+ public void testMotor1percent100() throws LcnException {
+ l.handleCommandPercent(PercentType.HUNDRED, LcnChannelGroup.ROLLERSHUTTERRELAYSLAT, 0);
+ verify(handler).sendPck("JW100001");
+ }
+
+ @Test
+ public void testMotor1percent50() throws LcnException {
+ l.handleCommandPercent(new PercentType(50), LcnChannelGroup.ROLLERSHUTTERRELAYSLAT, 0);
+ verify(handler).sendPck("JW050001");
+ }
+
+ @Test
+ public void testMotor4percent50() throws LcnException {
+ l.handleCommandPercent(new PercentType(50), LcnChannelGroup.ROLLERSHUTTERRELAYSLAT, 3);
+ verify(handler).sendPck("JW050008");
+ }
+}
diff --git a/bundles/org.openhab.binding.lcn/src/test/java/org/openhab/binding/lcn/internal/subhandler/LcnModuleRvarModeSubHandlerTest.java b/bundles/org.openhab.binding.lcn/src/test/java/org/openhab/binding/lcn/internal/subhandler/LcnModuleRvarModeSubHandlerTest.java
new file mode 100644
index 000000000..ab916af90
--- /dev/null
+++ b/bundles/org.openhab.binding.lcn/src/test/java/org/openhab/binding/lcn/internal/subhandler/LcnModuleRvarModeSubHandlerTest.java
@@ -0,0 +1,63 @@
+/**
+ * Copyright (c) 2010-2022 Contributors to the openHAB project
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ */
+package org.openhab.binding.lcn.internal.subhandler;
+
+import static org.mockito.Mockito.verify;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.openhab.binding.lcn.internal.common.LcnException;
+import org.openhab.core.library.types.StringType;
+
+/**
+ * Test class.
+ *
+ * @author Fabian Wolter - Initial contribution
+ */
+@NonNullByDefault
+public class LcnModuleRvarModeSubHandlerTest extends AbstractTestLcnModuleSubHandler {
+ private @NonNullByDefault({}) LcnModuleRvarModeSubHandler l;
+
+ @Override
+ @BeforeEach
+ public void setUp() {
+ super.setUp();
+
+ l = new LcnModuleRvarModeSubHandler(handler, info);
+ }
+
+ @Test
+ public void testhandleCommand1Cooling() throws LcnException {
+ l.handleCommandString(new StringType("COOLING"), 0);
+ verify(handler).sendPck("REATC");
+ }
+
+ @Test
+ public void testhandleCommand1Heating() throws LcnException {
+ l.handleCommandString(new StringType("HEATING"), 0);
+ verify(handler).sendPck("REATH");
+ }
+
+ @Test
+ public void testhandleCommand2Cooling() throws LcnException {
+ l.handleCommandString(new StringType("COOLING"), 1);
+ verify(handler).sendPck("REBTC");
+ }
+
+ @Test
+ public void testhandleCommand2Heating() throws LcnException {
+ l.handleCommandString(new StringType("HEATING"), 1);
+ verify(handler).sendPck("REBTH");
+ }
+}
diff --git a/bundles/org.openhab.binding.lcn/src/test/java/org/openhab/binding/lcn/internal/subhandler/LcnModuleRvarSetpointSubHandlerTest.java b/bundles/org.openhab.binding.lcn/src/test/java/org/openhab/binding/lcn/internal/subhandler/LcnModuleRvarSetpointSubHandlerTest.java
index b765671dc..1c41b6578 100644
--- a/bundles/org.openhab.binding.lcn/src/test/java/org/openhab/binding/lcn/internal/subhandler/LcnModuleRvarSetpointSubHandlerTest.java
+++ b/bundles/org.openhab.binding.lcn/src/test/java/org/openhab/binding/lcn/internal/subhandler/LcnModuleRvarSetpointSubHandlerTest.java
@@ -12,6 +12,7 @@
*/
package org.openhab.binding.lcn.internal.subhandler;
+import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.*;
import org.eclipse.jdt.annotation.NonNullByDefault;
@@ -103,36 +104,41 @@ public class LcnModuleRvarSetpointSubHandlerTest extends AbstractTestLcnModuleSu
@Test
public void testRvar1() {
- l.tryParse("=M000005.S11234");
+ tryParseAllHandlers("=M000005.S11234");
verify(handler).updateChannel(LcnChannelGroup.RVARSETPOINT, "1", new DecimalType(1234));
verify(handler).updateChannel(LcnChannelGroup.RVARLOCK, "1", OnOffType.OFF);
+ verify(handler, times(2)).updateChannel(any(), any(), any());
}
@Test
public void testRvar2() {
- l.tryParse("=M000005.S21234");
+ tryParseAllHandlers("=M000005.S21234");
verify(handler).updateChannel(LcnChannelGroup.RVARSETPOINT, "2", new DecimalType(1234));
verify(handler).updateChannel(LcnChannelGroup.RVARLOCK, "2", OnOffType.OFF);
+ verify(handler, times(2)).updateChannel(any(), any(), any());
}
@Test
public void testRvar1SensorDefective() {
- l.tryParse("=M000005.S132512");
+ tryParseAllHandlers("=M000005.S132512");
verify(handler).updateChannel(LcnChannelGroup.RVARSETPOINT, "1", new StringType("DEFECTIVE"));
verify(handler).updateChannel(LcnChannelGroup.RVARLOCK, "1", OnOffType.OFF);
+ verify(handler, times(2)).updateChannel(any(), any(), any());
}
@Test
public void testRvar1Locked() {
- l.tryParse("=M000005.S134002");
+ tryParseAllHandlers("=M000005.S134002");
verify(handler).updateChannel(LcnChannelGroup.RVARSETPOINT, "1", new DecimalType(1234));
verify(handler).updateChannel(LcnChannelGroup.RVARLOCK, "1", OnOffType.ON);
+ verify(handler, times(2)).updateChannel(any(), any(), any());
}
@Test
public void testRvar2Locked() {
- l.tryParse("=M000005.S234002");
+ tryParseAllHandlers("=M000005.S234002");
verify(handler).updateChannel(LcnChannelGroup.RVARSETPOINT, "2", new DecimalType(1234));
verify(handler).updateChannel(LcnChannelGroup.RVARLOCK, "2", OnOffType.ON);
+ verify(handler, times(2)).updateChannel(any(), any(), any());
}
}
diff --git a/bundles/org.openhab.binding.lcn/src/test/java/org/openhab/binding/lcn/internal/subhandler/LcnModuleS0CounterSubHandlerTest.java b/bundles/org.openhab.binding.lcn/src/test/java/org/openhab/binding/lcn/internal/subhandler/LcnModuleS0CounterSubHandlerTest.java
index 7fea0b1af..189975ef8 100644
--- a/bundles/org.openhab.binding.lcn/src/test/java/org/openhab/binding/lcn/internal/subhandler/LcnModuleS0CounterSubHandlerTest.java
+++ b/bundles/org.openhab.binding.lcn/src/test/java/org/openhab/binding/lcn/internal/subhandler/LcnModuleS0CounterSubHandlerTest.java
@@ -12,6 +12,7 @@
*/
package org.openhab.binding.lcn.internal.subhandler;
+import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.verify;
import org.eclipse.jdt.annotation.NonNullByDefault;
@@ -27,31 +28,30 @@ import org.openhab.core.library.types.DecimalType;
*/
@NonNullByDefault
public class LcnModuleS0CounterSubHandlerTest extends AbstractTestLcnModuleSubHandler {
- private @NonNullByDefault({}) LcnModuleS0CounterSubHandler l;
-
@Override
@BeforeEach
public void setUp() {
super.setUp();
-
- l = new LcnModuleS0CounterSubHandler(handler, info);
}
@Test
public void testZero() {
- l.tryParse("=M000005.C10");
+ tryParseAllHandlers("=M000005.C10");
verify(handler).updateChannel(LcnChannelGroup.S0INPUT, "1", new DecimalType(0));
+ verify(handler).updateChannel(any(), any(), any());
}
@Test
public void testMaxValue() {
- l.tryParse("=M000005.C14294967295");
+ tryParseAllHandlers("=M000005.C14294967295");
verify(handler).updateChannel(LcnChannelGroup.S0INPUT, "1", new DecimalType(4294967295L));
+ verify(handler).updateChannel(any(), any(), any());
}
@Test
public void test4() {
- l.tryParse("=M000005.C412345");
+ tryParseAllHandlers("=M000005.C412345");
verify(handler).updateChannel(LcnChannelGroup.S0INPUT, "4", new DecimalType(12345));
+ verify(handler).updateChannel(any(), any(), any());
}
}
diff --git a/bundles/org.openhab.binding.lcn/src/test/java/org/openhab/binding/lcn/internal/subhandler/LcnModuleThresholdSubHandlerTest.java b/bundles/org.openhab.binding.lcn/src/test/java/org/openhab/binding/lcn/internal/subhandler/LcnModuleThresholdSubHandlerTest.java
index a83003a9e..ef8ab1dca 100644
--- a/bundles/org.openhab.binding.lcn/src/test/java/org/openhab/binding/lcn/internal/subhandler/LcnModuleThresholdSubHandlerTest.java
+++ b/bundles/org.openhab.binding.lcn/src/test/java/org/openhab/binding/lcn/internal/subhandler/LcnModuleThresholdSubHandlerTest.java
@@ -12,6 +12,7 @@
*/
package org.openhab.binding.lcn.internal.subhandler;
+import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.*;
import org.eclipse.jdt.annotation.NonNullByDefault;
@@ -41,30 +42,34 @@ public class LcnModuleThresholdSubHandlerTest extends AbstractTestLcnModuleSubHa
@Test
public void testThreshold11() {
- l.tryParse("=M000005.T1112345");
+ tryParseAllHandlers("=M000005.T1112345");
verify(handler).updateChannel(LcnChannelGroup.THRESHOLDREGISTER1, "1", new DecimalType(12345));
+ verify(handler).updateChannel(any(), any(), any());
}
@Test
public void testThreshold14() {
- l.tryParse("=M000005.T140");
+ tryParseAllHandlers("=M000005.T140");
verify(handler).updateChannel(LcnChannelGroup.THRESHOLDREGISTER1, "4", new DecimalType(0));
+ verify(handler).updateChannel(any(), any(), any());
}
@Test
public void testThreshold41() {
- l.tryParse("=M000005.T4112345");
+ tryParseAllHandlers("=M000005.T4112345");
verify(handler).updateChannel(LcnChannelGroup.THRESHOLDREGISTER4, "1", new DecimalType(12345));
+ verify(handler).updateChannel(any(), any(), any());
}
@Test
public void testThresholdLegacy() {
- l.tryParse("=M000005.S1123451123411123000000000112345");
+ tryParseAllHandlers("=M000005.S1123451123411123000000000112345");
verify(handler).updateChannel(LcnChannelGroup.THRESHOLDREGISTER1, "1", new DecimalType(12345));
verify(handler).updateChannel(LcnChannelGroup.THRESHOLDREGISTER1, "2", new DecimalType(11234));
verify(handler).updateChannel(LcnChannelGroup.THRESHOLDREGISTER1, "3", new DecimalType(11123));
verify(handler).updateChannel(LcnChannelGroup.THRESHOLDREGISTER1, "4", new DecimalType(0));
verify(handler).updateChannel(LcnChannelGroup.THRESHOLDREGISTER1, "5", new DecimalType(1));
+ verify(handler, times(5)).updateChannel(any(), any(), any());
}
@Test
diff --git a/bundles/org.openhab.binding.lcn/src/test/java/org/openhab/binding/lcn/internal/subhandler/LcnModuleVariableSubHandlerTest.java b/bundles/org.openhab.binding.lcn/src/test/java/org/openhab/binding/lcn/internal/subhandler/LcnModuleVariableSubHandlerTest.java
index 35a3a6e6c..59062efe7 100644
--- a/bundles/org.openhab.binding.lcn/src/test/java/org/openhab/binding/lcn/internal/subhandler/LcnModuleVariableSubHandlerTest.java
+++ b/bundles/org.openhab.binding.lcn/src/test/java/org/openhab/binding/lcn/internal/subhandler/LcnModuleVariableSubHandlerTest.java
@@ -12,6 +12,7 @@
*/
package org.openhab.binding.lcn.internal.subhandler;
+import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.*;
import org.eclipse.jdt.annotation.NonNullByDefault;
@@ -42,21 +43,24 @@ public class LcnModuleVariableSubHandlerTest extends AbstractTestLcnModuleSubHan
@Test
public void testStatusVariable1() {
- l.tryParse("=M000005.A00112345");
+ tryParseAllHandlers("=M000005.A00112345");
verify(handler).updateChannel(LcnChannelGroup.VARIABLE, "1", new DecimalType(12345));
+ verify(handler).updateChannel(any(), any(), any());
}
@Test
public void testStatusVariable12() {
- l.tryParse("=M000005.A01212345");
+ tryParseAllHandlers("=M000005.A01212345");
verify(handler).updateChannel(LcnChannelGroup.VARIABLE, "12", new DecimalType(12345));
+ verify(handler).updateChannel(any(), any(), any());
}
@Test
public void testStatusLegacyVariable3() {
when(info.getLastRequestedVarWithoutTypeInResponse()).thenReturn(Variable.VARIABLE3);
- l.tryParse("=M000005.12345");
+ tryParseAllHandlers("=M000005.12345");
verify(handler).updateChannel(LcnChannelGroup.VARIABLE, "3", new DecimalType(12345));
+ verify(handler).updateChannel(any(), any(), any());
}
@Test
@@ -77,13 +81,15 @@ public class LcnModuleVariableSubHandlerTest extends AbstractTestLcnModuleSubHan
@Test
public void testStatusVariable10SensorDefective() {
- l.tryParse("=M000005.A01032512");
+ tryParseAllHandlers("=M000005.A01032512");
verify(handler).updateChannel(LcnChannelGroup.VARIABLE, "10", new StringType("DEFECTIVE"));
+ verify(handler).updateChannel(any(), any(), any());
}
@Test
public void testStatusVariable8NotConfigured() {
- l.tryParse("=M000005.A00865535");
+ tryParseAllHandlers("=M000005.A00865535");
verify(handler).updateChannel(LcnChannelGroup.VARIABLE, "8", new StringType("Not configured in LCN-PRO"));
+ verify(handler).updateChannel(any(), any(), any());
}
}