[lcn] Add shutter positioning/angle, operating hours counters, tunable white, regulator mode, beeping (#13056)

* [lcn] Add shutter positioning/angle, operating hours counters, tunable white, regulator mode, beeping

Also, fix possible race condition during connecting, when the PC coupler is not connected to the LCN data wire.
Replace discontinued LCN-PKE by LCN-VISU.

Signed-off-by: Fabian Wolter <github@fabian-wolter.de>
This commit is contained in:
Fabian Wolter 2022-07-10 21:46:41 +02:00 committed by GitHub
parent 9bd8854e0b
commit 36bd806c28
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
37 changed files with 1268 additions and 126 deletions

View File

@ -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)<br />
*tonality* - The tonality as a String. You need to use quotes. See below.<br />
*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"

View File

@ -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(?<segId>\\d{3})(?<modId>\\d{3})";
public static final String ADDRESS_WITHOUT_PREFIX = "M(?<segId>\\d{3})(?<modId>\\d{3})";
public static final String ADDRESS_REGEX = "[:=%]" + ADDRESS_WITHOUT_PREFIX;
public static final Pattern MEASUREMENT_PATTERN_BEFORE_2013 = Pattern
.compile(LcnBindingConstants.ADDRESS_REGEX + "\\.(?<value>\\d{5})");
/** LCN coding for ACK */
public static final int CODE_ACK = -1;
public static final Collection<String> ALLOWED_BEEP_TONALITIES = Set.of("N", "S", "1", "2", "3", "4", "5", "6",
"7");
}

View File

