diff --git a/bundles/org.openhab.binding.lcn/README.md b/bundles/org.openhab.binding.lcn/README.md
index 15afd6d6b76f0..35fa8c774e6d7 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.
![Illustration of the LCN product family](doc/overview.jpg)
-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 6576cb8be5427..2879316f776f4 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 1cfa8bf9f9493..60299dcc0d078 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 @@
@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 void startRelayTimer(
}
}
+ /**
+ * 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 static void startRelayTimer(ThingActions actions, int relaynumber, double
((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 91c0108a33fe3..13633b0c3b0b1 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 void handleCommand(ChannelUID channelUid, Command command) {
} 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 aa76515462775..6dc16f75d99da 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 void handleCommand(ChannelUID channelUID, Command command) {
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 f3b8f2e537d09..8bc38994bd331 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.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 993437a6ee0ae..da72b52f6def2 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 a495ee93549d4..62bd7b8f2c7b0 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 static String dimOutput(int outputId, double percent, int rampMs) throws
}
}
+ /**
+ * 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 static String controlRelays(LcnDefs.RelayStateModifier[] states) throws L
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 static String setSetpointAbsolute(int number, int value) {
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 static String startRelayTimer(int relayNumber, double duration) throws Lc
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 bd953e6a60a6e..640f2fa11831a 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 void shutdownFinally() {
*/
protected void parseLcnBusDiconnectMessage(String pck) {
if (pck.equals(LcnDefs.LCNCONNSTATE_DISCONNECTED)) {
- connection.getCallback().onOffline("LCN bus not connected to LCN-PCHK/PKE");
+ connection.getCallback().onOffline("LCN-PCHK/VISU not connected to LCN data wire");
nextState(ConnectionStateWaitForLcnBusConnectedAfterDisconnected::new);
}
}
diff --git a/bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/connection/ConnectionStateMachine.java b/bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/connection/ConnectionStateMachine.java
index 071ca459851ef..51a595e89c975 100644
--- a/bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/connection/ConnectionStateMachine.java
+++ b/bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/connection/ConnectionStateMachine.java
@@ -84,7 +84,7 @@ public synchronized void handleConnectionFailed(@Nullable Throwable e) {
*
* @param data the PCK message
*/
- public void onInputReceived(String data) {
+ public synchronized void onInputReceived(String data) {
AbstractConnectionState localState = state;
if (localState != null) {
localState.onPckMessageReceived(data);
diff --git a/bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/connection/ConnectionStateWaitForLcnBusConnected.java b/bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/connection/ConnectionStateWaitForLcnBusConnected.java
index 0f69dbf43b4df..050f24f8c8f10 100644
--- a/bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/connection/ConnectionStateWaitForLcnBusConnected.java
+++ b/bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/connection/ConnectionStateWaitForLcnBusConnected.java
@@ -51,7 +51,7 @@ public void onPckMessageReceived(String data) {
switch (data) {
case LcnDefs.LCNCONNSTATE_DISCONNECTED:
cancelLegacyTimer();
- connection.getCallback().onOffline("LCN bus not connected to LCN-PCHK/PKE");
+ connection.getCallback().onOffline("LCN-PCHK/VISU not connected to LCN data wire");
break;
case LcnDefs.LCNCONNSTATE_CONNECTED:
cancelLegacyTimer();
@@ -61,7 +61,7 @@ public void onPckMessageReceived(String data) {
case LcnDefs.INSUFFICIENT_LICENSES:
cancelLegacyTimer();
handleConnectionFailed(
- new LcnException("LCN-PCHK/PKE has not enough licenses to handle this connection"));
+ new LcnException("LCN-PCHK/VISU has not enough licenses to handle this connection"));
break;
}
}
diff --git a/bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/subhandler/LcnModuleRollershutterRelaySubHandler.java b/bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/subhandler/AbstractLcnModuleRollershutterRelaySubHandler.java
similarity index 71%
rename from bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/subhandler/LcnModuleRollershutterRelaySubHandler.java
rename to bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/subhandler/AbstractLcnModuleRollershutterRelaySubHandler.java
index 4f9db7f848c68..a0763fa6a564d 100644
--- a/bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/subhandler/LcnModuleRollershutterRelaySubHandler.java
+++ b/bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/subhandler/AbstractLcnModuleRollershutterRelaySubHandler.java
@@ -18,6 +18,7 @@
import java.util.regex.Pattern;
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.common.LcnDefs;
@@ -25,6 +26,7 @@
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;
import org.openhab.core.library.types.StopMoveType;
import org.openhab.core.library.types.UpDownType;
@@ -34,8 +36,13 @@
* @author Fabian Wolter - Initial contribution
*/
@NonNullByDefault
-public class LcnModuleRollershutterRelaySubHandler extends AbstractLcnModuleSubHandler {
- public LcnModuleRollershutterRelaySubHandler(LcnModuleHandler handler, ModInfo info) {
+public abstract class AbstractLcnModuleRollershutterRelaySubHandler extends AbstractLcnModuleSubHandler {
+ private static final String POSITION = "P";
+ private static final String ANGLE = "W";
+ private static final Pattern PATTERN = Pattern.compile(LcnBindingConstants.ADDRESS_REGEX + //
+ "(?[" + POSITION + "|" + ANGLE + "])(?\\d)(?\\d{3})");
+
+ public AbstractLcnModuleRollershutterRelaySubHandler(LcnModuleHandler handler, ModInfo info) {
super(handler, info);
}
@@ -68,11 +75,21 @@ public void handleCommandStopMove(StopMoveType command, LcnChannelGroup channelG
@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 89638aac95775..ea7b5e517d4dd 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 @@ private void unsupportedCommand(Command command) {
* @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 0000000000000..2fa8de3a96d3c
--- /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 a87c103c37b03..2c14314418802 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.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 LcnModuleOutputSubHandler(LcnModuleHandler handler, ModInfo info) {
}
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 void handleCommandDimmerOutput(DimmerOutputCommand command, int number) t
}
}
+ @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 0000000000000..ca172ffc3d2f7
--- /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 0000000000000..61dfa61616400
--- /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 0000000000000..3dac5c44c51af
--- /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 a9443bbbc8f31..af7307cb5f9d6 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 21ff3e5980a6e..20e9f64fe62f9 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 57ad336e8d2ef..b36127470f471 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 void testSendKeysD3Make() throws LcnException {
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 3bac04e89e2c2..5443798eb440c 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.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 @@
* @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 void testMove4() throws LcnException {
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 665f6dda4e7bb..54160eea28c54 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 @@
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 fccc7340ebe18..6ca0932ad33c0 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 @@
*/
@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 void testStatusAllClosed() {
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 void testStatusAllOpen() {
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 void testStatus1And7Closed() {
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 26183f60f9297..eb1d0fd307e60 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 @@
*/
@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 8c184019bd8ff..d96a4007107d8 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 void setUp() {
@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 void testStatus() {
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 5e2b99999a169..1607f45e97e1e 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 void testStatusLedOffLogicNot() {
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 void testStatusMixed() {
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 0000000000000..611c4b0cc329d
--- /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 2a8a56ed39971..98cf5d93e9197 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.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 void setUp() {
@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 void testHandleCommandDimmerOutput12Value40() throws LcnException {
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 30bac3228b5eb..bb7bb517d14c0 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.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 void setUp() {
@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 void testStatusAllOff() {
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 void testStatusAllOn() {
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 void testStatusRelay1Relay7On() {
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 0000000000000..7260c099c90b1
--- /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 0000000000000..307ce292c3285
--- /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 0000000000000..ab916af90efbc
--- /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 b765671dcdbdf..1c41b65782fca 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 void testhandleCommandRvar2NegativeLegacy() throws LcnException {
@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 7fea0b1af1957..189975ef88243 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 @@
*/
@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 a83003a9e7c96..ef8ab1dcaec6c 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 void setUp() {
@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 35a3a6e6c3c19..59062efe75aab 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 void setUp() {
@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 void testHandleCommandLegacyTvarNegative() throws LcnException {
@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());
}
}