@ -40,6 +40,8 @@ import org.slf4j.LoggerFactory;
@NonNullByDefault
public class LcnModuleActions implements ThingActions {
private final Logger logger = LoggerFactory.getLogger(LcnModuleActions.class);
private static final int MAX_BEEP_VOLUME = 100;
private static final int MAX_BEEP_COUNT = 50;
private static final int DYN_TEXT_CHUNK_COUNT = 5;
private static final int DYN_TEXT_HEADER_LENGTH = 6;
private static final int DYN_TEXT_CHUNK_LENGTH = 12;
@ -173,6 +175,42 @@ public class LcnModuleActions implements ThingActions {
}
}
/**
* Let the beeper connected to the LCN module beep.
*
* @param volume sound volume in percent. Can be null. Then, the last volume is used.
* @param tonality N=normal, S=special, 1-7 tonalities 1-7. Can be null. Then, normal tonality is used.
* @param count number of beeps. Can be null. Then, number of beeps is one.
*/
@RuleAction(label = "let the module's beeper beep", description = "Lets the beeper connected to the LCN module beep")
public void beep(
@ActionInput(name = "volume", required = false, type = "java.lang.Double", label = "Sound Volume", description = "The sound volume in percent.") @Nullable Double soundVolume,
@ActionInput(name = "tonality", required = false, type = "java.lang.String", label = "Tonality", description = "Tonality (N, S, 1-7)") @Nullable String tonality,
@ActionInput(name = "count", required = false, type = "java.lang.Integer", label = "Count", description = "Number of beeps") @Nullable Integer count) {
try {
if (soundVolume != null) {
if (soundVolume < 0) {
throw new LcnException("Volume cannot be negative: " + soundVolume);
}
getHandler().sendPck(PckGenerator.setBeepVolume(Math.min(soundVolume, MAX_BEEP_VOLUME)));
}
Integer localCount = count;
if (localCount == null) {
localCount = 1;
}
String filteredTonality = LcnBindingConstants.ALLOWED_BEEP_TONALITIES.stream() //
.filter(t -> t.equals(tonality)) //
.findAny() //
.orElse("N");
getHandler().sendPck(PckGenerator.beep(filteredTonality, Math.min(localCount, MAX_BEEP_COUNT)));
} catch (LcnException e) {
logger.warn("Could not send beep command: {}", e.getMessage());
}
}
/** Static alias to support the old DSL rules engine and make the action available there. */
public static void hitKey(ThingActions actions, @Nullable String table, int key, @Nullable String action) {
((LcnModuleActions) actions).hitKey(table, key, action);
@ -193,6 +231,11 @@ public class LcnModuleActions implements ThingActions {
((LcnModuleActions) actions).startRelayTimer(relaynumber, duration);
}
/** Static alias to support the old DSL rules engine and make the action available there. */
public static void beep(ThingActions actions, Double soundVolume, String tonality, Integer count) {
((LcnModuleActions) actions).beep(soundVolume, tonality, count);
}
private LcnModuleHandler getHandler() throws LcnException {
LcnModuleHandler localModuleHandler = moduleHandler;
if (localModuleHandler != null) {

View File

@ -218,7 +218,7 @@ public class LcnModuleHandler extends BaseThingHandler {
} else if (command instanceof PercentType) {
subHandler.handleCommandPercent((PercentType) command, channelGroup, channelUid.getIdWithoutGroup());
} else if (command instanceof StringType) {
subHandler.handleCommandString((StringType) command, number.get());
subHandler.handleCommandString((StringType) command, number.orElse(0));
} else if (command instanceof DecimalType) {
DecimalType decimalType = (DecimalType) command;
DecimalType nativeValue = getConverter(channelUid).onCommandFromItem(decimalType.doubleValue());

View File

@ -65,7 +65,7 @@ public class PckGatewayHandler extends BaseBridgeHandler {
public synchronized void initialize() {
PckGatewayConfiguration localConfig = config = getConfigAs(PckGatewayConfiguration.class);
String errorMessage = "Could not connect to LCN-PCHK/PKE: " + localConfig.getHostname() + ": ";
String errorMessage = "Could not connect to LCN-PCHK/VISU: " + localConfig.getHostname() + ": ";
try {
OutputPortDimMode dimMode;

View File

@ -24,11 +24,14 @@ import org.openhab.binding.lcn.internal.subhandler.LcnModuleHostCommandSubHandle
import org.openhab.binding.lcn.internal.subhandler.LcnModuleKeyLockTableSubHandler;
import org.openhab.binding.lcn.internal.subhandler.LcnModuleLedSubHandler;
import org.openhab.binding.lcn.internal.subhandler.LcnModuleLogicSubHandler;
import org.openhab.binding.lcn.internal.subhandler.LcnModuleOperatingHoursCounterSubHandler;
import org.openhab.binding.lcn.internal.subhandler.LcnModuleOutputSubHandler;
import org.openhab.binding.lcn.internal.subhandler.LcnModuleRelaySubHandler;
import org.openhab.binding.lcn.internal.subhandler.LcnModuleRollershutterOutputSubHandler;
import org.openhab.binding.lcn.internal.subhandler.LcnModuleRollershutterRelaySubHandler;
import org.openhab.binding.lcn.internal.subhandler.LcnModuleRollershutterRelayPositionSubHandler;
import org.openhab.binding.lcn.internal.subhandler.LcnModuleRollershutterRelaySlatAngleSubHandler;
import org.openhab.binding.lcn.internal.subhandler.LcnModuleRvarLockSubHandler;
import org.openhab.binding.lcn.internal.subhandler.LcnModuleRvarModeSubHandler;
import org.openhab.binding.lcn.internal.subhandler.LcnModuleRvarSetpointSubHandler;
import org.openhab.binding.lcn.internal.subhandler.LcnModuleS0CounterSubHandler;
import org.openhab.binding.lcn.internal.subhandler.LcnModuleThresholdSubHandler;
@ -44,12 +47,14 @@ public enum LcnChannelGroup {
OUTPUT(4, LcnModuleOutputSubHandler::new),
ROLLERSHUTTEROUTPUT(1, LcnModuleRollershutterOutputSubHandler::new),
RELAY(8, LcnModuleRelaySubHandler::new),
ROLLERSHUTTERRELAY(4, LcnModuleRollershutterRelaySubHandler::new),
ROLLERSHUTTERRELAY(4, LcnModuleRollershutterRelayPositionSubHandler::new),
ROLLERSHUTTERRELAYSLAT(4, LcnModuleRollershutterRelaySlatAngleSubHandler::new),
LED(12, LcnModuleLedSubHandler::new),
LOGIC(4, LcnModuleLogicSubHandler::new),
BINARYSENSOR(8, LcnModuleBinarySensorSubHandler::new),
VARIABLE(12, LcnModuleVariableSubHandler::new),
RVARSETPOINT(2, LcnModuleRvarSetpointSubHandler::new),
RVARMODE(2, LcnModuleRvarModeSubHandler::new),
RVARLOCK(2, LcnModuleRvarLockSubHandler::new),
THRESHOLDREGISTER1(5, LcnModuleThresholdSubHandler::new),
THRESHOLDREGISTER2(4, LcnModuleThresholdSubHandler::new),
@ -61,6 +66,7 @@ public enum LcnChannelGroup {
KEYLOCKTABLEC(8, LcnModuleKeyLockTableSubHandler::new),
KEYLOCKTABLED(8, LcnModuleKeyLockTableSubHandler::new),
CODE(0, LcnModuleCodeSubHandler::new),
OPERATINGHOURS(0, LcnModuleOperatingHoursCounterSubHandler::new),
HOSTCOMMAND(0, LcnModuleHostCommandSubHandler::new);
private int count;

View File

@ -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?)";
/**

View File

@ -136,6 +136,21 @@ public final class PckGenerator {
}
}
/**
* Generates a command for setting the tunable white mode.
*
* @param mode 0..2
* @return the PCK command (without address header) as text
* @throws LcnException if out of range
*/
public static String setTunableWhiteMode(int mode) throws LcnException {
if (mode < 0 || mode > 2) {
throw new LcnException();
}
return String.format("AW%d", mode);
}
/**
* Generates a dim command for all output-ports.
*
@ -332,6 +347,42 @@ public final class PckGenerator {
return ret.toString();
}
/**
* Generates a command to control the position of roller shutters on relays.
*
* @param motorNumber of the roller shutter (0-based)
* @param percent of the entire roller shutter height
* @return the PCK command (without address header) as text
* @throws LcnException if out of range
*/
public static String controlShutterPosition(int motorNumber, int percent) throws LcnException {
return controlShutter(motorNumber, percent, "JH");
}
/**
* Generates a command to control the slat angle of roller shutters on relays.
*
* @param motorNumber of the roller shutter (0-based)
* @param percent of the slat angle
* @return the PCK command (without address header) as text
* @throws LcnException if out of range
*/
public static String controlShutterSlatAngle(int motorNumber, int percent) throws LcnException {
return controlShutter(motorNumber, percent, "JW");
}
private static String controlShutter(int motorNumber, int percent, String command) throws LcnException {
if (motorNumber < 0 || motorNumber >= 4) {
throw new LcnException("Roller shutter (relay) motor number out of range: " + motorNumber);
}
if (percent < 0 || percent > 100) {
throw new LcnException("Roller shutter (relay) position/angle out of range (percent): " + percent);
}
return String.format("%s%03d%03d", command, percent, 1 << motorNumber);
}
/**
* Generates a binary-sensors status request.
*
@ -365,6 +416,30 @@ public final class PckGenerator {
return String.format("X2%03d%03d%03d", 30, b1, b2);
}
/**
* Generates a command to change the regulator mode.
*
* @param number regulator number 0..1
* @param cooling true=cooling, false=heating
* @return the PCK command (without address header) as text
* @throws LcnException
*/
public static String setRVarMode(int number, boolean cooling) throws LcnException {
String regulator;
switch (number) {
case 0:
regulator = "A";
break;
case 1:
regulator = "B";
break;
default:
throw new LcnException();
}
return "RE" + regulator + "T" + (cooling ? "C" : "H");
}
/**
* Generates a command to change the value of a variable.
*
@ -751,6 +826,41 @@ public final class PckGenerator {
return command.toString();
}
/**
* Generates a command to set the beeping sound volume.
*
* @param volume the sound volume
* @return the PCK command (without address header) as text
* @throws LcnException if out of range
*/
public static String setBeepVolume(double volume) throws LcnException {
if (volume < 0 || volume > 100) {
throw new LcnException();
}
return String.format("PIV%03d", Math.round(volume));
}
/**
* Generates a command to let the beeper connected to the LCN module beep.
*
* @param volume the sound volume
* @return the PCK command (without address header) as text
* @throws LcnException if out of range
*/
public static String beep(String tonality, int count) throws LcnException {
LcnBindingConstants.ALLOWED_BEEP_TONALITIES.stream() //
.filter(t -> t.equals(tonality)) //
.findAny() //
.orElseThrow(LcnException::new);
if (count < 0) {
throw new LcnException();
}
return String.format("PI%s%d", tonality, Math.min(count, 50));
}
/**
* Generates a null command, used for broadcast messages.
*

View File

@ -80,7 +80,7 @@ public abstract class AbstractConnectionState extends AbstractState<ConnectionSt
*/
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);
}
}

View File

@ -84,7 +84,7 @@ public class ConnectionStateMachine extends AbstractStateMachine<ConnectionState
*
* @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);

View File

@ -51,7 +51,7 @@ public class ConnectionStateWaitForLcnBusConnected extends AbstractConnectionSta
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 class ConnectionStateWaitForLcnBusConnected extends AbstractConnectionSta
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;
}
}

View File

@ -18,6 +18,7 @@ import java.util.regex.Matcher;
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.LcnDefs.RelayStateModifier;
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 @@ import org.openhab.core.library.types.UpDownType;
* @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 + //
"(?<type>[" + POSITION + "|" + ANGLE + "])(?<shutterNumber>\\d)(?<percent>\\d{3})");
public AbstractLcnModuleRollershutterRelaySubHandler(LcnModuleHandler handler, ModInfo info) {
super(handler, info);
}
@ -68,11 +75,21 @@ public class LcnModuleRollershutterRelaySubHandler extends AbstractLcnModuleSubH
@Override
public void handleStatusMessage(Matcher matcher) {
// status messages of roller shutters on relays are handled in the relay sub handler
int shutterNumber = Integer.parseInt(matcher.group("shutterNumber")) - 1;
int percent = Integer.parseInt(matcher.group("percent"));
LcnChannelGroup group;
if (POSITION.equals(matcher.group("type"))) {
group = LcnChannelGroup.ROLLERSHUTTERRELAY;
} else {
group = LcnChannelGroup.ROLLERSHUTTERRELAYSLAT;
}
fireUpdate(group, shutterNumber, new PercentType(percent));
}
@Override
public Collection<Pattern> getPckStatusMessagePatterns() {
return Collections.emptyList();
return Collections.singleton(PATTERN);
}
}

View File

@ -13,7 +13,6 @@
package org.openhab.binding.lcn.internal.subhandler;
import java.util.Arrays;
import java.util.Optional;
import java.util.regex.Matcher;
import org.eclipse.jdt.annotation.NonNullByDefault;
@ -121,17 +120,17 @@ public abstract class AbstractLcnModuleSubHandler implements ILcnModuleSubHandle
* @return true, if the message could be processed successfully
*/
public void tryParse(String pck) {
Optional<Matcher> 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());
}
});
}
/**

View File

@ -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>[" + Type.createPattern() + "])(?<number>\\d)(?<durationSec>\\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<Pattern> 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));
}
}

View File

@ -29,6 +29,7 @@ import org.openhab.binding.lcn.internal.connection.ModInfo;
import org.openhab.core.library.types.HSBType;
import org.openhab.core.library.types.OnOffType;
import org.openhab.core.library.types.PercentType;
import org.openhab.core.library.types.StringType;
import org.openhab.core.library.types.UpDownType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -53,8 +54,8 @@ public class LcnModuleOutputSubHandler extends AbstractLcnModuleSubHandler {
}
static {
PERCENT_PATTERN = Pattern.compile(LcnBindingConstants.ADDRESS_REGEX + "A(?<outputId>\\d)(?<percent>\\d+)");
NATIVE_PATTERN = Pattern.compile(LcnBindingConstants.ADDRESS_REGEX + "O(?<outputId>\\d)(?<value>\\d+)");
PERCENT_PATTERN = Pattern.compile(LcnBindingConstants.ADDRESS_REGEX + "A(?<outputId>\\d)(?<percent>\\d{3})");
NATIVE_PATTERN = Pattern.compile(LcnBindingConstants.ADDRESS_REGEX + "O(?<outputId>\\d)(?<value>\\d{3})");
}
@Override
@ -142,6 +143,25 @@ public class LcnModuleOutputSubHandler extends AbstractLcnModuleSubHandler {
}
}
@Override
public void handleCommandString(StringType command, int number) throws LcnException {
int mode = 0;
switch (command.toString()) {
case "DISABLE":
mode = 0;
break;
case "OUTPUT1":
mode = 1;
break;
case "BOTH":
mode = 2;
break;
}
handler.sendPck(PckGenerator.setTunableWhiteMode(mode));
}
@Override
public void handleStatusMessage(Matcher matcher) {
int outputId = Integer.parseInt(matcher.group("outputId")) - 1;

View File

@ -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()));
}
}

View File

@ -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()));
}
}

View File

@ -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<Pattern> getPckStatusMessagePatterns() {
return Collections.emptyList();
}
}

View File

@ -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

View File

@ -5,7 +5,7 @@
<bridge-type id="pckGateway">
<label>LCN-PCHK Gateway</label>
<description>An LCN gateway speaking the PCK language. E.g. LCN-PCHK software or the DIN rail device LCN-PKE.</description>
<description>An LCN gateway speaking the PCK language. E.g. LCN-PCHK software or the DIN rail device LCN-VISU.</description>
<config-description-ref uri="thing-type:lcn:pckGateway"/>
</bridge-type>
@ -24,10 +24,12 @@
<channel-group typeId="leds" id="led"/>
<channel-group typeId="relays" id="relay"/>
<channel-group typeId="rollershutterrelays" id="rollershutterrelay"/>
<channel-group typeId="rollershutterrelayslats" id="rollershutterrelayslat"/>
<channel-group typeId="logics" id="logic"/>
<channel-group typeId="binarysensors" id="binarysensor"/>
<channel-group typeId="variables" id="variable"/>
<channel-group typeId="rvarsetpoints" id="rvarsetpoint"/>
<channel-group typeId="rvarmodes" id="rvarmode"/>
<channel-group typeId="rvarlocks" id="rvarlock"/>
<channel-group typeId="thresholdregisters1" id="thresholdregister1"/>
<channel-group typeId="thresholdregisters2" id="thresholdregister2"/>
@ -39,6 +41,7 @@
<channel-group typeId="keyslocktablec" id="keylocktablec"/>
<channel-group typeId="keyslocktabled" id="keylocktabled"/>
<channel-group typeId="codes" id="code"/>
<channel-group typeId="operatinghourscounters" id="operatinghourscounter"/>
<channel-group typeId="hostcommands" id="hostcommand"/>
</channel-groups>
<properties>
@ -91,6 +94,19 @@
<autoUpdatePolicy>veto</autoUpdatePolicy>
</channel-type>
<channel-type id="tunablewhite">
<item-type>String</item-type>
<label>Tunable White Mode</label>
<state>
<options>
<option value="DISABLE">Tunable White Disabled</option>
<option value="OUTPUT1">Control Output 1 (Output 2 is auto)</option>
<option value="BOTH">Output 1 Brightness/Output 2 Temperature</option>
</options>
</state>
<autoUpdatePolicy>recommend</autoUpdatePolicy><!-- There's no status message in LCN -->
</channel-type>
<channel-group-type id="outputs">
<label>Dimmer Outputs</label>
<channels>
@ -109,6 +125,7 @@
<channel typeId="color" id="color">
<label>RGB Color Control (Outputs 1-3)</label>
</channel>
<channel typeId="tunablewhite" id="tunablewhite"/>
</channels>
</channel-group-type>
@ -151,7 +168,7 @@
<channel-type id="rollershutter">
<item-type>Rollershutter</item-type>
<label>Roller Shutter</label>
<autoUpdatePolicy>veto</autoUpdatePolicy>
<autoUpdatePolicy>veto</autoUpdatePolicy><!-- The position messages come as the shutter moves -->
<config-description>
<parameter name="invertUpDown" type="boolean">
<label>Invert Up/Down</label>
@ -163,19 +180,37 @@
</channel-type>
<channel-group-type id="rollershutterrelays">
<label>Roller Shutter (Relay)</label>
<label>Shutter (Relay)</label>
<channels>
<channel typeId="rollershutter" id="1">
<label>Shutter 1-2</label>
<label>Position 1-2</label>
</channel>
<channel typeId="rollershutter" id="2">
<label>Shutter 3-4</label>
<label>Position 3-4</label>
</channel>
<channel typeId="rollershutter" id="3">
<label>Shutter 5-6</label>
<label>Position 5-6</label>
</channel>
<channel typeId="rollershutter" id="4">
<label>Shutter 7-8</label>
<label>Position 7-8</label>
</channel>
</channels>
</channel-group-type>
<channel-group-type id="rollershutterrelayslats">
<label>Shutter Slat Angle (Relay)</label>
<channels>
<channel typeId="rollershutter" id="1">
<label>Slat Angle 1-2</label>
</channel>
<channel typeId="rollershutter" id="2">
<label>Slat Angle 3-4</label>
</channel>
<channel typeId="rollershutter" id="3">
<label>Slat Angle 5-6</label>
</channel>
<channel typeId="rollershutter" id="4">
<label>Slat Angle 7-8</label>
</channel>
</channels>
</channel-group-type>
@ -378,6 +413,30 @@
</channels>
</channel-group-type>
<channel-type id="rvarmode" advanced="true">
<item-type>String</item-type>
<label>RVar Heating/Cooling</label>
<state>
<options>
<option value="HEATING">Heating</option>
<option value="COOLING">Cooling</option>
</options>
</state>
<autoUpdatePolicy>recommend</autoUpdatePolicy><!-- There's no status message in LCN -->
</channel-type>
<channel-group-type id="rvarmodes">
<label>RVar Heating/Cooling</label>
<channels>
<channel typeId="rvarmode" id="1">
<label>R1Var Mode</label>
</channel>
<channel typeId="rvarmode" id="2">
<label>R2Var Mode</label>
</channel>
</channels>
</channel-group-type>
<channel-type id="rvarlock" advanced="true">
<item-type>Switch</item-type>
<label>RVar Lock State</label>
@ -664,6 +723,90 @@
</channels>
</channel-group-type>
<channel-group-type id="operatinghourscounters">
<label>Operating Hours Counters</label>
<channels>
<channel typeId="operatinghourscounter" id="output1">
<label>Output 1</label>
</channel>
<channel typeId="operatinghourscounter" id="output2">
<label>Output 2</label>
</channel>
<channel typeId="operatinghourscounter" id="output3">
<label>Output 3</label>
</channel>
<channel typeId="operatinghourscounter" id="output4">
<label>Output 4</label>
</channel>
<channel typeId="operatinghourscounter" id="relay1">
<label>Relay 1</label>
</channel>
<channel typeId="operatinghourscounter" id="relay2">
<label>Relay 2</label>
</channel>
<channel typeId="operatinghourscounter" id="relay3">
<label>Relay 3</label>
</channel>
<channel typeId="operatinghourscounter" id="relay4">
<label>Relay 4</label>
</channel>
<channel typeId="operatinghourscounter" id="relay5">
<label>Relay 5</label>
</channel>
<channel typeId="operatinghourscounter" id="relay6">
<label>Relay 6</label>
</channel>
<channel typeId="operatinghourscounter" id="relay7">
<label>Relay 7</label>
</channel>
<channel typeId="operatinghourscounter" id="relay8">
<label>Relay 8</label>
</channel>
<channel typeId="operatinghourscounter" id="binarysensor1">
<label>Binary Sensor 1</label>
</channel>
<channel typeId="operatinghourscounter" id="binarysensor2">
<label>Binary Sensor 2</label>
</channel>
<channel typeId="operatinghourscounter" id="binarysensor3">
<label>Binary Sensor 3</label>
</channel>
<channel typeId="operatinghourscounter" id="binarysensor4">
<label>Binary Sensor 4</label>
</channel>
<channel typeId="operatinghourscounter" id="binarysensor5">
<label>Binary Sensor 5</label>
</channel>
<channel typeId="operatinghourscounter" id="binarysensor6">
<label>Binary Sensor 6</label>
</channel>
<channel typeId="operatinghourscounter" id="binarysensor7">
<label>Binary Sensor 7</label>
</channel>
<channel typeId="operatinghourscounter" id="binarysensor8">
<label>Binary Sensor 8</label>
</channel>
<channel typeId="operatinghourscounter" id="outputrelativework1">
<label>Output 1 Relative Work</label>
</channel>
<channel typeId="operatinghourscounter" id="outputrelativework2">
<label>Output 2 Relative Work</label>
</channel>
<channel typeId="operatinghourscounter" id="outputrelativework3">
<label>Output 3 Relative Work</label>
</channel>
<channel typeId="operatinghourscounter" id="outputrelativework4">
<label>Output 4 Relative Work</label>
</channel>
</channels>
</channel-group-type>
<channel-type id="operatinghourscounter" advanced="true">
<item-type>Number:Time</item-type>
<label>Operating Hours Counter</label>
<state readOnly="true"/>
</channel-type>
<channel-type id="sendKeys" advanced="true">
<kind>trigger</kind>
<label>Send Keys</label>

View File

@ -200,4 +200,44 @@ public class ModuleActionsTest {
verify(handler).sendPck("TS---L00100000");
}
@Test
public void testBeepNull() throws LcnException {
a.beep(null, null, null);
verify(handler).sendPck("PIN1");
verify(handler, times(1)).sendPck(anyString());
}
@Test
public void testBeepSpecial() throws LcnException {
a.beep(null, "S", 5);
verify(handler).sendPck("PIS5");
verify(handler, times(1)).sendPck(anyString());
}
@Test
public void testBeepVolume() throws LcnException {
a.beep(50d, "3", 5);
verify(handler).sendPck("PIV050");
verify(handler).sendPck("PI35");
verify(handler, times(2)).sendPck(anyString());
}
@Test
public void testBeepInvalidVolume() throws LcnException {
a.beep(-1d, "3", 5);
verify(handler, times(0)).sendPck(anyString());
}
@Test
public void testBeepInvalidTonality() throws LcnException {
a.beep(null, "X", 5);
verify(handler).sendPck("PIN5");
verify(handler, times(1)).sendPck(anyString());
}
}

View File

@ -12,6 +12,7 @@
*/
package org.openhab.binding.lcn.internal.subhandler;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.verify;
import org.eclipse.jdt.annotation.NonNullByDefault;
@ -19,6 +20,7 @@ import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.openhab.binding.lcn.internal.common.LcnChannelGroup;
import org.openhab.binding.lcn.internal.common.LcnException;
import org.openhab.core.library.types.PercentType;
import org.openhab.core.library.types.StopMoveType;
import org.openhab.core.library.types.UpDownType;
@ -28,15 +30,16 @@ import org.openhab.core.library.types.UpDownType;
* @author Fabian Wolter - Initial contribution
*/
@NonNullByDefault
public class LcnModuleRollershutterRelaySubHandlerTest extends AbstractTestLcnModuleSubHandler {
private @NonNullByDefault({}) LcnModuleRollershutterRelaySubHandler l;
public class AbstractLcnModuleRollershutterRelaySubHandlerTest extends AbstractTestLcnModuleSubHandler {
private @NonNullByDefault({}) AbstractLcnModuleRollershutterRelaySubHandler l;
@Override
@BeforeEach
public void setUp() {
super.setUp();
l = new LcnModuleRollershutterRelaySubHandler(handler, info);
l = new AbstractLcnModuleRollershutterRelaySubHandler(handler, info) {
};
}
@Test
@ -98,4 +101,32 @@ public class LcnModuleRollershutterRelaySubHandlerTest extends AbstractTestLcnMo
l.handleCommandStopMove(StopMoveType.MOVE, LcnChannelGroup.ROLLERSHUTTERRELAY, 3);
verify(handler).sendPck("R8------1-");
}
@Test
public void testShutter1Percent0Position() {
tryParseAllHandlers(":M000005P1000");
verify(handler).updateChannel(LcnChannelGroup.ROLLERSHUTTERRELAY, "1", new PercentType(0));
verify(handler).updateChannel(any(), any(), any());
}
@Test
public void testShutter4Percent100Position() {
tryParseAllHandlers(":M000005P4100");
verify(handler).updateChannel(LcnChannelGroup.ROLLERSHUTTERRELAY, "4", new PercentType(100));
verify(handler).updateChannel(any(), any(), any());
}
@Test
public void testShutter1Percent0Angle() {
tryParseAllHandlers(":M000005W1000");
verify(handler).updateChannel(LcnChannelGroup.ROLLERSHUTTERRELAYSLAT, "1", new PercentType(0));
verify(handler).updateChannel(any(), any(), any());
}
@Test
public void testShutter4Percent100Angle() {
tryParseAllHandlers(":M000005W4100");
verify(handler).updateChannel(LcnChannelGroup.ROLLERSHUTTERRELAYSLAT, "4", new PercentType(100));
verify(handler).updateChannel(any(), any(), any());
}
}

View File

@ -14,6 +14,9 @@ package org.openhab.binding.lcn.internal.subhandler;
import static org.mockito.Mockito.when;
import java.util.ArrayList;
import java.util.Collection;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
@ -35,8 +38,35 @@ public class AbstractTestLcnModuleSubHandler {
protected @Mock @NonNullByDefault({}) LcnModuleHandler handler;
protected @Mock @NonNullByDefault({}) ModInfo info;
private @NonNullByDefault({}) Collection<AbstractLcnModuleSubHandler> 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));
}
}

View File

@ -12,7 +12,8 @@
*/
package org.openhab.binding.lcn.internal.subhandler;
import static org.mockito.Mockito.verify;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.*;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.junit.jupiter.api.BeforeEach;
@ -27,19 +28,15 @@ import org.openhab.core.library.types.OpenClosedType;
*/
@NonNullByDefault
public class LcnModuleBinarySensorSubHandlerTest extends AbstractTestLcnModuleSubHandler {
private @NonNullByDefault({}) LcnModuleBinarySensorSubHandler l;
@Override
@BeforeEach
public void setUp() {
super.setUp();
l = new LcnModuleBinarySensorSubHandler(handler, info);
}
@Test
public void testStatusAllClosed() {
l.tryParse("=M000005Bx000");
tryParseAllHandlers("=M000005Bx000");
verify(handler).updateChannel(LcnChannelGroup.BINARYSENSOR, "1", OpenClosedType.CLOSED);
verify(handler).updateChannel(LcnChannelGroup.BINARYSENSOR, "2", OpenClosedType.CLOSED);
verify(handler).updateChannel(LcnChannelGroup.BINARYSENSOR, "3", OpenClosedType.CLOSED);
@ -48,11 +45,12 @@ public class LcnModuleBinarySensorSubHandlerTest extends AbstractTestLcnModuleSu
verify(handler).updateChannel(LcnChannelGroup.BINARYSENSOR, "6", OpenClosedType.CLOSED);
verify(handler).updateChannel(LcnChannelGroup.BINARYSENSOR, "7", OpenClosedType.CLOSED);
verify(handler).updateChannel(LcnChannelGroup.BINARYSENSOR, "8", OpenClosedType.CLOSED);
verify(handler, times(8)).updateChannel(any(), any(), any());
}
@Test
public void testStatusAllOpen() {
l.tryParse("=M000005Bx255");
tryParseAllHandlers("=M000005Bx255");
verify(handler).updateChannel(LcnChannelGroup.BINARYSENSOR, "1", OpenClosedType.OPEN);
verify(handler).updateChannel(LcnChannelGroup.BINARYSENSOR, "2", OpenClosedType.OPEN);
verify(handler).updateChannel(LcnChannelGroup.BINARYSENSOR, "3", OpenClosedType.OPEN);
@ -60,11 +58,12 @@ public class LcnModuleBinarySensorSubHandlerTest extends AbstractTestLcnModuleSu
verify(handler).updateChannel(LcnChannelGroup.BINARYSENSOR, "6", OpenClosedType.OPEN);
verify(handler).updateChannel(LcnChannelGroup.BINARYSENSOR, "7", OpenClosedType.OPEN);
verify(handler).updateChannel(LcnChannelGroup.BINARYSENSOR, "8", OpenClosedType.OPEN);
verify(handler, times(8)).updateChannel(any(), any(), any());
}
@Test
public void testStatus1And7Closed() {
l.tryParse("=M000005Bx065");
tryParseAllHandlers("=M000005Bx065");
verify(handler).updateChannel(LcnChannelGroup.BINARYSENSOR, "1", OpenClosedType.OPEN);
verify(handler).updateChannel(LcnChannelGroup.BINARYSENSOR, "2", OpenClosedType.CLOSED);
verify(handler).updateChannel(LcnChannelGroup.BINARYSENSOR, "3", OpenClosedType.CLOSED);
@ -73,5 +72,6 @@ public class LcnModuleBinarySensorSubHandlerTest extends AbstractTestLcnModuleSu
verify(handler).updateChannel(LcnChannelGroup.BINARYSENSOR, "6", OpenClosedType.CLOSED);
verify(handler).updateChannel(LcnChannelGroup.BINARYSENSOR, "7", OpenClosedType.OPEN);
verify(handler).updateChannel(LcnChannelGroup.BINARYSENSOR, "8", OpenClosedType.CLOSED);
verify(handler, times(8)).updateChannel(any(), any(), any());
}
}

View File

@ -12,7 +12,8 @@
*/
package org.openhab.binding.lcn.internal.subhandler;
import static org.mockito.Mockito.verify;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.*;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.junit.jupiter.api.BeforeEach;
@ -26,48 +27,49 @@ import org.openhab.binding.lcn.internal.common.LcnChannelGroup;
*/
@NonNullByDefault
public class LcnModuleHostCommandSubHandlerTest extends AbstractTestLcnModuleSubHandler {
private @NonNullByDefault({}) LcnModuleHostCommandSubHandler subHandler;
@Override
@BeforeEach
public void setUp() {
super.setUp();
subHandler = new LcnModuleHostCommandSubHandler(handler, info);
}
@Test
public void testA1Hit() {
subHandler.tryParse("+M004000005.STH065001");
tryParseAllHandlers("+M004000005.STH065001");
verify(handler).triggerChannel(LcnChannelGroup.HOSTCOMMAND, "sendKeys", "A1:HIT");
verify(handler).triggerChannel(any(), any(), any());
}
@Test
public void testA1Make() {
subHandler.tryParse("+M004000005.STH066001");
tryParseAllHandlers("+M004000005.STH066001");
verify(handler).triggerChannel(LcnChannelGroup.HOSTCOMMAND, "sendKeys", "A1:MAKE");
verify(handler).triggerChannel(any(), any(), any());
}
@Test
public void testC8Break() {
subHandler.tryParse("+M004000005.STH112128");
tryParseAllHandlers("+M004000005.STH112128");
verify(handler).triggerChannel(LcnChannelGroup.HOSTCOMMAND, "sendKeys", "C8:BREAK");
verify(handler).triggerChannel(any(), any(), any());
}
@Test
public void testC1Hit() {
subHandler.tryParse("+M004000005.STH080001");
tryParseAllHandlers("+M004000005.STH080001");
verify(handler).triggerChannel(LcnChannelGroup.HOSTCOMMAND, "sendKeys", "C1:HIT");
verify(handler).triggerChannel(any(), any(), any());
}
@Test
public void testMultiple() {
subHandler.tryParse("+M004000005.STH121034");
tryParseAllHandlers("+M004000005.STH121034");
verify(handler).triggerChannel(LcnChannelGroup.HOSTCOMMAND, "sendKeys", "A2:HIT");
verify(handler).triggerChannel(LcnChannelGroup.HOSTCOMMAND, "sendKeys", "A6:HIT");
verify(handler).triggerChannel(LcnChannelGroup.HOSTCOMMAND, "sendKeys", "B2:MAKE");
verify(handler).triggerChannel(LcnChannelGroup.HOSTCOMMAND, "sendKeys", "B6:MAKE");
verify(handler).triggerChannel(LcnChannelGroup.HOSTCOMMAND, "sendKeys", "C2:BREAK");
verify(handler).triggerChannel(LcnChannelGroup.HOSTCOMMAND, "sendKeys", "C6:BREAK");
verify(handler, times(6)).triggerChannel(any(), any(), any());
}
}

View File

@ -12,7 +12,8 @@
*/
package org.openhab.binding.lcn.internal.subhandler;
import static org.mockito.Mockito.verify;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.*;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.junit.jupiter.api.BeforeEach;
@ -40,7 +41,7 @@ public class LcnModuleKeyLockTableSubHandlerTest extends AbstractTestLcnModuleSu
@Test
public void testStatus() {
l.tryParse("=M000005.TX098036000255");
tryParseAllHandlers("=M000005.TX098036000255");
verify(handler).updateChannel(LcnChannelGroup.KEYLOCKTABLEA, "1", OnOffType.OFF);
verify(handler).updateChannel(LcnChannelGroup.KEYLOCKTABLEA, "2", OnOffType.ON);
verify(handler).updateChannel(LcnChannelGroup.KEYLOCKTABLEA, "3", OnOffType.OFF);
@ -73,6 +74,7 @@ public class LcnModuleKeyLockTableSubHandlerTest extends AbstractTestLcnModuleSu
verify(handler).updateChannel(LcnChannelGroup.KEYLOCKTABLED, "6", OnOffType.ON);
verify(handler).updateChannel(LcnChannelGroup.KEYLOCKTABLED, "7", OnOffType.ON);
verify(handler).updateChannel(LcnChannelGroup.KEYLOCKTABLED, "8", OnOffType.ON);
verify(handler, times(32)).updateChannel(any(), any(), any());
}
@Test

View File

@ -12,7 +12,8 @@
*/
package org.openhab.binding.lcn.internal.subhandler;
import static org.mockito.Mockito.verify;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.*;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.junit.jupiter.api.BeforeEach;
@ -34,19 +35,16 @@ public class LcnModuleLogicSubHandlerTest extends AbstractTestLcnModuleSubHandle
private static final StringType NOT = new StringType("NOT");
private static final StringType OR = new StringType("OR");
private static final StringType AND = new StringType("AND");
private @NonNullByDefault({}) LcnModuleLogicSubHandler l;
@Override
@BeforeEach
public void setUp() {
super.setUp();
l = new LcnModuleLogicSubHandler(handler, info);
}
@Test
public void testStatusLedOffLogicNot() {
l.tryParse("=M000005.TLAAAAAAAAAAAANNNN");
tryParseAllHandlers("=M000005.TLAAAAAAAAAAAANNNN");
verify(handler).updateChannel(LcnChannelGroup.LED, "1", OFF);
verify(handler).updateChannel(LcnChannelGroup.LED, "2", OFF);
verify(handler).updateChannel(LcnChannelGroup.LED, "3", OFF);
@ -63,11 +61,12 @@ public class LcnModuleLogicSubHandlerTest extends AbstractTestLcnModuleSubHandle
verify(handler).updateChannel(LcnChannelGroup.LOGIC, "2", NOT);
verify(handler).updateChannel(LcnChannelGroup.LOGIC, "3", NOT);
verify(handler).updateChannel(LcnChannelGroup.LOGIC, "4", NOT);
verify(handler, times(16)).updateChannel(any(), any(), any());
}
@Test
public void testStatusMixed() {
l.tryParse("=M000005.TLAEBFAAAAAAAFNVNT");
tryParseAllHandlers("=M000005.TLAEBFAAAAAAAFNVNT");
verify(handler).updateChannel(LcnChannelGroup.LED, "1", OFF);
verify(handler).updateChannel(LcnChannelGroup.LED, "2", ON);
verify(handler).updateChannel(LcnChannelGroup.LED, "3", BLINK);
@ -84,23 +83,27 @@ public class LcnModuleLogicSubHandlerTest extends AbstractTestLcnModuleSubHandle
verify(handler).updateChannel(LcnChannelGroup.LOGIC, "2", AND);
verify(handler).updateChannel(LcnChannelGroup.LOGIC, "3", NOT);
verify(handler).updateChannel(LcnChannelGroup.LOGIC, "4", OR);
verify(handler, times(16)).updateChannel(any(), any(), any());
}
@Test
public void testStatusSingleLogic1Not() {
l.tryParse("=M000005S1000");
tryParseAllHandlers("=M000005S1000");
verify(handler).updateChannel(LcnChannelGroup.LOGIC, "1", NOT);
verify(handler).updateChannel(any(), any(), any());
}
@Test
public void testStatusSingleLogic4Or() {
l.tryParse("=M000005S4025");
tryParseAllHandlers("=M000005S4025");
verify(handler).updateChannel(LcnChannelGroup.LOGIC, "4", OR);
verify(handler).updateChannel(any(), any(), any());
}
@Test
public void testStatusSingleLogic3And() {
l.tryParse("=M000005S3050");
tryParseAllHandlers("=M000005S3050");
verify(handler).updateChannel(LcnChannelGroup.LOGIC, "3", AND);
verify(handler).updateChannel(any(), any(), any());
}
}

View File

@ -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());
}
}

View File

@ -12,7 +12,8 @@
*/
package org.openhab.binding.lcn.internal.subhandler;
import static org.mockito.Mockito.verify;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.*;
import java.math.BigDecimal;
@ -25,6 +26,8 @@ import org.openhab.binding.lcn.internal.common.LcnDefs;
import org.openhab.binding.lcn.internal.common.LcnException;
import org.openhab.core.library.types.OnOffType;
import org.openhab.core.library.types.PercentType;
import org.openhab.core.library.types.StringType;
import org.openhab.core.library.types.UpDownType;
/**
* Test class.
@ -45,62 +48,78 @@ public class LcnModuleOutputSubHandlerTest extends AbstractTestLcnModuleSubHandl
@Test
public void testStatusOutput1OffPercent() {
l.tryParse("=M000005A1000");
tryParseAllHandlers(":M000005A1000");
verify(handler).updateChannel(LcnChannelGroup.OUTPUT, "1", new PercentType(0));
verify(handler).updateChannel(any(), any(), any());
}
@Test
public void testStatusOutput2OffPercent() {
l.tryParse("=M000005A2000");
tryParseAllHandlers(":M000005A2000");
verify(handler).updateChannel(LcnChannelGroup.OUTPUT, "2", new PercentType(0));
verify(handler).updateChannel(any(), any(), any());
}
@Test
public void testStatusOutput1OffNative() {
l.tryParse("=M000005O1000");
tryParseAllHandlers(":M000005O1000");
verify(handler).updateChannel(LcnChannelGroup.OUTPUT, "1", new PercentType(0));
verify(handler).updateChannel(any(), any(), any());
}
@Test
public void testStatusOutput2OffNative() {
l.tryParse("=M000005O2000");
tryParseAllHandlers(":M000005O2000");
verify(handler).updateChannel(LcnChannelGroup.OUTPUT, "2", new PercentType(0));
verify(handler).updateChannel(any(), any(), any());
}
@Test
public void testStatusOutput1OnPercent() {
l.tryParse("=M000005A1100");
tryParseAllHandlers(":M000005A1100");
verify(handler).updateChannel(LcnChannelGroup.OUTPUT, "1", new PercentType(100));
verify(handler).updateChannel(LcnChannelGroup.ROLLERSHUTTEROUTPUT, "1", UpDownType.UP);
verify(handler, times(2)).updateChannel(any(), any(), any());
}
@Test
public void testStatusOutput2OnPercent() {
l.tryParse("=M000005A2100");
tryParseAllHandlers(":M000005A2100");
verify(handler).updateChannel(LcnChannelGroup.OUTPUT, "2", new PercentType(100));
verify(handler).updateChannel(LcnChannelGroup.ROLLERSHUTTEROUTPUT, "1", UpDownType.DOWN);
verify(handler, times(2)).updateChannel(any(), any(), any());
}
@Test
public void testStatusOutput1OnNative() {
l.tryParse("=M000005O1200");
tryParseAllHandlers(":M000005O1200");
verify(handler).updateChannel(LcnChannelGroup.OUTPUT, "1", new PercentType(100));
verify(handler).updateChannel(LcnChannelGroup.ROLLERSHUTTEROUTPUT, "1", UpDownType.UP);
verify(handler, times(2)).updateChannel(any(), any(), any());
}
@Test
public void testStatusOutput2OnNative() {
l.tryParse("=M000005O2200");
tryParseAllHandlers(":M000005O2200");
verify(handler).updateChannel(LcnChannelGroup.OUTPUT, "2", new PercentType(100));
verify(handler).updateChannel(LcnChannelGroup.ROLLERSHUTTEROUTPUT, "1", UpDownType.DOWN);
verify(handler, times(2)).updateChannel(any(), any(), any());
}
@Test
public void testStatusOutput2On50Percent() {
l.tryParse("=M000005A2050");
tryParseAllHandlers(":M000005A2050");
verify(handler).updateChannel(LcnChannelGroup.OUTPUT, "2", new PercentType(50));
verify(handler).updateChannel(LcnChannelGroup.ROLLERSHUTTEROUTPUT, "1", UpDownType.DOWN);
verify(handler, times(2)).updateChannel(any(), any(), any());
}
@Test
public void testStatusOutput1On50Native() {
l.tryParse("=M000005O1100");
tryParseAllHandlers(":M000005O1100");
verify(handler).updateChannel(LcnChannelGroup.OUTPUT, "1", new PercentType(50));
verify(handler).updateChannel(LcnChannelGroup.ROLLERSHUTTEROUTPUT, "1", UpDownType.UP);
verify(handler, times(2)).updateChannel(any(), any(), any());
}
@Test
@ -195,4 +214,22 @@ public class LcnModuleOutputSubHandlerTest extends AbstractTestLcnModuleSubHandl
l.handleCommandDimmerOutput(new DimmerOutputCommand(BigDecimal.valueOf(40), false, true, 0), 0);
verify(handler).sendPck("AY040040");
}
@Test
public void testHandleCommandTuneableWhite0() throws LcnException {
l.handleCommandString(new StringType("DISABLE"), 0);
verify(handler).sendPck("AW0");
}
@Test
public void testHandleCommandTuneableWhite1() throws LcnException {
l.handleCommandString(new StringType("OUTPUT1"), 0);
verify(handler).sendPck("AW1");
}
@Test
public void testHandleCommandTuneableWhite2() throws LcnException {
l.handleCommandString(new StringType("BOTH"), 0);
verify(handler).sendPck("AW2");
}
}

View File

@ -12,7 +12,8 @@
*/
package org.openhab.binding.lcn.internal.subhandler;
import static org.mockito.Mockito.verify;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.*;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.junit.jupiter.api.BeforeEach;
@ -21,6 +22,7 @@ import org.openhab.binding.lcn.internal.common.LcnChannelGroup;
import org.openhab.binding.lcn.internal.common.LcnException;
import org.openhab.core.library.types.OnOffType;
import org.openhab.core.library.types.PercentType;
import org.openhab.core.library.types.UpDownType;
/**
* Test class.
@ -41,7 +43,7 @@ public class LcnModuleRelaySubHandlerTest extends AbstractTestLcnModuleSubHandle
@Test
public void testStatusAllOff() {
l.tryParse("=M000005Rx000");
tryParseAllHandlers("=M000005Rx000");
verify(handler).updateChannel(LcnChannelGroup.RELAY, "1", OnOffType.OFF);
verify(handler).updateChannel(LcnChannelGroup.RELAY, "2", OnOffType.OFF);
verify(handler).updateChannel(LcnChannelGroup.RELAY, "3", OnOffType.OFF);
@ -50,11 +52,16 @@ public class LcnModuleRelaySubHandlerTest extends AbstractTestLcnModuleSubHandle
verify(handler).updateChannel(LcnChannelGroup.RELAY, "6", OnOffType.OFF);
verify(handler).updateChannel(LcnChannelGroup.RELAY, "7", OnOffType.OFF);
verify(handler).updateChannel(LcnChannelGroup.RELAY, "8", OnOffType.OFF);
verify(handler).updateChannel(LcnChannelGroup.ROLLERSHUTTERRELAY, "1", UpDownType.UP);
verify(handler).updateChannel(LcnChannelGroup.ROLLERSHUTTERRELAY, "2", UpDownType.UP);
verify(handler).updateChannel(LcnChannelGroup.ROLLERSHUTTERRELAY, "3", UpDownType.UP);
verify(handler).updateChannel(LcnChannelGroup.ROLLERSHUTTERRELAY, "4", UpDownType.UP);
verify(handler, times(12)).updateChannel(any(), any(), any());
}
@Test
public void testStatusAllOn() {
l.tryParse("=M000005Rx255");
tryParseAllHandlers("=M000005Rx255");
verify(handler).updateChannel(LcnChannelGroup.RELAY, "1", OnOffType.ON);
verify(handler).updateChannel(LcnChannelGroup.RELAY, "2", OnOffType.ON);
verify(handler).updateChannel(LcnChannelGroup.RELAY, "3", OnOffType.ON);
@ -62,11 +69,16 @@ public class LcnModuleRelaySubHandlerTest extends AbstractTestLcnModuleSubHandle
verify(handler).updateChannel(LcnChannelGroup.RELAY, "6", OnOffType.ON);
verify(handler).updateChannel(LcnChannelGroup.RELAY, "7", OnOffType.ON);
verify(handler).updateChannel(LcnChannelGroup.RELAY, "8", OnOffType.ON);
verify(handler).updateChannel(LcnChannelGroup.ROLLERSHUTTERRELAY, "1", UpDownType.DOWN);
verify(handler).updateChannel(LcnChannelGroup.ROLLERSHUTTERRELAY, "2", UpDownType.DOWN);
verify(handler).updateChannel(LcnChannelGroup.ROLLERSHUTTERRELAY, "3", UpDownType.DOWN);
verify(handler).updateChannel(LcnChannelGroup.ROLLERSHUTTERRELAY, "4", UpDownType.DOWN);
verify(handler, times(12)).updateChannel(any(), any(), any());
}
@Test
public void testStatusRelay1Relay7On() {
l.tryParse("=M000005Rx065");
tryParseAllHandlers("=M000005Rx065");
verify(handler).updateChannel(LcnChannelGroup.RELAY, "1", OnOffType.ON);
verify(handler).updateChannel(LcnChannelGroup.RELAY, "2", OnOffType.OFF);
verify(handler).updateChannel(LcnChannelGroup.RELAY, "3", OnOffType.OFF);
@ -75,6 +87,11 @@ public class LcnModuleRelaySubHandlerTest extends AbstractTestLcnModuleSubHandle
verify(handler).updateChannel(LcnChannelGroup.RELAY, "6", OnOffType.OFF);
verify(handler).updateChannel(LcnChannelGroup.RELAY, "7", OnOffType.ON);
verify(handler).updateChannel(LcnChannelGroup.RELAY, "8", OnOffType.OFF);
verify(handler).updateChannel(LcnChannelGroup.ROLLERSHUTTERRELAY, "1", UpDownType.UP);
verify(handler).updateChannel(LcnChannelGroup.ROLLERSHUTTERRELAY, "2", UpDownType.UP);
verify(handler).updateChannel(LcnChannelGroup.ROLLERSHUTTERRELAY, "3", UpDownType.UP);
verify(handler).updateChannel(LcnChannelGroup.ROLLERSHUTTERRELAY, "4", UpDownType.UP);
verify(handler, times(12)).updateChannel(any(), any(), any());
}
@Test

View File

@ -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);
});
}
}

View File

@ -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");
}
}

View File

@ -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");
}
}

View File

@ -12,6 +12,7 @@
*/
package org.openhab.binding.lcn.internal.subhandler;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.*;
import org.eclipse.jdt.annotation.NonNullByDefault;
@ -103,36 +104,41 @@ public class LcnModuleRvarSetpointSubHandlerTest extends AbstractTestLcnModuleSu
@Test
public void testRvar1() {
l.tryParse("=M000005.S11234");
tryParseAllHandlers("=M000005.S11234");
verify(handler).updateChannel(LcnChannelGroup.RVARSETPOINT, "1", new DecimalType(1234));
verify(handler).updateChannel(LcnChannelGroup.RVARLOCK, "1", OnOffType.OFF);
verify(handler, times(2)).updateChannel(any(), any(), any());
}
@Test
public void testRvar2() {
l.tryParse("=M000005.S21234");
tryParseAllHandlers("=M000005.S21234");
verify(handler).updateChannel(LcnChannelGroup.RVARSETPOINT, "2", new DecimalType(1234));
verify(handler).updateChannel(LcnChannelGroup.RVARLOCK, "2", OnOffType.OFF);
verify(handler, times(2)).updateChannel(any(), any(), any());
}
@Test
public void testRvar1SensorDefective() {
l.tryParse("=M000005.S132512");
tryParseAllHandlers("=M000005.S132512");
verify(handler).updateChannel(LcnChannelGroup.RVARSETPOINT, "1", new StringType("DEFECTIVE"));
verify(handler).updateChannel(LcnChannelGroup.RVARLOCK, "1", OnOffType.OFF);
verify(handler, times(2)).updateChannel(any(), any(), any());
}
@Test
public void testRvar1Locked() {
l.tryParse("=M000005.S134002");
tryParseAllHandlers("=M000005.S134002");
verify(handler).updateChannel(LcnChannelGroup.RVARSETPOINT, "1", new DecimalType(1234));
verify(handler).updateChannel(LcnChannelGroup.RVARLOCK, "1", OnOffType.ON);
verify(handler, times(2)).updateChannel(any(), any(), any());
}
@Test
public void testRvar2Locked() {
l.tryParse("=M000005.S234002");
tryParseAllHandlers("=M000005.S234002");
verify(handler).updateChannel(LcnChannelGroup.RVARSETPOINT, "2", new DecimalType(1234));
verify(handler).updateChannel(LcnChannelGroup.RVARLOCK, "2", OnOffType.ON);
verify(handler, times(2)).updateChannel(any(), any(), any());
}
}

View File

@ -12,6 +12,7 @@
*/
package org.openhab.binding.lcn.internal.subhandler;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.verify;
import org.eclipse.jdt.annotation.NonNullByDefault;
@ -27,31 +28,30 @@ import org.openhab.core.library.types.DecimalType;
*/
@NonNullByDefault
public class LcnModuleS0CounterSubHandlerTest extends AbstractTestLcnModuleSubHandler {
private @NonNullByDefault({}) LcnModuleS0CounterSubHandler l;
@Override
@BeforeEach
public void setUp() {
super.setUp();
l = new LcnModuleS0CounterSubHandler(handler, info);
}
@Test
public void testZero() {
l.tryParse("=M000005.C10");
tryParseAllHandlers("=M000005.C10");
verify(handler).updateChannel(LcnChannelGroup.S0INPUT, "1", new DecimalType(0));
verify(handler).updateChannel(any(), any(), any());
}
@Test
public void testMaxValue() {
l.tryParse("=M000005.C14294967295");
tryParseAllHandlers("=M000005.C14294967295");
verify(handler).updateChannel(LcnChannelGroup.S0INPUT, "1", new DecimalType(4294967295L));
verify(handler).updateChannel(any(), any(), any());
}
@Test
public void test4() {
l.tryParse("=M000005.C412345");
tryParseAllHandlers("=M000005.C412345");
verify(handler).updateChannel(LcnChannelGroup.S0INPUT, "4", new DecimalType(12345));
verify(handler).updateChannel(any(), any(), any());
}
}

View File

@ -12,6 +12,7 @@
*/
package org.openhab.binding.lcn.internal.subhandler;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.*;
import org.eclipse.jdt.annotation.NonNullByDefault;
@ -41,30 +42,34 @@ public class LcnModuleThresholdSubHandlerTest extends AbstractTestLcnModuleSubHa
@Test
public void testThreshold11() {
l.tryParse("=M000005.T1112345");
tryParseAllHandlers("=M000005.T1112345");
verify(handler).updateChannel(LcnChannelGroup.THRESHOLDREGISTER1, "1", new DecimalType(12345));
verify(handler).updateChannel(any(), any(), any());
}
@Test
public void testThreshold14() {
l.tryParse("=M000005.T140");
tryParseAllHandlers("=M000005.T140");
verify(handler).updateChannel(LcnChannelGroup.THRESHOLDREGISTER1, "4", new DecimalType(0));
verify(handler).updateChannel(any(), any(), any());
}
@Test
public void testThreshold41() {
l.tryParse("=M000005.T4112345");
tryParseAllHandlers("=M000005.T4112345");
verify(handler).updateChannel(LcnChannelGroup.THRESHOLDREGISTER4, "1", new DecimalType(12345));
verify(handler).updateChannel(any(), any(), any());
}
@Test
public void testThresholdLegacy() {
l.tryParse("=M000005.S1123451123411123000000000112345");
tryParseAllHandlers("=M000005.S1123451123411123000000000112345");
verify(handler).updateChannel(LcnChannelGroup.THRESHOLDREGISTER1, "1", new DecimalType(12345));
verify(handler).updateChannel(LcnChannelGroup.THRESHOLDREGISTER1, "2", new DecimalType(11234));
verify(handler).updateChannel(LcnChannelGroup.THRESHOLDREGISTER1, "3", new DecimalType(11123));
verify(handler).updateChannel(LcnChannelGroup.THRESHOLDREGISTER1, "4", new DecimalType(0));
verify(handler).updateChannel(LcnChannelGroup.THRESHOLDREGISTER1, "5", new DecimalType(1));
verify(handler, times(5)).updateChannel(any(), any(), any());
}
@Test

View File

@ -12,6 +12,7 @@
*/
package org.openhab.binding.lcn.internal.subhandler;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.*;
import org.eclipse.jdt.annotation.NonNullByDefault;
@ -42,21 +43,24 @@ public class LcnModuleVariableSubHandlerTest extends AbstractTestLcnModuleSubHan
@Test
public void testStatusVariable1() {
l.tryParse("=M000005.A00112345");
tryParseAllHandlers("=M000005.A00112345");
verify(handler).updateChannel(LcnChannelGroup.VARIABLE, "1", new DecimalType(12345));
verify(handler).updateChannel(any(), any(), any());
}
@Test
public void testStatusVariable12() {
l.tryParse("=M000005.A01212345");
tryParseAllHandlers("=M000005.A01212345");
verify(handler).updateChannel(LcnChannelGroup.VARIABLE, "12", new DecimalType(12345));
verify(handler).updateChannel(any(), any(), any());
}
@Test
public void testStatusLegacyVariable3() {
when(info.getLastRequestedVarWithoutTypeInResponse()).thenReturn(Variable.VARIABLE3);
l.tryParse("=M000005.12345");
tryParseAllHandlers("=M000005.12345");
verify(handler).updateChannel(LcnChannelGroup.VARIABLE, "3", new DecimalType(12345));
verify(handler).updateChannel(any(), any(), any());
}
@Test
@ -77,13 +81,15 @@ public class LcnModuleVariableSubHandlerTest extends AbstractTestLcnModuleSubHan
@Test
public void testStatusVariable10SensorDefective() {
l.tryParse("=M000005.A01032512");
tryParseAllHandlers("=M000005.A01032512");
verify(handler).updateChannel(LcnChannelGroup.VARIABLE, "10", new StringType("DEFECTIVE"));
verify(handler).updateChannel(any(), any(), any());
}
@Test
public void testStatusVariable8NotConfigured() {
l.tryParse("=M000005.A00865535");
tryParseAllHandlers("=M000005.A00865535");
verify(handler).updateChannel(LcnChannelGroup.VARIABLE, "8", new StringType("Not configured in LCN-PRO"));
verify(handler).updateChannel(any(), any(), any());
}
}