]> git.basschouten.com Git - openhab-addons.git/commitdiff
[rfxcom] Enable Raw message transmission (#10866)
authorJames Hewitt <james.hewitt@uk.ibm.com>
Thu, 24 Jun 2021 17:37:37 +0000 (18:37 +0100)
committerGitHub <noreply@github.com>
Thu, 24 Jun 2021 17:37:37 +0000 (19:37 +0200)
This enables raw message transmission by configuring a raw thing with pulses to
send for either ON, OFF, OPEN or CLOSED commands.

To enable extended config, this includes a refactor for the RFXComHandler to
support different Configuration objects depending on the thing type, and moves
the parsing, validation, and message matching logic to the Configuration objects
where the logic is more appropriate.

To enable testing of the RFXComHandler, the RFXComMessageFactory was abstracted
out and injected as a dependency.

Signed-off-by: James Hewitt <james.hewitt@uk.ibm.com>
74 files changed:
bundles/org.openhab.binding.rfxcom/README.md
bundles/org.openhab.binding.rfxcom/src/main/java/org/openhab/binding/rfxcom/internal/RFXComBindingConstants.java
bundles/org.openhab.binding.rfxcom/src/main/java/org/openhab/binding/rfxcom/internal/RFXComHandlerFactory.java
bundles/org.openhab.binding.rfxcom/src/main/java/org/openhab/binding/rfxcom/internal/config/RFXComDeviceConfiguration.java
bundles/org.openhab.binding.rfxcom/src/main/java/org/openhab/binding/rfxcom/internal/config/RFXComGenericDeviceConfiguration.java [new file with mode: 0644]
bundles/org.openhab.binding.rfxcom/src/main/java/org/openhab/binding/rfxcom/internal/config/RFXComLighting4DeviceConfiguration.java [new file with mode: 0644]
bundles/org.openhab.binding.rfxcom/src/main/java/org/openhab/binding/rfxcom/internal/config/RFXComRawDeviceConfiguration.java [new file with mode: 0644]
bundles/org.openhab.binding.rfxcom/src/main/java/org/openhab/binding/rfxcom/internal/exceptions/RFXComInvalidParameterException.java [new file with mode: 0644]
bundles/org.openhab.binding.rfxcom/src/main/java/org/openhab/binding/rfxcom/internal/exceptions/RFXComInvalidStateException.java [new file with mode: 0644]
bundles/org.openhab.binding.rfxcom/src/main/java/org/openhab/binding/rfxcom/internal/handler/RFXComBridgeHandler.java
bundles/org.openhab.binding.rfxcom/src/main/java/org/openhab/binding/rfxcom/internal/handler/RFXComHandler.java
bundles/org.openhab.binding.rfxcom/src/main/java/org/openhab/binding/rfxcom/internal/messages/RFXComDeviceMessageImpl.java
bundles/org.openhab.binding.rfxcom/src/main/java/org/openhab/binding/rfxcom/internal/messages/RFXComInterfaceMessage.java
bundles/org.openhab.binding.rfxcom/src/main/java/org/openhab/binding/rfxcom/internal/messages/RFXComLighting4Message.java
bundles/org.openhab.binding.rfxcom/src/main/java/org/openhab/binding/rfxcom/internal/messages/RFXComMessage.java
bundles/org.openhab.binding.rfxcom/src/main/java/org/openhab/binding/rfxcom/internal/messages/RFXComMessageFactory.java
bundles/org.openhab.binding.rfxcom/src/main/java/org/openhab/binding/rfxcom/internal/messages/RFXComMessageFactoryImpl.java [new file with mode: 0644]
bundles/org.openhab.binding.rfxcom/src/main/java/org/openhab/binding/rfxcom/internal/messages/RFXComRawMessage.java
bundles/org.openhab.binding.rfxcom/src/main/resources/OH-INF/thing/channels.xml
bundles/org.openhab.binding.rfxcom/src/main/resources/OH-INF/thing/raw.xml
bundles/org.openhab.binding.rfxcom/src/test/java/org/openhab/binding/rfxcom/internal/config/RFXComDeviceConfigurationBuilder.java [deleted file]
bundles/org.openhab.binding.rfxcom/src/test/java/org/openhab/binding/rfxcom/internal/config/RFXComGenericDeviceConfigurationTest.java [new file with mode: 0644]
bundles/org.openhab.binding.rfxcom/src/test/java/org/openhab/binding/rfxcom/internal/config/RFXComLighting4DeviceConfigurationTest.java [new file with mode: 0644]
bundles/org.openhab.binding.rfxcom/src/test/java/org/openhab/binding/rfxcom/internal/config/RFXComRawDeviceConfigurationTest.java [new file with mode: 0644]
bundles/org.openhab.binding.rfxcom/src/test/java/org/openhab/binding/rfxcom/internal/handler/RFXComHandlerTest.java [new file with mode: 0644]
bundles/org.openhab.binding.rfxcom/src/test/java/org/openhab/binding/rfxcom/internal/messages/RFXComBBQTemperatureMessageTest.java
bundles/org.openhab.binding.rfxcom/src/test/java/org/openhab/binding/rfxcom/internal/messages/RFXComBarometricMessageTest.java
bundles/org.openhab.binding.rfxcom/src/test/java/org/openhab/binding/rfxcom/internal/messages/RFXComBlinds1MessageTest.java
bundles/org.openhab.binding.rfxcom/src/test/java/org/openhab/binding/rfxcom/internal/messages/RFXComCamera1MessageTest.java
bundles/org.openhab.binding.rfxcom/src/test/java/org/openhab/binding/rfxcom/internal/messages/RFXComChimeMessageTest.java
bundles/org.openhab.binding.rfxcom/src/test/java/org/openhab/binding/rfxcom/internal/messages/RFXComCurrentEnergyMessageTest.java
bundles/org.openhab.binding.rfxcom/src/test/java/org/openhab/binding/rfxcom/internal/messages/RFXComCurrentMessageTest.java
bundles/org.openhab.binding.rfxcom/src/test/java/org/openhab/binding/rfxcom/internal/messages/RFXComCurtain1MessageTest.java
bundles/org.openhab.binding.rfxcom/src/test/java/org/openhab/binding/rfxcom/internal/messages/RFXComDateTimeMessageTest.java
bundles/org.openhab.binding.rfxcom/src/test/java/org/openhab/binding/rfxcom/internal/messages/RFXComEdisioTest.java
bundles/org.openhab.binding.rfxcom/src/test/java/org/openhab/binding/rfxcom/internal/messages/RFXComEnergyMessageTest.java
bundles/org.openhab.binding.rfxcom/src/test/java/org/openhab/binding/rfxcom/internal/messages/RFXComFS20MessageTest.java
bundles/org.openhab.binding.rfxcom/src/test/java/org/openhab/binding/rfxcom/internal/messages/RFXComFanMessageTest.java
bundles/org.openhab.binding.rfxcom/src/test/java/org/openhab/binding/rfxcom/internal/messages/RFXComGasMessageTest.java
bundles/org.openhab.binding.rfxcom/src/test/java/org/openhab/binding/rfxcom/internal/messages/RFXComHomeConfortTest.java
bundles/org.openhab.binding.rfxcom/src/test/java/org/openhab/binding/rfxcom/internal/messages/RFXComHumidityMessageTest.java
bundles/org.openhab.binding.rfxcom/src/test/java/org/openhab/binding/rfxcom/internal/messages/RFXComIOLinesMessageTest.java
bundles/org.openhab.binding.rfxcom/src/test/java/org/openhab/binding/rfxcom/internal/messages/RFXComInterfaceMessageTest.java
bundles/org.openhab.binding.rfxcom/src/test/java/org/openhab/binding/rfxcom/internal/messages/RFXComInvalidMessageTypeTest.java
bundles/org.openhab.binding.rfxcom/src/test/java/org/openhab/binding/rfxcom/internal/messages/RFXComLighting1MessageTest.java
bundles/org.openhab.binding.rfxcom/src/test/java/org/openhab/binding/rfxcom/internal/messages/RFXComLighting2MessageTest.java
bundles/org.openhab.binding.rfxcom/src/test/java/org/openhab/binding/rfxcom/internal/messages/RFXComLighting3MessageTest.java
bundles/org.openhab.binding.rfxcom/src/test/java/org/openhab/binding/rfxcom/internal/messages/RFXComLighting4MessageTest.java
bundles/org.openhab.binding.rfxcom/src/test/java/org/openhab/binding/rfxcom/internal/messages/RFXComLighting5MessageTest.java
bundles/org.openhab.binding.rfxcom/src/test/java/org/openhab/binding/rfxcom/internal/messages/RFXComLighting6MessageTest.java
bundles/org.openhab.binding.rfxcom/src/test/java/org/openhab/binding/rfxcom/internal/messages/RFXComPowerMessageTest.java
bundles/org.openhab.binding.rfxcom/src/test/java/org/openhab/binding/rfxcom/internal/messages/RFXComRFXMeterMessageTest.java
bundles/org.openhab.binding.rfxcom/src/test/java/org/openhab/binding/rfxcom/internal/messages/RFXComRFXSensorMessageTest.java
bundles/org.openhab.binding.rfxcom/src/test/java/org/openhab/binding/rfxcom/internal/messages/RFXComRadiator1MessageTest.java
bundles/org.openhab.binding.rfxcom/src/test/java/org/openhab/binding/rfxcom/internal/messages/RFXComRainMessageTest.java
bundles/org.openhab.binding.rfxcom/src/test/java/org/openhab/binding/rfxcom/internal/messages/RFXComRawMessageTest.java
bundles/org.openhab.binding.rfxcom/src/test/java/org/openhab/binding/rfxcom/internal/messages/RFXComRemoteControlMessageTest.java
bundles/org.openhab.binding.rfxcom/src/test/java/org/openhab/binding/rfxcom/internal/messages/RFXComRfyMessageTest.java
bundles/org.openhab.binding.rfxcom/src/test/java/org/openhab/binding/rfxcom/internal/messages/RFXComSecurity1MessageTest.java
bundles/org.openhab.binding.rfxcom/src/test/java/org/openhab/binding/rfxcom/internal/messages/RFXComSecurity2MessageTest.java
bundles/org.openhab.binding.rfxcom/src/test/java/org/openhab/binding/rfxcom/internal/messages/RFXComTemperatureHumidityBarometricMessageTest.java
bundles/org.openhab.binding.rfxcom/src/test/java/org/openhab/binding/rfxcom/internal/messages/RFXComTemperatureHumidityMessageTest.java
bundles/org.openhab.binding.rfxcom/src/test/java/org/openhab/binding/rfxcom/internal/messages/RFXComTemperatureMessageTest.java
bundles/org.openhab.binding.rfxcom/src/test/java/org/openhab/binding/rfxcom/internal/messages/RFXComTemperatureRainMessageTest.java
bundles/org.openhab.binding.rfxcom/src/test/java/org/openhab/binding/rfxcom/internal/messages/RFXComThermostat1MessageTest.java
bundles/org.openhab.binding.rfxcom/src/test/java/org/openhab/binding/rfxcom/internal/messages/RFXComThermostat2MessageTest.java
bundles/org.openhab.binding.rfxcom/src/test/java/org/openhab/binding/rfxcom/internal/messages/RFXComThermostat3MessageTest.java
bundles/org.openhab.binding.rfxcom/src/test/java/org/openhab/binding/rfxcom/internal/messages/RFXComThermostat4MessageTest.java
bundles/org.openhab.binding.rfxcom/src/test/java/org/openhab/binding/rfxcom/internal/messages/RFXComTransmitterMessageTest.java
bundles/org.openhab.binding.rfxcom/src/test/java/org/openhab/binding/rfxcom/internal/messages/RFXComUVMessageTest.java
bundles/org.openhab.binding.rfxcom/src/test/java/org/openhab/binding/rfxcom/internal/messages/RFXComUndecodedRFMessageTest.java
bundles/org.openhab.binding.rfxcom/src/test/java/org/openhab/binding/rfxcom/internal/messages/RFXComWaterMessageTest.java
bundles/org.openhab.binding.rfxcom/src/test/java/org/openhab/binding/rfxcom/internal/messages/RFXComWeightMessageTest.java
bundles/org.openhab.binding.rfxcom/src/test/java/org/openhab/binding/rfxcom/internal/messages/RFXComWindMessageTest.java

index de8f614a8a70c850f63c63870e92d764e6c49dad..172b6c20fca4e65604742e47f60b03cda01f6eb1 100644 (file)
@@ -171,6 +171,7 @@ This binding currently supports following channel types:
 | mood            | Number        | Mood channel.                                                                      |
 | motion          | Switch        | Motion detection sensor state.                                                     |
 | pressure        | Number        | Barometric value in hPa.                                                           |
+| pulses          | String        | Space separated decimal pulse lengths for a raw message in usec.                   |
 | rainrate        | Number        | Rain fall rate in millimeters per hour.                                            |
 | raintotal       | Number        | Total rain in millimeters.                                                         |
 | rawmessage      | String        | Hexadecimal representation of the raw RFXCOM msg incl. header and payload          |
@@ -918,9 +919,15 @@ A Rain device
         *   RAIN6 - La Crosse TX5
         *   RAIN9 - TFA 30.3233.1
 
+
 ### raw - RFXCOM Raw Messages
 
-Raw messages.
+Raw messages. These messages are included in the Pro firmware and represent messages
+for which the device does not understand the protocol. The raw message is a list of the
+length of the RF pulses before they have been interpreted as bytes.
+
+You can also send raw messages by recording the pulses of an incoming message and
+using them to configure a raw thing item.
 
 #### Channels
 
@@ -928,11 +935,13 @@ Raw messages.
 |------------|---------------------------|-----------|-------------|
 | rawMessage | [rawmessage](#channels)   | String    |             |
 | rawPayload | [rawpayload](#channels)   | String    |             |
+| pulses     | [pulses](#channels)       | String    |             |
 
 #### Configuration Options
 
 *   deviceId - Device Id
-    *   Raw items cannot provide a device ID, so this value is always RAW.
+    *   Raw items cannot provide a device ID, so to receive RAW messages use
+        a Device Id of RAW. For transmit only devices, use any Device Id.
 
 *   subType - Sub Type
     *   Specifies message sub type.
@@ -942,6 +951,79 @@ Raw messages.
         *   RAW_PACKET3
         *   RAW_PACKET4
 
+*   repeat - Repeat
+    *   Number of times to repeat message on transmit. Defaults to 5.
+
+*   onPulses - On Pulses
+    *   Pulses to send for an ON command. Space delimited pulse lengths
+        in usec. Must be an even number of pulse lengths, with a maximum
+        of 142 total pulses. Max pulse length is 65535. Pulses of value 0
+        will be transmitted as 10000. See the RFXtfx user guide for more
+        information.
+
+*   offPulses - Off Pulses
+    *   Pulses to send for an OFF command. Space delimited pulse lengths
+        in usec. Must be an even number of pulse lengths, with a maximum
+        of 142 total pulses. Max pulse length is 65535. Pulses of value 0
+        will be transmitted as 10000. See the RFXtfx user guide for more
+        information.
+
+*   openPulses - Open Pulses
+    *   Pulses to send for an OPEN command. Space delimited pulse lengths
+        in usec. Must be an even number of pulse lengths, with a maximum
+        of 142 total pulses. Max pulse length is 65535. Pulses of value 0
+        will be transmitted as 10000. See the RFXtfx user guide for more
+        information.
+
+*   closedPulses - Closed Pulses
+    *   Pulses to send for an CLOSED command. Space delimited pulse lengths
+        in usec. Must be an even number of pulse lengths, with a maximum
+        of 142 total pulses. Max pulse length is 65535. Pulses of value 0
+        will be transmitted as 10000. See the RFXtfx user guide for more
+        information.
+
+#### Examples
+
+This can be used to transmit raw messages.
+
+The first step is to work out the right pulses for the device. You can do this using RFXmngr, or
+you can do this using openhab:
+
+1. Set up a RAW thing to receive raw pulses:
+
+    ```
+    Bridge rfxcom:tcpbridge:rfxtrx0 [ host="192.168.42.10", port=10001, enableUndecoded=true ] {
+        Thing raw RAW [ deviceId="RAW", subType="RAW_PACKET1" ]
+    }
+    ```
+
+2. Add an item to see what the pulses are:
+
+    ```
+    String RawPulses { channel="rfxcom:raw:rfxtrx0:RAW:pulses" }
+    ```
+
+3. Activate the device and look at the pulses that are set. Look for a higher value in the pulses, that is
+   likely to be a gap for a repeat. Take the pulses from before the gap. Make sure there are an
+   even number, and if not, drop a 0 on the end.
+
+Now you have the pulses, set up a send device:
+
+1. Set up a RAW thing to send a command:
+
+    ```
+    Bridge rfxcom:tcpbridge:rfxtrx0 [ host="192.168.42.10", port=10001, enableUndecoded=true ] {
+        Thing raw MySwitch [ deviceId="MySwitch", subType="RAW_PACKET1", onPulses="100 200 300 0", offPulses="400 500 600 0" ]
+    }
+    ```
+
+2. Add an item to send the command:
+
+    ```
+    Switch MySwitch { channel="rfxcom:raw:rfxtrx0:MySwitch:command" }
+    ```
+
+3. Use the command to send the raw message.
 
 ### rfxsensor - RFXCOM RFXSensor 
 
@@ -1230,7 +1312,12 @@ A Thermostat3 device.
 
 ### undecoded - RFXCOM Undecoded RF Messages
 
-Any messages that RFXCOM can receive but not decode.
+Undecoded messages are messages where RFCOM understands the protocol and has converted
+the raw RF pulses into bytes, but has not attempted to decode the bytes into meaningful
+data.
+
+Undecoded message are receive only, there is not way to transmit an undecoded message.
+If you need to repeat an undecoded message, consider looking at Raw messages instead.
 
 #### Channels
 
index d7c67118fa711b1c8c67afe04c9849cec21be213..b0650bc2007d7448fb203d3978982c46991b8c18 100644 (file)
@@ -12,6 +12,7 @@
  */
 package org.openhab.binding.rfxcom.internal;
 
+import java.util.AbstractMap;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.Map;
@@ -20,6 +21,9 @@ import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
 import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.openhab.binding.rfxcom.internal.config.RFXComDeviceConfiguration;
+import org.openhab.binding.rfxcom.internal.config.RFXComLighting4DeviceConfiguration;
+import org.openhab.binding.rfxcom.internal.config.RFXComRawDeviceConfiguration;
 import org.openhab.binding.rfxcom.internal.messages.RFXComBaseMessage.PacketType;
 import org.openhab.core.thing.ThingTypeUID;
 
@@ -65,6 +69,7 @@ public class RFXComBindingConstants {
     // List of all Channel ids
     public static final String CHANNEL_RAW_MESSAGE = "rawMessage";
     public static final String CHANNEL_RAW_PAYLOAD = "rawPayload";
+    public static final String CHANNEL_PULSES = "pulses";
     public static final String CHANNEL_SHUTTER = "shutter";
     public static final String CHANNEL_VENETIAN_BLIND = "venetianBlind";
     public static final String CHANNEL_SUN_WIND_DETECTOR = "sunWindDetector";
@@ -188,6 +193,16 @@ public class RFXComBindingConstants {
                     THING_TYPE_THERMOSTAT2, THING_TYPE_THERMOSTAT3, THING_TYPE_UNDECODED, THING_TYPE_UV,
                     THING_TYPE_WATER_USAGE, THING_TYPE_WEIGHTING_SCALE, THING_TYPE_WIND).collect(Collectors.toSet()));
 
+    /**
+     * Map Device ThingTypeUIDs to their Configuration class
+     */
+    public static final Map<ThingTypeUID, Class<? extends RFXComDeviceConfiguration>> THING_TYPE_UID_CONFIGURATION_CLASS_MAP = Map
+            .ofEntries(
+                    new AbstractMap.SimpleEntry<ThingTypeUID, Class<? extends RFXComDeviceConfiguration>>(
+                            THING_TYPE_RAW, RFXComRawDeviceConfiguration.class),
+                    new AbstractMap.SimpleEntry<ThingTypeUID, Class<? extends RFXComDeviceConfiguration>>(
+                            THING_TYPE_LIGHTNING4, RFXComLighting4DeviceConfiguration.class));
+
     /**
      * Map RFXCOM packet types to RFXCOM Thing types and vice versa.
      */
index e9d9620125cd3bc2b7b0f9cc3e40853d27e46ecb..4175d71d8a5463fe33a01f18ec0cf1a66035f40f 100644 (file)
@@ -64,7 +64,7 @@ public class RFXComHandlerFactory extends BaseThingHandlerFactory {
 
         if (RFXComBindingConstants.SUPPORTED_BRIDGE_THING_TYPES_UIDS.contains(thingTypeUID)) {
             return new RFXComBridgeHandler((Bridge) thing, serialPortManager);
-        } else if (supportsThingType(thingTypeUID)) {
+        } else if (RFXComBindingConstants.SUPPORTED_DEVICE_THING_TYPES_UIDS.contains(thingTypeUID)) {
             return new RFXComHandler(thing);
         }
 
index 730c016f6953e878dcc9b8a7b6abffd76dd938a0..38086f59c5247585d31fd4bd4483198aca21976b 100644 (file)
  */
 package org.openhab.binding.rfxcom.internal.config;
 
+import org.openhab.binding.rfxcom.internal.exceptions.RFXComInvalidParameterException;
+import org.openhab.binding.rfxcom.internal.messages.RFXComDeviceMessage;
+
 /**
- * Configuration class for RfxcomBinding device.
+ * Configuration interface for RFXCom devices.
  *
  * @author Pauli Anttila - Initial contribution
+ * @author James Hewitt-Thomas - Convert to interface and add validation and matching
  */
+public interface RFXComDeviceConfiguration {
+    public void parseAndValidate() throws RFXComInvalidParameterException;
 
-public class RFXComDeviceConfiguration {
-    public static final String DEVICE_ID_LABEL = "deviceId";
-    public static final String SUB_TYPE_LABEL = "subType";
-    public static final String PULSE_LABEL = "pulse";
-    public static final String ON_COMMAND_ID_LABEL = "onCommandId";
-    public static final String OFF_COMMAND_ID_LABEL = "offCommandId";
-
-    public String deviceId;
-    public String subType;
-    public Integer pulse;
-    public Integer onCommandId;
-    public Integer offCommandId;
+    public boolean matchesMessage(RFXComDeviceMessage message);
 }
diff --git a/bundles/org.openhab.binding.rfxcom/src/main/java/org/openhab/binding/rfxcom/internal/config/RFXComGenericDeviceConfiguration.java b/bundles/org.openhab.binding.rfxcom/src/main/java/org/openhab/binding/rfxcom/internal/config/RFXComGenericDeviceConfiguration.java
new file mode 100644 (file)
index 0000000..3e3f132
--- /dev/null
@@ -0,0 +1,44 @@
+/**
+ * Copyright (c) 2010-2021 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.rfxcom.internal.config;
+
+import org.openhab.binding.rfxcom.internal.exceptions.RFXComInvalidParameterException;
+import org.openhab.binding.rfxcom.internal.messages.RFXComDeviceMessage;
+
+/**
+ * Configuration class for generic RFXCOM device.
+ *
+ * @author Pauli Anttila - Initial contribution
+ * @author James Hewitt-Thomas - Add validations and matching
+ */
+public class RFXComGenericDeviceConfiguration implements RFXComDeviceConfiguration {
+    public static final String DEVICE_ID_LABEL = "deviceId";
+    public static final String SUB_TYPE_LABEL = "subType";
+    public String deviceId;
+    public String subType;
+
+    @Override
+    public void parseAndValidate() throws RFXComInvalidParameterException {
+        if (deviceId == null) {
+            throw new RFXComInvalidParameterException("deviceId", null, "RFXCOM device missing deviceId");
+        }
+        if (subType == null) {
+            throw new RFXComInvalidParameterException("subType", null, "RFXCOM device missing subType");
+        }
+    }
+
+    @Override
+    public boolean matchesMessage(RFXComDeviceMessage message) {
+        return deviceId.equals(message.getDeviceId());
+    }
+}
diff --git a/bundles/org.openhab.binding.rfxcom/src/main/java/org/openhab/binding/rfxcom/internal/config/RFXComLighting4DeviceConfiguration.java b/bundles/org.openhab.binding.rfxcom/src/main/java/org/openhab/binding/rfxcom/internal/config/RFXComLighting4DeviceConfiguration.java
new file mode 100644 (file)
index 0000000..f1244ed
--- /dev/null
@@ -0,0 +1,27 @@
+/**
+ * Copyright (c) 2010-2021 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.rfxcom.internal.config;
+
+/**
+ * Configuration class for Lighting4 RFXCOM device.
+ *
+ * @author James Hewitt-Thomas - Initial contribution
+ */
+public class RFXComLighting4DeviceConfiguration extends RFXComGenericDeviceConfiguration {
+    public static final String PULSE_LABEL = "pulse";
+    public static final String ON_COMMAND_ID_LABEL = "onCommandId";
+    public static final String OFF_COMMAND_ID_LABEL = "offCommandId";
+    public Integer pulse;
+    public Integer onCommandId;
+    public Integer offCommandId;
+}
diff --git a/bundles/org.openhab.binding.rfxcom/src/main/java/org/openhab/binding/rfxcom/internal/config/RFXComRawDeviceConfiguration.java b/bundles/org.openhab.binding.rfxcom/src/main/java/org/openhab/binding/rfxcom/internal/config/RFXComRawDeviceConfiguration.java
new file mode 100644 (file)
index 0000000..042055a
--- /dev/null
@@ -0,0 +1,99 @@
+/**
+ * Copyright (c) 2010-2021 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.rfxcom.internal.config;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
+import org.openhab.binding.rfxcom.internal.exceptions.RFXComInvalidParameterException;
+
+/**
+ * Configuration class for Raw RFXCOM device.
+ *
+ * @author James Hewitt-Thomas - Initial contribution
+ */
+@NonNullByDefault
+public class RFXComRawDeviceConfiguration extends RFXComGenericDeviceConfiguration {
+    public static final String REPEAT_LABEL = "repeat";
+    public int repeat;
+
+    public static final String ON_PULSES_LABEL = "onPulses";
+    public static final String OFF_PULSES_LABEL = "offPulses";
+    @Nullable
+    public String onPulses;
+    @Nullable
+    public String offPulses;
+    public short @Nullable [] onPulsesArray;
+    public short @Nullable [] offPulsesArray;
+
+    public static final String OPEN_PULSES_LABEL = "openPulses";
+    public static final String CLOSED_PULSES_LABEL = "closedPulses";
+    @Nullable
+    public String openPulses;
+    @Nullable
+    public String closedPulses;
+    public short @Nullable [] openPulsesArray;
+    public short @Nullable [] closedPulsesArray;
+
+    @Override
+    public void parseAndValidate() throws RFXComInvalidParameterException {
+        super.parseAndValidate();
+
+        onPulsesArray = parseAndValidatePulses("onPulses", onPulses);
+        offPulsesArray = parseAndValidatePulses("offPulses", offPulses);
+        openPulsesArray = parseAndValidatePulses("openPulses", openPulses);
+        closedPulsesArray = parseAndValidatePulses("closedPulses", closedPulses);
+    }
+
+    private static short @Nullable [] parseAndValidatePulses(String parameter, @Nullable String pulses)
+            throws RFXComInvalidParameterException {
+        if (pulses != null) {
+            return parseAndValidatePulsesNonNull(parameter, pulses);
+        } else {
+            return null;
+        }
+    }
+
+    private static short[] parseAndValidatePulsesNonNull(String parameter, String pulses)
+            throws RFXComInvalidParameterException {
+        String[] strings = pulses.trim().split("\\s+");
+
+        if (strings.length > 124) {
+            throw new RFXComInvalidParameterException(parameter, pulses, "Cannot have more than 124 pulses");
+        }
+
+        if (strings.length % 2 != 0) {
+            throw new RFXComInvalidParameterException(parameter, pulses, "Pulses must be in pairs");
+        }
+
+        try {
+            short[] shorts = new short[strings.length];
+            for (int i = 0; i < strings.length; i++) {
+                int pulse = Integer.parseInt(strings[i]);
+                if (pulse > 65535) {
+                    throw new RFXComInvalidParameterException(parameter, pulses, "Cannot have pulse above 65535 usec");
+                } else if (pulse < 0) {
+                    throw new RFXComInvalidParameterException(parameter, pulses, "Cannot have negative pulse");
+                } else if (pulse == 0) {
+                    // The user guide suggests that received pulses of size 0 should be
+                    // replaced with something above 8000, as they represent gaps.
+                    shorts[i] = 10000;
+                } else {
+                    shorts[i] = (short) pulse;
+                }
+            }
+            return shorts;
+        } catch (NumberFormatException e) {
+            throw new RFXComInvalidParameterException(parameter, pulses, e.getMessage(), e);
+        }
+    }
+}
diff --git a/bundles/org.openhab.binding.rfxcom/src/main/java/org/openhab/binding/rfxcom/internal/exceptions/RFXComInvalidParameterException.java b/bundles/org.openhab.binding.rfxcom/src/main/java/org/openhab/binding/rfxcom/internal/exceptions/RFXComInvalidParameterException.java
new file mode 100644 (file)
index 0000000..78c462f
--- /dev/null
@@ -0,0 +1,39 @@
+/**
+ * Copyright (c) 2010-2021 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.rfxcom.internal.exceptions;
+
+/**
+ * Exception for when RFXCOM messages have a value that we don't understand.
+ *
+ * @author James Hewitt-Thomas - Initial contribution
+ */
+public class RFXComInvalidParameterException extends RFXComException {
+
+    private static final long serialVersionUID = -2778120072474013560L;
+
+    public RFXComInvalidParameterException(String parameter, String value) {
+        super("Invalid value '" + value + "' for parameter " + parameter);
+    }
+
+    public RFXComInvalidParameterException(String parameter, String value, String reason) {
+        super("Invalid value '" + value + "' for parameter " + parameter + ": " + reason);
+    }
+
+    public RFXComInvalidParameterException(String parameter, String value, Throwable cause) {
+        super("Invalid value '" + value + "' for parameter " + parameter, cause);
+    }
+
+    public RFXComInvalidParameterException(String parameter, String value, String reason, Throwable cause) {
+        super("Invalid value '" + value + "' for parameter " + parameter + ": " + reason, cause);
+    }
+}
diff --git a/bundles/org.openhab.binding.rfxcom/src/main/java/org/openhab/binding/rfxcom/internal/exceptions/RFXComInvalidStateException.java b/bundles/org.openhab.binding.rfxcom/src/main/java/org/openhab/binding/rfxcom/internal/exceptions/RFXComInvalidStateException.java
new file mode 100644 (file)
index 0000000..7de0425
--- /dev/null
@@ -0,0 +1,31 @@
+/**
+ * Copyright (c) 2010-2021 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.rfxcom.internal.exceptions;
+
+/**
+ * Exception for when RFXCOM messages have a value that we don't understand.
+ *
+ * @author James Hewitt-Thomas - Initial contribution
+ */
+public class RFXComInvalidStateException extends RFXComException {
+
+    private static final long serialVersionUID = -2770653643474013560L;
+
+    public RFXComInvalidStateException(String channel, String state) {
+        super("Invalid state '" + state + "' for parameter " + channel);
+    }
+
+    public RFXComInvalidStateException(String channel, String state, String reason) {
+        super("Invalid state '" + state + "' for parameter " + channel + ": " + reason);
+    }
+}
index 5ea7f9a9c62e6a0c6da0791bf8a9d0f9c7ccdaf9..092ebf4364769b7adf692de840b950af1c06d991 100644 (file)
@@ -41,6 +41,7 @@ import org.openhab.binding.rfxcom.internal.messages.RFXComInterfaceMessage.Comma
 import org.openhab.binding.rfxcom.internal.messages.RFXComInterfaceMessage.SubType;
 import org.openhab.binding.rfxcom.internal.messages.RFXComMessage;
 import org.openhab.binding.rfxcom.internal.messages.RFXComMessageFactory;
+import org.openhab.binding.rfxcom.internal.messages.RFXComMessageFactoryImpl;
 import org.openhab.binding.rfxcom.internal.messages.RFXComTransmitterMessage;
 import org.openhab.core.io.transport.serial.SerialPortManager;
 import org.openhab.core.thing.Bridge;
@@ -75,6 +76,8 @@ public class RFXComBridgeHandler extends BaseBridgeHandler {
 
     private SerialPortManager serialPortManager;
 
+    private RFXComMessageFactory messageFactory;
+
     private class TransmitQueue {
         private Queue<RFXComBaseMessage> queue = new LinkedBlockingQueue<>();
 
@@ -116,6 +119,14 @@ public class RFXComBridgeHandler extends BaseBridgeHandler {
     public RFXComBridgeHandler(@NonNull Bridge br, SerialPortManager serialPortManager) {
         super(br);
         this.serialPortManager = serialPortManager;
+        this.messageFactory = RFXComMessageFactoryImpl.INSTANCE;
+    }
+
+    public RFXComBridgeHandler(@NonNull Bridge br, SerialPortManager serialPortManager,
+            RFXComMessageFactory messageFactory) {
+        super(br);
+        this.serialPortManager = serialPortManager;
+        this.messageFactory = messageFactory;
     }
 
     @Override
@@ -198,7 +209,7 @@ public class RFXComBridgeHandler extends BaseBridgeHandler {
                 connector.connect(configuration);
 
                 logger.debug("Reset controller");
-                connector.sendMessage(RFXComMessageFactory.CMD_RESET);
+                connector.sendMessage(RFXComInterfaceMessage.CMD_RESET);
 
                 // controller does not response immediately after reset,
                 // so wait a while
@@ -207,7 +218,7 @@ public class RFXComBridgeHandler extends BaseBridgeHandler {
                 connector.addEventListener(eventListener);
 
                 logger.debug("Get status of controller");
-                connector.sendMessage(RFXComMessageFactory.CMD_GET_STATUS);
+                connector.sendMessage(RFXComInterfaceMessage.CMD_GET_STATUS);
             }
         } catch (IOException e) {
             logger.error("Connection to RFXCOM transceiver failed", e);
@@ -243,7 +254,7 @@ public class RFXComBridgeHandler extends BaseBridgeHandler {
         @Override
         public void packetReceived(byte[] packet) {
             try {
-                RFXComMessage message = RFXComMessageFactory.createMessage(packet);
+                RFXComMessage message = messageFactory.createMessage(packet);
                 logger.debug("Message received: {}", message);
 
                 if (message instanceof RFXComInterfaceMessage) {
@@ -299,7 +310,7 @@ public class RFXComBridgeHandler extends BaseBridgeHandler {
                             // regardless of whether it fails and the RFXCOM's buffer
                             // is big enough to queue up the command.
                             logger.debug("Start receiver");
-                            connector.sendMessage(RFXComMessageFactory.CMD_START_RECEIVER);
+                            connector.sendMessage(RFXComInterfaceMessage.CMD_START_RECEIVER);
                         }
                     } else if (msg.subType == SubType.START_RECEIVER) {
                         updateStatus(ThingStatus.ONLINE);
index b48741cd4800a582c3d72b2dc10b47c01018f7b2..992015902859b35a9b506427ceaeba4ca4957d6d 100644 (file)
@@ -19,15 +19,22 @@ import java.util.concurrent.ConcurrentHashMap;
 
 import org.eclipse.jdt.annotation.NonNull;
 import org.openhab.binding.rfxcom.internal.DeviceMessageListener;
+import org.openhab.binding.rfxcom.internal.RFXComBindingConstants;
 import org.openhab.binding.rfxcom.internal.config.RFXComDeviceConfiguration;
+import org.openhab.binding.rfxcom.internal.config.RFXComGenericDeviceConfiguration;
 import org.openhab.binding.rfxcom.internal.exceptions.RFXComException;
+import org.openhab.binding.rfxcom.internal.exceptions.RFXComInvalidParameterException;
+import org.openhab.binding.rfxcom.internal.exceptions.RFXComInvalidStateException;
 import org.openhab.binding.rfxcom.internal.exceptions.RFXComMessageNotImplementedException;
+import org.openhab.binding.rfxcom.internal.exceptions.RFXComUnsupportedChannelException;
 import org.openhab.binding.rfxcom.internal.messages.RFXComBaseMessage.PacketType;
 import org.openhab.binding.rfxcom.internal.messages.RFXComDeviceMessage;
 import org.openhab.binding.rfxcom.internal.messages.RFXComMessage;
 import org.openhab.binding.rfxcom.internal.messages.RFXComMessageFactory;
+import org.openhab.binding.rfxcom.internal.messages.RFXComMessageFactoryImpl;
 import org.openhab.core.library.types.DecimalType;
 import org.openhab.core.library.types.OnOffType;
+import org.openhab.core.thing.Bridge;
 import org.openhab.core.thing.Channel;
 import org.openhab.core.thing.ChannelUID;
 import org.openhab.core.thing.Thing;
@@ -58,10 +65,22 @@ public class RFXComHandler extends BaseThingHandler implements DeviceMessageList
     private final Map<String, Type> stateMap = new ConcurrentHashMap<>();
 
     private RFXComBridgeHandler bridgeHandler;
+
+    private Class<? extends RFXComDeviceConfiguration> configType;
     private RFXComDeviceConfiguration config;
 
+    private RFXComMessageFactory messageFactory;
+
     public RFXComHandler(@NonNull Thing thing) {
+        this(thing, RFXComMessageFactoryImpl.INSTANCE);
+    }
+
+    public RFXComHandler(@NonNull Thing thing, RFXComMessageFactory messageFactory) {
         super(thing);
+        this.messageFactory = messageFactory;
+
+        configType = RFXComBindingConstants.THING_TYPE_UID_CONFIGURATION_CLASS_MAP.getOrDefault(thing.getThingTypeUID(),
+                RFXComGenericDeviceConfiguration.class);
     }
 
     @Override
@@ -73,10 +92,10 @@ public class RFXComHandler extends BaseThingHandler implements DeviceMessageList
                 logger.trace("Received unsupported Refresh command");
             } else {
                 try {
-                    PacketType packetType = RFXComMessageFactory
+                    PacketType packetType = RFXComMessageFactoryImpl
                             .convertPacketType(getThing().getThingTypeUID().getId().toUpperCase());
 
-                    RFXComMessage msg = RFXComMessageFactory.createMessage(packetType);
+                    RFXComMessage msg = messageFactory.createMessage(packetType);
 
                     msg.setConfig(config);
                     msg.convertFromState(channelUID.getId(), command);
@@ -84,6 +103,10 @@ public class RFXComHandler extends BaseThingHandler implements DeviceMessageList
                     bridgeHandler.sendMessage(msg);
                 } catch (RFXComMessageNotImplementedException e) {
                     logger.error("Message not supported", e);
+                } catch (RFXComUnsupportedChannelException e) {
+                    logger.error("Channel not supported", e);
+                } catch (RFXComInvalidStateException e) {
+                    logger.error("Invalid state supplied for channel", e);
                 } catch (RFXComException e) {
                     logger.error("Transmitting error", e);
                 }
@@ -94,8 +117,14 @@ public class RFXComHandler extends BaseThingHandler implements DeviceMessageList
     @Override
     public void initialize() {
         logger.debug("Initializing thing {}", getThing().getUID());
-        initializeBridge((getBridge() == null) ? null : getBridge().getHandler(),
-                (getBridge() == null) ? null : getBridge().getStatus());
+
+        Bridge bridge = getBridge();
+
+        if (bridge == null) {
+            initializeBridge(null, null);
+        } else {
+            initializeBridge(bridge.getHandler(), bridge.getStatus());
+        }
 
         stateMap.clear();
     }
@@ -103,27 +132,36 @@ public class RFXComHandler extends BaseThingHandler implements DeviceMessageList
     @Override
     public void bridgeStatusChanged(ThingStatusInfo bridgeStatusInfo) {
         logger.debug("bridgeStatusChanged {} for thing {}", bridgeStatusInfo, getThing().getUID());
-        initializeBridge((getBridge() == null) ? null : getBridge().getHandler(), bridgeStatusInfo.getStatus());
+
+        Bridge bridge = getBridge();
+
+        if (bridge == null) {
+            initializeBridge(null, bridgeStatusInfo.getStatus());
+        } else {
+            initializeBridge(bridge.getHandler(), bridgeStatusInfo.getStatus());
+        }
     }
 
     private void initializeBridge(ThingHandler thingHandler, ThingStatus bridgeStatus) {
         logger.debug("initializeBridge {} for thing {}", bridgeStatus, getThing().getUID());
 
-        config = getConfigAs(RFXComDeviceConfiguration.class);
-        if (config.deviceId == null || config.subType == null) {
-            updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
-                    "RFXCOM device missing deviceId or subType");
-        } else if (thingHandler != null && bridgeStatus != null) {
-            bridgeHandler = (RFXComBridgeHandler) thingHandler;
-            bridgeHandler.registerDeviceStatusListener(this);
+        try {
+            config = getConfigAs(configType);
+            config.parseAndValidate();
+            if (thingHandler != null && bridgeStatus != null) {
+                bridgeHandler = (RFXComBridgeHandler) thingHandler;
+                bridgeHandler.registerDeviceStatusListener(this);
 
-            if (bridgeStatus == ThingStatus.ONLINE) {
-                updateStatus(ThingStatus.ONLINE);
+                if (bridgeStatus == ThingStatus.ONLINE) {
+                    updateStatus(ThingStatus.ONLINE);
+                } else {
+                    updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE);
+                }
             } else {
-                updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE);
+                updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_UNINITIALIZED);
             }
-        } else {
-            updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_UNINITIALIZED);
+        } catch (RFXComInvalidParameterException e) {
+            updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, e.getMessage());
         }
     }
 
@@ -140,8 +178,7 @@ public class RFXComHandler extends BaseThingHandler implements DeviceMessageList
     @Override
     public void onDeviceMessageReceived(ThingUID bridge, RFXComDeviceMessage message) {
         try {
-            String id = message.getDeviceId();
-            if (config.deviceId.equals(id)) {
+            if (config.matchesMessage(message)) {
                 String receivedId = PACKET_TYPE_THING_TYPE_UID_MAP.get(message.getPacketType()).getId();
                 logger.debug("Received message from bridge: {} message: {}", bridge, message);
 
index 593f96f43c6de81f02155682efbb6c15c62de948..ed4de3e361b439126dcc000ff08aebab1271dd13 100644 (file)
@@ -15,6 +15,7 @@ package org.openhab.binding.rfxcom.internal.messages;
 import static org.openhab.binding.rfxcom.internal.RFXComBindingConstants.CHANNEL_SIGNAL_LEVEL;
 
 import org.openhab.binding.rfxcom.internal.config.RFXComDeviceConfiguration;
+import org.openhab.binding.rfxcom.internal.config.RFXComGenericDeviceConfiguration;
 import org.openhab.binding.rfxcom.internal.exceptions.RFXComException;
 import org.openhab.binding.rfxcom.internal.exceptions.RFXComUnsupportedChannelException;
 import org.openhab.binding.rfxcom.internal.handler.DeviceState;
@@ -41,8 +42,9 @@ abstract class RFXComDeviceMessageImpl<T> extends RFXComBaseMessage implements R
 
     @Override
     public void setConfig(RFXComDeviceConfiguration config) throws RFXComException {
-        this.setSubType(convertSubType(config.subType));
-        this.setDeviceId(config.deviceId);
+        RFXComGenericDeviceConfiguration genericConfig = (RFXComGenericDeviceConfiguration) config;
+        this.setSubType(convertSubType(genericConfig.subType));
+        this.setDeviceId(genericConfig.deviceId);
     }
 
     @Override
@@ -67,8 +69,9 @@ abstract class RFXComDeviceMessageImpl<T> extends RFXComBaseMessage implements R
         String subTypeString = convertSubType(String.valueOf(subType)).toString();
         String label = getPacketType() + "-" + getDeviceId();
 
-        discoveryResultBuilder.withLabel(label).withProperty(RFXComDeviceConfiguration.DEVICE_ID_LABEL, getDeviceId())
-                .withProperty(RFXComDeviceConfiguration.SUB_TYPE_LABEL, subTypeString);
+        discoveryResultBuilder.withLabel(label)
+                .withProperty(RFXComGenericDeviceConfiguration.DEVICE_ID_LABEL, getDeviceId())
+                .withProperty(RFXComGenericDeviceConfiguration.SUB_TYPE_LABEL, subTypeString);
     }
 
     /**
index 13b89fd79be062b829bd4e3a4ac8446fa7a02cae..d225a8a595ecd06e4b285779081ae47d2c880d6e 100644 (file)
@@ -373,4 +373,32 @@ public class RFXComInterfaceMessage extends RFXComBaseMessage {
     public void convertFromState(String channelId, Type type) {
         throw new UnsupportedOperationException();
     }
+
+    /**
+     * Command to reset RFXCOM controller.
+     *
+     */
+    public static final byte[] CMD_RESET = new byte[] { 0x0D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x00, 0x00 };
+
+    /**
+     * Command to get RFXCOM controller status.
+     *
+     */
+    public static final byte[] CMD_GET_STATUS = new byte[] { 0x0D, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x00, 0x00 };
+
+    /**
+     * Command to save RFXCOM controller configuration.
+     *
+     */
+    public static final byte[] CMD_SAVE = new byte[] { 0x0D, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x00 };
+
+    /**
+     * Command to start RFXCOM receiver.
+     *
+     */
+    public static final byte[] CMD_START_RECEIVER = new byte[] { 0x0D, 0x00, 0x00, 0x03, 0x07, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x00, 0x00, 0x00 };
 }
index 97b41eb548bb71e2679d2787fe43bed5e1d2374a..20321f69175482b0ca390301897db8425ea8fb0d 100644 (file)
 package org.openhab.binding.rfxcom.internal.messages;
 
 import static org.openhab.binding.rfxcom.internal.RFXComBindingConstants.*;
-import static org.openhab.binding.rfxcom.internal.config.RFXComDeviceConfiguration.*;
+import static org.openhab.binding.rfxcom.internal.config.RFXComLighting4DeviceConfiguration.*;
 import static org.openhab.binding.rfxcom.internal.messages.ByteEnumUtil.fromByte;
 
 import org.openhab.binding.rfxcom.internal.config.RFXComDeviceConfiguration;
+import org.openhab.binding.rfxcom.internal.config.RFXComLighting4DeviceConfiguration;
 import org.openhab.binding.rfxcom.internal.exceptions.RFXComException;
 import org.openhab.binding.rfxcom.internal.exceptions.RFXComUnsupportedChannelException;
 import org.openhab.binding.rfxcom.internal.exceptions.RFXComUnsupportedValueException;
@@ -274,10 +275,11 @@ public class RFXComLighting4Message extends RFXComDeviceMessageImpl<RFXComLighti
 
     @Override
     public void setConfig(RFXComDeviceConfiguration config) throws RFXComException {
-        super.setConfig(config);
-        this.pulse = config.pulse != null ? config.pulse : 350;
-        this.onCommandId = valueOrDefault(config.onCommandId, DEFAULT_ON_COMMAND_ID);
-        this.offCommandId = valueOrDefault(config.offCommandId, DEFAULT_OFF_COMMAND_ID);
+        RFXComLighting4DeviceConfiguration lighting4Config = (RFXComLighting4DeviceConfiguration) config;
+        super.setConfig(lighting4Config);
+        this.pulse = lighting4Config.pulse != null ? lighting4Config.pulse : 350;
+        this.onCommandId = valueOrDefault(lighting4Config.onCommandId, DEFAULT_ON_COMMAND_ID);
+        this.offCommandId = valueOrDefault(lighting4Config.offCommandId, DEFAULT_OFF_COMMAND_ID);
     }
 
     private int valueOrDefault(Integer commandId, byte defaultValue) {
index 997623a67bd4a1312bc4a535de39def43a384c30..d7e4443dbc7ed154eb50e9c73c3be85c84a31bd9 100644 (file)
@@ -14,6 +14,7 @@ package org.openhab.binding.rfxcom.internal.messages;
 
 import org.openhab.binding.rfxcom.internal.config.RFXComDeviceConfiguration;
 import org.openhab.binding.rfxcom.internal.exceptions.RFXComException;
+import org.openhab.binding.rfxcom.internal.exceptions.RFXComInvalidStateException;
 import org.openhab.binding.rfxcom.internal.exceptions.RFXComUnsupportedChannelException;
 import org.openhab.core.types.Type;
 
@@ -40,8 +41,12 @@ public interface RFXComMessage {
 
     /**
      * Procedure for converting openHAB state to RFXCOM object.
+     *
+     * @throws RFXComUnsupportedChannelException If we do not support setting this channel
+     * @throws RFXComInvalidStateException If the state (type) is invalid for the channel
      */
-    void convertFromState(String channelId, Type type) throws RFXComUnsupportedChannelException;
+    void convertFromState(String channelId, Type type)
+            throws RFXComUnsupportedChannelException, RFXComInvalidStateException;
 
     /**
      * Procedure to pass configuration to a message
index 231d79aa2ad07b7b4fbb406a6a06595b6f5829c3..d555a32f58d329a9dfd24411dcee0edb43b7f71c 100644 (file)
  */
 package org.openhab.binding.rfxcom.internal.messages;
 
-import java.lang.reflect.Constructor;
-import java.lang.reflect.InvocationTargetException;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-
 import org.openhab.binding.rfxcom.internal.exceptions.RFXComException;
-import org.openhab.binding.rfxcom.internal.exceptions.RFXComMessageNotImplementedException;
 import org.openhab.binding.rfxcom.internal.messages.RFXComBaseMessage.PacketType;
 
 /**
+ * Factory to create RFXCom messages from either bytes delivered by the RFXCom device
+ * or from openhab state to transmit.
  *
  * @author Pauli Anttila - Initial contribution
+ * @author James Hewitt-Thomas - Convert to interface to allow dependency injection
  */
-public class RFXComMessageFactory {
-
-    @SuppressWarnings("serial")
-    private static final Map<PacketType, Class<? extends RFXComMessage>> MESSAGE_CLASSES = Collections
-            .unmodifiableMap(new HashMap<PacketType, Class<? extends RFXComMessage>>() {
-                {
-                    put(PacketType.INTERFACE_CONTROL, RFXComInterfaceControlMessage.class);
-                    put(PacketType.INTERFACE_MESSAGE, RFXComInterfaceMessage.class);
-                    put(PacketType.TRANSMITTER_MESSAGE, RFXComTransmitterMessage.class);
-                    put(PacketType.UNDECODED_RF_MESSAGE, RFXComUndecodedRFMessage.class);
-                    put(PacketType.LIGHTING1, RFXComLighting1Message.class);
-                    put(PacketType.LIGHTING2, RFXComLighting2Message.class);
-                    // put(PacketType.LIGHTING3, RFXComLighting3Message.class);
-                    put(PacketType.LIGHTING4, RFXComLighting4Message.class);
-                    put(PacketType.LIGHTING5, RFXComLighting5Message.class);
-                    put(PacketType.LIGHTING6, RFXComLighting6Message.class);
-                    put(PacketType.CHIME, RFXComChimeMessage.class);
-                    put(PacketType.FAN, RFXComFanMessage.class);
-                    // put(PacketType.FAN_SF01, RFXComFanMessage.class);
-                    // put(PacketType.FAN_ITHO, RFXComFanMessage.class);
-                    // put(PacketType.FAN_SEAV, RFXComFanMessage.class);
-                    put(PacketType.FAN_LUCCI_DC, RFXComFanMessage.class);
-                    // put(PacketType.FAN_FT1211R, RFXComFanMessage.class);
-                    put(PacketType.FAN_FALMEC, RFXComFanMessage.class);
-                    put(PacketType.FAN_LUCCI_DC_II, RFXComFanMessage.class);
-                    put(PacketType.FAN_NOVY, RFXComFanMessage.class);
-                    put(PacketType.CURTAIN1, RFXComCurtain1Message.class);
-                    put(PacketType.BLINDS1, RFXComBlinds1Message.class);
-                    put(PacketType.RFY, RFXComRfyMessage.class);
-                    put(PacketType.HOME_CONFORT, RFXComHomeConfortMessage.class);
-                    put(PacketType.SECURITY1, RFXComSecurity1Message.class);
-                    put(PacketType.SECURITY2, RFXComSecurity2Message.class);
-                    // put(PacketType.CAMERA1, RFXComCamera1Message.class);
-                    // put(PacketType.REMOTE_CONTROL, RFXComRemoteControlMessage.class);
-                    put(PacketType.THERMOSTAT1, RFXComThermostat1Message.class);
-                    // put(PacketType.THERMOSTAT2, RFXComThermostat2Message.class);
-                    put(PacketType.THERMOSTAT3, RFXComThermostat3Message.class);
-                    // put(PacketType.RADIATOR1, RFXComRadiator1Message.class);
-                    put(PacketType.BBQ, RFXComBBQTemperatureMessage.class);
-                    put(PacketType.TEMPERATURE_RAIN, RFXComTemperatureRainMessage.class);
-                    put(PacketType.TEMPERATURE, RFXComTemperatureMessage.class);
-                    put(PacketType.HUMIDITY, RFXComHumidityMessage.class);
-                    put(PacketType.TEMPERATURE_HUMIDITY, RFXComTemperatureHumidityMessage.class);
-                    // put(PacketType.BAROMETRIC, RFXComBarometricMessage.class);
-                    put(PacketType.TEMPERATURE_HUMIDITY_BAROMETRIC, RFXComTemperatureHumidityBarometricMessage.class);
-                    put(PacketType.RAIN, RFXComRainMessage.class);
-                    put(PacketType.WIND, RFXComWindMessage.class);
-                    put(PacketType.UV, RFXComUVMessage.class);
-                    put(PacketType.DATE_TIME, RFXComDateTimeMessage.class);
-                    put(PacketType.CURRENT, RFXComCurrentMessage.class);
-                    put(PacketType.ENERGY, RFXComEnergyMessage.class);
-                    put(PacketType.CURRENT_ENERGY, RFXComCurrentEnergyMessage.class);
-                    // put(PacketType.POWER, RFXComPowerMessage.class);
-                    // put(PacketType.WEIGHT, RFXComWeightMessage.class);
-                    // put(PacketType.GAS, RFXComGasMessage.class);
-                    // put(PacketType.WATER, RFXComWaterMessage.class);
-                    put(PacketType.RFXSENSOR, RFXComRFXSensorMessage.class);
-                    // put(PacketType.RFXMETER, RFXComRFXMeterMessage.class);
-                    // put(PacketType.FS20, RFXComFS20Message.class);
-                    put(PacketType.RAW, RFXComRawMessage.class);
-                    // put(PacketType.IO_LINES, RFXComIOLinesMessage.class);
-                }
-            });
-
-    /**
-     * Command to reset RFXCOM controller.
-     *
-     */
-    public static final byte[] CMD_RESET = new byte[] { 0x0D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-            0x00, 0x00, 0x00, 0x00 };
-
-    /**
-     * Command to get RFXCOM controller status.
-     *
-     */
-    public static final byte[] CMD_GET_STATUS = new byte[] { 0x0D, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
-            0x00, 0x00, 0x00, 0x00 };
-
-    /**
-     * Command to save RFXCOM controller configuration.
-     *
-     */
-    public static final byte[] CMD_SAVE = new byte[] { 0x0D, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-            0x00, 0x00, 0x00 };
-
-    /**
-     * Command to start RFXCOM receiver.
-     *
-     */
-    public static final byte[] CMD_START_RECEIVER = new byte[] { 0x0D, 0x00, 0x00, 0x03, 0x07, 0x00, 0x00, 0x00, 0x00,
-            0x00, 0x00, 0x00, 0x00, 0x00 };
-
-    public static RFXComMessage createMessage(PacketType packetType) throws RFXComException {
-        try {
-            Class<? extends RFXComMessage> cl = MESSAGE_CLASSES.get(packetType);
-            if (cl == null) {
-                throw new RFXComMessageNotImplementedException("Message " + packetType + " not implemented");
-            }
-            return cl.newInstance();
-        } catch (IllegalAccessException | InstantiationException e) {
-            throw new RFXComException(e);
-        }
-    }
-
-    public static RFXComMessage createMessage(byte[] packet) throws RFXComException {
-        PacketType packetType = ByteEnumUtil.fromByte(PacketType.class, packet[1]);
-
-        try {
-            Class<? extends RFXComMessage> cl = MESSAGE_CLASSES.get(packetType);
-            if (cl == null) {
-                throw new RFXComMessageNotImplementedException("Message " + packetType + " not implemented");
-            }
-            Constructor<?> c = cl.getConstructor(byte[].class);
-            return (RFXComMessage) c.newInstance(packet);
-        } catch (InvocationTargetException e) {
-            if (e.getCause() instanceof RFXComException) {
-                throw (RFXComException) e.getCause();
-            } else {
-                throw new RFXComException(e);
-            }
-        } catch (NoSuchMethodException | IllegalAccessException | InstantiationException e) {
-            throw new RFXComException(e);
-        }
-    }
-
-    public static PacketType convertPacketType(String packetType) throws IllegalArgumentException {
-        for (PacketType p : PacketType.values()) {
-            if (p.toString().replace("_", "").equals(packetType.replace("_", ""))) {
-                return p;
-            }
-        }
+public interface RFXComMessageFactory {
+    public RFXComMessage createMessage(PacketType packetType) throws RFXComException;
 
-        throw new IllegalArgumentException("Unknown packet type " + packetType);
-    }
+    public RFXComMessage createMessage(byte[] packet) throws RFXComException;
 }
diff --git a/bundles/org.openhab.binding.rfxcom/src/main/java/org/openhab/binding/rfxcom/internal/messages/RFXComMessageFactoryImpl.java b/bundles/org.openhab.binding.rfxcom/src/main/java/org/openhab/binding/rfxcom/internal/messages/RFXComMessageFactoryImpl.java
new file mode 100644 (file)
index 0000000..6098d43
--- /dev/null
@@ -0,0 +1,147 @@
+/**
+ * Copyright (c) 2010-2021 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.rfxcom.internal.messages;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.openhab.binding.rfxcom.internal.exceptions.RFXComException;
+import org.openhab.binding.rfxcom.internal.exceptions.RFXComMessageNotImplementedException;
+import org.openhab.binding.rfxcom.internal.messages.RFXComBaseMessage.PacketType;
+
+/**
+ * Factory to create RFXCom messages from either bytes delivered by the RFXCom device
+ * or from openhab state to transmit.
+ *
+ * @author Pauli Anttila - Initial contribution
+ * @author James Hewitt-Thomas - Use the enum singleton pattern to allow dependency injection
+ */
+public enum RFXComMessageFactoryImpl implements RFXComMessageFactory {
+    INSTANCE();
+
+    @SuppressWarnings("serial")
+    private static final Map<PacketType, Class<? extends RFXComMessage>> MESSAGE_CLASSES = Collections
+            .unmodifiableMap(new HashMap<PacketType, Class<? extends RFXComMessage>>() {
+                {
+                    put(PacketType.INTERFACE_CONTROL, RFXComInterfaceControlMessage.class);
+                    put(PacketType.INTERFACE_MESSAGE, RFXComInterfaceMessage.class);
+                    put(PacketType.TRANSMITTER_MESSAGE, RFXComTransmitterMessage.class);
+                    put(PacketType.UNDECODED_RF_MESSAGE, RFXComUndecodedRFMessage.class);
+                    put(PacketType.LIGHTING1, RFXComLighting1Message.class);
+                    put(PacketType.LIGHTING2, RFXComLighting2Message.class);
+                    // put(PacketType.LIGHTING3, RFXComLighting3Message.class);
+                    put(PacketType.LIGHTING4, RFXComLighting4Message.class);
+                    put(PacketType.LIGHTING5, RFXComLighting5Message.class);
+                    put(PacketType.LIGHTING6, RFXComLighting6Message.class);
+                    put(PacketType.CHIME, RFXComChimeMessage.class);
+                    put(PacketType.FAN, RFXComFanMessage.class);
+                    // put(PacketType.FAN_SF01, RFXComFanMessage.class);
+                    // put(PacketType.FAN_ITHO, RFXComFanMessage.class);
+                    // put(PacketType.FAN_SEAV, RFXComFanMessage.class);
+                    put(PacketType.FAN_LUCCI_DC, RFXComFanMessage.class);
+                    // put(PacketType.FAN_FT1211R, RFXComFanMessage.class);
+                    put(PacketType.FAN_FALMEC, RFXComFanMessage.class);
+                    put(PacketType.FAN_LUCCI_DC_II, RFXComFanMessage.class);
+                    put(PacketType.FAN_NOVY, RFXComFanMessage.class);
+                    put(PacketType.CURTAIN1, RFXComCurtain1Message.class);
+                    put(PacketType.BLINDS1, RFXComBlinds1Message.class);
+                    put(PacketType.RFY, RFXComRfyMessage.class);
+                    put(PacketType.HOME_CONFORT, RFXComHomeConfortMessage.class);
+                    put(PacketType.SECURITY1, RFXComSecurity1Message.class);
+                    put(PacketType.SECURITY2, RFXComSecurity2Message.class);
+                    // put(PacketType.CAMERA1, RFXComCamera1Message.class);
+                    // put(PacketType.REMOTE_CONTROL, RFXComRemoteControlMessage.class);
+                    put(PacketType.THERMOSTAT1, RFXComThermostat1Message.class);
+                    // put(PacketType.THERMOSTAT2, RFXComThermostat2Message.class);
+                    put(PacketType.THERMOSTAT3, RFXComThermostat3Message.class);
+                    // put(PacketType.RADIATOR1, RFXComRadiator1Message.class);
+                    put(PacketType.BBQ, RFXComBBQTemperatureMessage.class);
+                    put(PacketType.TEMPERATURE_RAIN, RFXComTemperatureRainMessage.class);
+                    put(PacketType.TEMPERATURE, RFXComTemperatureMessage.class);
+                    put(PacketType.HUMIDITY, RFXComHumidityMessage.class);
+                    put(PacketType.TEMPERATURE_HUMIDITY, RFXComTemperatureHumidityMessage.class);
+                    // put(PacketType.BAROMETRIC, RFXComBarometricMessage.class);
+                    put(PacketType.TEMPERATURE_HUMIDITY_BAROMETRIC, RFXComTemperatureHumidityBarometricMessage.class);
+                    put(PacketType.RAIN, RFXComRainMessage.class);
+                    put(PacketType.WIND, RFXComWindMessage.class);
+                    put(PacketType.UV, RFXComUVMessage.class);
+                    put(PacketType.DATE_TIME, RFXComDateTimeMessage.class);
+                    put(PacketType.CURRENT, RFXComCurrentMessage.class);
+                    put(PacketType.ENERGY, RFXComEnergyMessage.class);
+                    put(PacketType.CURRENT_ENERGY, RFXComCurrentEnergyMessage.class);
+                    // put(PacketType.POWER, RFXComPowerMessage.class);
+                    // put(PacketType.WEIGHT, RFXComWeightMessage.class);
+                    // put(PacketType.GAS, RFXComGasMessage.class);
+                    // put(PacketType.WATER, RFXComWaterMessage.class);
+                    put(PacketType.RFXSENSOR, RFXComRFXSensorMessage.class);
+                    // put(PacketType.RFXMETER, RFXComRFXMeterMessage.class);
+                    // put(PacketType.FS20, RFXComFS20Message.class);
+                    put(PacketType.RAW, RFXComRawMessage.class);
+                    // put(PacketType.IO_LINES, RFXComIOLinesMessage.class);
+                }
+            });
+
+    /**
+     * Create message for transmission from the packet type associated with the thing.
+     */
+    @Override
+    public RFXComMessage createMessage(PacketType packetType) throws RFXComException {
+        try {
+            Class<? extends RFXComMessage> cl = MESSAGE_CLASSES.get(packetType);
+            if (cl == null) {
+                throw new RFXComMessageNotImplementedException("Message " + packetType + " not implemented");
+            }
+            return cl.getDeclaredConstructor().newInstance();
+        } catch (ReflectiveOperationException e) {
+            throw new RFXComException(e);
+        }
+    }
+
+    /**
+     * Create message from received bytes.
+     */
+    @Override
+    public RFXComMessage createMessage(byte[] packet) throws RFXComException {
+        PacketType packetType = ByteEnumUtil.fromByte(PacketType.class, packet[1]);
+
+        try {
+            Class<? extends RFXComMessage> cl = MESSAGE_CLASSES.get(packetType);
+            if (cl == null) {
+                throw new RFXComMessageNotImplementedException("Message " + packetType + " not implemented");
+            }
+            Constructor<?> c = cl.getConstructor(byte[].class);
+            return (RFXComMessage) c.newInstance(packet);
+        } catch (InvocationTargetException e) {
+            if (e.getCause() instanceof RFXComException) {
+                throw (RFXComException) e.getCause();
+            } else {
+                throw new RFXComException(e);
+            }
+        } catch (NoSuchMethodException | IllegalAccessException | InstantiationException e) {
+            throw new RFXComException(e);
+        }
+    }
+
+    public static PacketType convertPacketType(String packetType) throws IllegalArgumentException {
+        for (PacketType p : PacketType.values()) {
+            if (p.toString().replace("_", "").equals(packetType.replace("_", ""))) {
+                return p;
+            }
+        }
+
+        throw new IllegalArgumentException("Unknown packet type " + packetType);
+    }
+}
index c4f1ed56129c131d086c5e40d9b26cc0edcd4c9d..1aa27620be3bfe0018612211a43a7594e8add1d2 100644 (file)
@@ -16,12 +16,19 @@ import static org.openhab.binding.rfxcom.internal.RFXComBindingConstants.*;
 import static org.openhab.binding.rfxcom.internal.messages.RFXComBaseMessage.PacketType.RAW;
 
 import java.nio.ByteBuffer;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
 
+import org.openhab.binding.rfxcom.internal.config.RFXComDeviceConfiguration;
+import org.openhab.binding.rfxcom.internal.config.RFXComRawDeviceConfiguration;
 import org.openhab.binding.rfxcom.internal.exceptions.RFXComException;
+import org.openhab.binding.rfxcom.internal.exceptions.RFXComInvalidStateException;
 import org.openhab.binding.rfxcom.internal.exceptions.RFXComMessageTooLongException;
 import org.openhab.binding.rfxcom.internal.exceptions.RFXComUnsupportedChannelException;
 import org.openhab.binding.rfxcom.internal.exceptions.RFXComUnsupportedValueException;
 import org.openhab.binding.rfxcom.internal.handler.DeviceState;
+import org.openhab.core.library.types.OnOffType;
+import org.openhab.core.library.types.OpenClosedType;
 import org.openhab.core.library.types.StringType;
 import org.openhab.core.types.State;
 import org.openhab.core.types.Type;
@@ -68,6 +75,8 @@ public class RFXComRawMessage extends RFXComDeviceMessageImpl<RFXComRawMessage.S
     public byte repeat;
     public short[] pulses;
 
+    private RFXComRawDeviceConfiguration config;
+
     public RFXComRawMessage() {
         super(RAW);
         pulses = new short[0];
@@ -114,7 +123,7 @@ public class RFXComRawMessage extends RFXComDeviceMessageImpl<RFXComRawMessage.S
         data[1] = RAW.toByte();
         data[2] = subType.toByte();
         data[3] = seqNbr;
-        data[4] = repeat;
+        data[4] = (byte) config.repeat;
 
         ByteBuffer.wrap(data, 5, pulsesByteLen).asShortBuffer().put(pulses);
 
@@ -126,6 +135,12 @@ public class RFXComRawMessage extends RFXComDeviceMessageImpl<RFXComRawMessage.S
         return "RAW";
     }
 
+    @Override
+    public void setConfig(RFXComDeviceConfiguration config) throws RFXComException {
+        super.setConfig(config);
+        this.config = (RFXComRawDeviceConfiguration) config;
+    }
+
     @Override
     public State convertToState(String channelId, DeviceState deviceState) throws RFXComUnsupportedChannelException {
         switch (channelId) {
@@ -137,6 +152,11 @@ public class RFXComRawMessage extends RFXComDeviceMessageImpl<RFXComRawMessage.S
                 ByteBuffer.wrap(payload).asShortBuffer().put(pulses);
                 return new StringType(HexUtils.bytesToHex(payload));
 
+            case CHANNEL_PULSES:
+                return new StringType(IntStream.range(0, pulses.length)
+                        .mapToObj(s -> Integer.toString(Short.toUnsignedInt(pulses[s])))
+                        .collect(Collectors.joining(" ")));
+
             default:
                 throw new RFXComUnsupportedChannelException("Nothing relevant for " + channelId);
         }
@@ -144,34 +164,47 @@ public class RFXComRawMessage extends RFXComDeviceMessageImpl<RFXComRawMessage.S
 
     @Override
     public void setSubType(SubType subType) {
-        throw new UnsupportedOperationException();
+        this.subType = subType;
     }
 
     @Override
     public void setDeviceId(String deviceId) {
-        throw new UnsupportedOperationException();
+        // Nothing to do here
     }
 
     @Override
-    public void convertFromState(String channelId, Type type) throws RFXComUnsupportedChannelException {
+    public void convertFromState(String channelId, Type type)
+            throws RFXComUnsupportedChannelException, RFXComInvalidStateException {
         switch (channelId) {
             case CHANNEL_RAW_MESSAGE:
-                if (type instanceof StringType) {
-                    // TODO: Check the raw message for validity (length, no more than 124 shorts, multiple of 4 bytes in
-                    // payload)
-                    throw new RFXComUnsupportedChannelException("Channel " + channelId + " inot yet implemented");
+            case CHANNEL_RAW_PAYLOAD:
+            case CHANNEL_PULSES:
+                throw new RFXComUnsupportedChannelException("Cannot send on channel " + channelId);
+
+            case CHANNEL_COMMAND:
+                if (type instanceof OnOffType) {
+                    if (type == OnOffType.ON) {
+                        this.pulses = config.onPulsesArray;
+                    } else {
+                        this.pulses = config.offPulsesArray;
+                    }
+                } else if (type instanceof OpenClosedType) {
+                    if (type == OpenClosedType.OPEN) {
+                        this.pulses = config.openPulsesArray;
+                    } else {
+                        this.pulses = config.closedPulsesArray;
+                    }
                 } else {
                     throw new RFXComUnsupportedChannelException("Channel " + channelId + " does not accept " + type);
                 }
 
-            case CHANNEL_RAW_PAYLOAD:
-                if (type instanceof StringType) {
-                    // TODO: Check the payload for validity (no more than 124 shorts, multiple of 4 bytes
-                    throw new RFXComUnsupportedChannelException("Channel " + channelId + " not yet implemented");
-                } else {
-                    throw new RFXComUnsupportedChannelException("Channel " + channelId + " does not accept " + type);
+                if (this.pulses == null) {
+                    throw new RFXComInvalidStateException(channelId, null,
+                            "No pulses provided in the device configuration for command" + type);
                 }
 
+                break;
+
             default:
                 throw new RFXComUnsupportedChannelException("Channel " + channelId + " is not relevant here");
         }
index 3707b8d7f50790d2cbe5e70dcf25ee3ade86612a..e7eb71502f2630d73626d03b078c18e9f37e6e51 100644 (file)
                <description>Hexadecimal representation of payload of raw and undecoded RFXCOM messages</description>
        </channel-type>
 
+       <channel-type id="pulses">
+               <item-type>String</item-type>
+               <label>Pulses</label>
+               <description>Decimal representation of the pulse lengths for a raw message in usec.</description>
+       </channel-type>
+
        <channel-type id="command">
                <item-type>Switch</item-type>
                <label>Command</label>
index 52618f3d11529d914f35578ec75ef49179fbab47..718bc35b19e2a4a3798ae683e96de21569a2ff72 100644 (file)
                <channels>
                        <channel id="rawMessage" typeId="rawmessage"/>
                        <channel id="rawPayload" typeId="rawpayload"/>
+                       <channel id="pulses" typeId="pulses"/>
+                       <channel id="command" typeId="command"/>
                </channels>
 
                <config-description>
                        <parameter name="deviceId" type="text" required="true">
                                <label>Device Id</label>
-                               <description>Raw items cannot provide a device ID, so this value is always RAW.</description>
+                               <description>Received raw message cannot provide a device ID, so to receive raw messages the device id must be RAW.
+                                       For transmit-only things, use any device id.</description>
                        </parameter>
                        <parameter name="subType" type="text" required="true">
                                <label>Sub Type</label>
                                        <option value="RAW_PACKET4">RAW_PACKET4</option>
                                </options>
                        </parameter>
+                       <parameter name="repeat" type="integer" min="1" max="255">
+                               <label>Repeat</label>
+                               <description>Number of times to repeat. Defaults to 5.</description>
+                               <default>5</default>
+                       </parameter>
+                       <parameter name="onPulses" type="text" required="false">
+                               <label>On Pulses</label>
+                               <description>Pulses to send for an ON command. Space delimited pulse lengths in usec. Must be an even number of
+                                       pulse lengths, with a maximum of 142 total pulses. Max pulse length is 65535. Pulses of value 0 will be transmitted
+                                       as 10000. See the RFXtfx user guide for more information.</description>
+                       </parameter>
+                       <parameter name="offPulses" type="text" required="false">
+                               <label>Off Pulses</label>
+                               <description>Pulses to send for an OFF command. Space delimited pulse lengths in usec. Must be an even number of
+                                       pulse lengths, with a maximum of 142 total pulses. Max pulse length is 65535. Pulses of value 0 will be transmitted
+                                       as 10000. See the RFXtfx user guide for more information.</description>
+                       </parameter>
+                       <parameter name="openPulses" type="text" required="false">
+                               <label>Open Pulses</label>
+                               <description>Pulses to send for an OPEN command. Space delimited pulse lengths in usec. Must be an even number of
+                                       pulse lengths, with a maximum of 142 total pulses. Max pulse length is 65535. Pulses of value 0 will be transmitted
+                                       as 10000. See the RFXtfx user guide for more information.</description>
+                       </parameter>
+                       <parameter name="closedPulses" type="text" required="false">
+                               <label>Closed Pulses</label>
+                               <description>Pulses to send for an CLOSED command. Space delimited pulse lengths in usec. Must be an even number of
+                                       pulse lengths, with a maximum of 142 total pulses. Max pulse length is 65535. Pulses of value 0 will be transmitted
+                                       as 10000. See the RFXtfx user guide for more information.</description>
+                       </parameter>
                </config-description>
        </thing-type>
 
diff --git a/bundles/org.openhab.binding.rfxcom/src/test/java/org/openhab/binding/rfxcom/internal/config/RFXComDeviceConfigurationBuilder.java b/bundles/org.openhab.binding.rfxcom/src/test/java/org/openhab/binding/rfxcom/internal/config/RFXComDeviceConfigurationBuilder.java
deleted file mode 100644 (file)
index 7053acf..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-/**
- * Copyright (c) 2010-2021 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.rfxcom.internal.config;
-
-/**
- * Test helper for RFXCom-binding
- *
- * @author Martin van Wingerden - Initial contribution
- */
-public class RFXComDeviceConfigurationBuilder {
-    private final RFXComDeviceConfiguration config;
-
-    public RFXComDeviceConfigurationBuilder() {
-        config = new RFXComDeviceConfiguration();
-    }
-
-    public RFXComDeviceConfigurationBuilder withDeviceId(String deviceId) {
-        config.deviceId = deviceId;
-        return this;
-    }
-
-    public RFXComDeviceConfigurationBuilder withSubType(String subType) {
-        config.subType = subType;
-        return this;
-    }
-
-    public RFXComDeviceConfigurationBuilder withPulse(Integer pulse) {
-        config.pulse = pulse;
-        return this;
-    }
-
-    public RFXComDeviceConfiguration build() {
-        return config;
-    }
-}
diff --git a/bundles/org.openhab.binding.rfxcom/src/test/java/org/openhab/binding/rfxcom/internal/config/RFXComGenericDeviceConfigurationTest.java b/bundles/org.openhab.binding.rfxcom/src/test/java/org/openhab/binding/rfxcom/internal/config/RFXComGenericDeviceConfigurationTest.java
new file mode 100644 (file)
index 0000000..fe9b13d
--- /dev/null
@@ -0,0 +1,56 @@
+/**
+ * Copyright (c) 2010-2021 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.rfxcom.internal.config;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.junit.jupiter.MockitoExtension;
+import org.openhab.binding.rfxcom.internal.exceptions.RFXComInvalidParameterException;
+
+/**
+ * Configuration class for generic devices.
+ *
+ * @author James Hewitt-Thomas - Initial contribution
+ */
+@ExtendWith(MockitoExtension.class)
+public class RFXComGenericDeviceConfigurationTest {
+
+    private RFXComGenericDeviceConfiguration config;
+
+    @BeforeEach
+    public void before() {
+        config = new RFXComGenericDeviceConfiguration();
+    }
+
+    @Test
+    public void testNoDeviceId() {
+        config.subType = "PT2262";
+        assertThrows(RFXComInvalidParameterException.class, () -> config.parseAndValidate());
+    }
+
+    @Test
+    public void testNoSubType() {
+        config.deviceId = "90000";
+        assertThrows(RFXComInvalidParameterException.class, () -> config.parseAndValidate());
+    }
+
+    @Test
+    public void testValidConfig() {
+        config.deviceId = "90000";
+        config.subType = "PT2262";
+        assertDoesNotThrow(() -> config.parseAndValidate());
+    }
+}
diff --git a/bundles/org.openhab.binding.rfxcom/src/test/java/org/openhab/binding/rfxcom/internal/config/RFXComLighting4DeviceConfigurationTest.java b/bundles/org.openhab.binding.rfxcom/src/test/java/org/openhab/binding/rfxcom/internal/config/RFXComLighting4DeviceConfigurationTest.java
new file mode 100644 (file)
index 0000000..97d5676
--- /dev/null
@@ -0,0 +1,43 @@
+/**
+ * Copyright (c) 2010-2021 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.rfxcom.internal.config;
+
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+/**
+ * Configuration class for Lighting 4 devices.
+ *
+ * @author James Hewitt-Thomas - Initial contribution
+ */
+@ExtendWith(MockitoExtension.class)
+public class RFXComLighting4DeviceConfigurationTest {
+
+    private RFXComLighting4DeviceConfiguration config;
+
+    @BeforeEach
+    public void before() {
+        config = new RFXComLighting4DeviceConfiguration();
+        config.deviceId = "90000";
+        config.subType = "PT2262";
+    }
+
+    @Test
+    public void testConfig() {
+        assertDoesNotThrow(() -> config.parseAndValidate());
+    }
+}
diff --git a/bundles/org.openhab.binding.rfxcom/src/test/java/org/openhab/binding/rfxcom/internal/config/RFXComRawDeviceConfigurationTest.java b/bundles/org.openhab.binding.rfxcom/src/test/java/org/openhab/binding/rfxcom/internal/config/RFXComRawDeviceConfigurationTest.java
new file mode 100644 (file)
index 0000000..de866c0
--- /dev/null
@@ -0,0 +1,79 @@
+/**
+ * Copyright (c) 2010-2021 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.rfxcom.internal.config;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.junit.jupiter.MockitoExtension;
+import org.openhab.binding.rfxcom.internal.exceptions.RFXComInvalidParameterException;
+
+/**
+ * Configuration class for Raw devices.
+ *
+ * @author James Hewitt-Thomas - Initial contribution
+ */
+@ExtendWith(MockitoExtension.class)
+public class RFXComRawDeviceConfigurationTest {
+
+    private RFXComRawDeviceConfiguration config;
+
+    @BeforeEach
+    public void before() {
+        config = new RFXComRawDeviceConfiguration();
+        config.deviceId = "RAW";
+        config.subType = "RAW_PACKET1";
+    }
+
+    @Test
+    public void testConfigWithoutPulses() {
+        assertDoesNotThrow(() -> config.parseAndValidate());
+    }
+
+    @Test
+    public void testConfigWithUnevenPulses() {
+        config.onPulses = "100 200 300";
+        assertThrows(RFXComInvalidParameterException.class, () -> config.parseAndValidate());
+    }
+
+    @Test
+    public void testConfigWithTooManyPulses() {
+        String pulses = IntStream.range(1, 126).mapToObj(Integer::toString).collect(Collectors.joining(" "));
+        config.offPulses = pulses;
+        assertThrows(RFXComInvalidParameterException.class, () -> config.parseAndValidate());
+    }
+
+    @Test
+    public void testConfigWithTooLargePulse() {
+        config.openPulses = "100000 200000";
+        assertThrows(RFXComInvalidParameterException.class, () -> config.parseAndValidate());
+    }
+
+    @Test
+    public void testConfigWithNaN() {
+        config.closedPulses = "abc def";
+        assertThrows(RFXComInvalidParameterException.class, () -> config.parseAndValidate());
+    }
+
+    @Test
+    public void testConfigWithValidPulses() {
+        config.onPulses = "100 200 300 400";
+        config.offPulses = "500 600 700 800";
+        assertDoesNotThrow(() -> config.parseAndValidate());
+    }
+}
diff --git a/bundles/org.openhab.binding.rfxcom/src/test/java/org/openhab/binding/rfxcom/internal/handler/RFXComHandlerTest.java b/bundles/org.openhab.binding.rfxcom/src/test/java/org/openhab/binding/rfxcom/internal/handler/RFXComHandlerTest.java
new file mode 100644 (file)
index 0000000..238f1a3
--- /dev/null
@@ -0,0 +1,189 @@
+/**
+ * Copyright (c) 2010-2021 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.rfxcom.internal.handler;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.mockito.ArgumentMatchers.*;
+import static org.mockito.Mockito.*;
+
+import java.util.Map;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+import org.openhab.binding.rfxcom.internal.config.RFXComDeviceConfiguration;
+import org.openhab.binding.rfxcom.internal.config.RFXComGenericDeviceConfiguration;
+import org.openhab.binding.rfxcom.internal.config.RFXComRawDeviceConfiguration;
+import org.openhab.binding.rfxcom.internal.exceptions.RFXComException;
+import org.openhab.binding.rfxcom.internal.messages.RFXComBaseMessage.PacketType;
+import org.openhab.binding.rfxcom.internal.messages.RFXComDeviceMessage;
+import org.openhab.binding.rfxcom.internal.messages.RFXComMessage;
+import org.openhab.binding.rfxcom.internal.messages.RFXComMessageFactory;
+import org.openhab.core.config.core.Configuration;
+import org.openhab.core.library.types.OnOffType;
+import org.openhab.core.thing.Bridge;
+import org.openhab.core.thing.ChannelUID;
+import org.openhab.core.thing.Thing;
+import org.openhab.core.thing.ThingStatus;
+import org.openhab.core.thing.ThingStatusDetail;
+import org.openhab.core.thing.ThingStatusInfo;
+import org.openhab.core.thing.ThingTypeUID;
+import org.openhab.core.thing.ThingUID;
+import org.openhab.core.thing.binding.ThingHandlerCallback;
+import org.openhab.core.types.Command;
+
+/**
+ * The {@link RFXComRawHandler} is responsible for extra validation for Raw things.
+ *
+ * @author James Hewitt-Thomas - Initial contribution
+ */
+@ExtendWith(MockitoExtension.class)
+public class RFXComHandlerTest {
+
+    static ThingUID bridgeUID = new ThingUID("rfxcom", "tcpbridge", "rfxtrx0");
+    static ThingUID thingUID = new ThingUID("rfxcom", bridgeUID, "mocked");
+    static ThingTypeUID thingTypeUID = new ThingTypeUID("rfxcom", "raw");
+
+    @Mock
+    Bridge bridge;
+
+    @Mock
+    RFXComBridgeHandler bridgeHandler;
+
+    @Mock
+    Thing thing;
+
+    @Mock
+    ThingHandlerCallback callback;
+
+    @Mock
+    RFXComMessageFactory messageFactory;
+
+    @Mock
+    RFXComMessage message;
+
+    @Captor
+    ArgumentCaptor<ThingStatusInfo> thingStatusInfoCaptor;
+
+    @Captor
+    ArgumentCaptor<RFXComGenericDeviceConfiguration> deviceConfigurationCaptor;
+
+    @Captor
+    ArgumentCaptor<RFXComDeviceMessage> deviceMessageCaptor;
+
+    RFXComHandler handler;
+
+    private void initBridge() {
+        when(bridge.getHandler()).thenReturn(bridgeHandler);
+        when(thing.getBridgeUID()).thenReturn(bridgeUID);
+        when(callback.getBridge(bridgeUID)).thenReturn(bridge);
+    }
+
+    private void initOfflineBridge() {
+        initBridge();
+
+        when(bridge.getStatus()).thenReturn(ThingStatus.OFFLINE);
+    }
+
+    private void initOnlineBridge() {
+        initBridge();
+
+        when(bridge.getStatus()).thenReturn(ThingStatus.ONLINE);
+    }
+
+    private void verifyStatusUpdated(ThingStatus status, ThingStatusDetail thingStatusDetail) {
+        verify(callback).statusUpdated(eq(thing), thingStatusInfoCaptor.capture());
+        ThingStatusInfo tsi = thingStatusInfoCaptor.getValue();
+        assertEquals(status, tsi.getStatus());
+        assertEquals(thingStatusDetail, tsi.getStatusDetail());
+    }
+
+    private RFXComGenericDeviceConfiguration sendMessageToGetConfig(String channel, Command command)
+            throws RFXComException {
+        when(messageFactory.createMessage(any(PacketType.class))).thenReturn(message);
+        ChannelUID cuid = new ChannelUID(thing.getUID(), channel);
+        handler.handleCommand(cuid, command);
+        verify(message).setConfig(deviceConfigurationCaptor.capture());
+        return deviceConfigurationCaptor.getValue();
+    }
+
+    @BeforeEach
+    public void before() {
+        when(thing.getUID()).thenReturn(thingUID);
+        when(thing.getThingTypeUID()).thenReturn(thingTypeUID);
+
+        handler = new RFXComHandler(thing, messageFactory);
+        handler.setCallback(callback);
+    }
+
+    @Test
+    public void testValidConfig() {
+        initOnlineBridge();
+        when(thing.getConfiguration()).thenReturn(new Configuration(Map.of("deviceId", "1088338.11", "subType", "AC")));
+
+        handler.initialize();
+        verifyStatusUpdated(ThingStatus.ONLINE, ThingStatusDetail.NONE);
+    }
+
+    @Test
+    public void testInvalidConfig() {
+        initOnlineBridge();
+        when(thing.getConfiguration()).thenReturn(new Configuration(Map.of()));
+
+        handler.initialize();
+        verifyStatusUpdated(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR);
+    }
+
+    @Test
+    public void testOfflineBridge() {
+        initOfflineBridge();
+        when(thing.getConfiguration()).thenReturn(new Configuration(Map.of("deviceId", "1088338.11", "subType", "AC")));
+
+        handler.initialize();
+        verifyStatusUpdated(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE);
+    }
+
+    @Test
+    public void testUnititialisedBridge() {
+        initBridge();
+        when(thing.getConfiguration())
+                .thenReturn(new Configuration(Map.of("deviceId", "RAW", "subType", "RAW_PACKET1")));
+
+        handler.initialize();
+        verifyStatusUpdated(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_UNINITIALIZED);
+    }
+
+    @Test
+    public void testWithoutBridge() {
+        when(thing.getConfiguration()).thenReturn(new Configuration(Map.of("deviceId", "1088338.11", "subType", "AC")));
+
+        handler.initialize();
+        verifyStatusUpdated(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_UNINITIALIZED);
+    }
+
+    @Test
+    public void testConfigType() throws RFXComException {
+        initOnlineBridge();
+        when(thing.getConfiguration()).thenReturn(
+                new Configuration(Map.of("deviceId", "RAW", "subType", "RAW_PACKET1", "onPulses", "1 2 3 4")));
+
+        handler.initialize();
+        verifyStatusUpdated(ThingStatus.ONLINE, ThingStatusDetail.NONE);
+        RFXComDeviceConfiguration config = sendMessageToGetConfig("command", OnOffType.ON);
+        assertEquals(RFXComRawDeviceConfiguration.class, config.getClass());
+    }
+}
index 89f04579367cd48ca0d03e69ddef6cbd7e472e6f..f05d7a92176958737d8c275fb46babea187fae0f 100644 (file)
@@ -31,7 +31,8 @@ public class RFXComBBQTemperatureMessageTest {
     public void testSomeMessages() throws RFXComException {
         String hexMessage = "0A4E012B2955001A002179";
         byte[] message = HexUtils.hexToBytes(hexMessage);
-        RFXComBBQTemperatureMessage msg = (RFXComBBQTemperatureMessage) RFXComMessageFactory.createMessage(message);
+        RFXComBBQTemperatureMessage msg = (RFXComBBQTemperatureMessage) RFXComMessageFactoryImpl.INSTANCE
+                .createMessage(message);
         assertEquals(BBQ1, msg.subType, "SubType");
         assertEquals(43, msg.seqNbr, "Seq Number");
         assertEquals("10581", msg.getDeviceId(), "Sensor Id");
index 0011bf9e2266a0e8485c25008be85ad1b99a5f1d..4c07f477cef837e542eb05b2e21b36311e7b53d8 100644 (file)
@@ -29,6 +29,6 @@ public class RFXComBarometricMessageTest {
     @Test
     public void checkNotImplemented() {
         assertThrows(RFXComMessageNotImplementedException.class,
-                () -> RFXComMessageFactory.createMessage(PacketType.BAROMETRIC));
+                () -> RFXComMessageFactoryImpl.INSTANCE.createMessage(PacketType.BAROMETRIC));
     }
 }
index e144ff0dbafbb360ea69d45734f09c6168758d92..74e606ca9a41b6e2a0b53e6c08c2f3b69dd01c11 100644 (file)
@@ -30,7 +30,7 @@ import org.openhab.core.util.HexUtils;
 public class RFXComBlinds1MessageTest {
     private void testMessage(String hexMsg, SubType subType, int seqNbr, String deviceId, int signalLevel,
             RFXComBlinds1Message.Commands command) throws RFXComException {
-        final RFXComBlinds1Message msg = (RFXComBlinds1Message) RFXComMessageFactory
+        final RFXComBlinds1Message msg = (RFXComBlinds1Message) RFXComMessageFactoryImpl.INSTANCE
                 .createMessage(HexUtils.hexToBytes(hexMsg));
         assertEquals(subType, msg.subType, "SubType");
         assertEquals(seqNbr, (short) (msg.seqNbr & 0xFF), "Seq Number");
index 5970c88285458f77ae9d158f177e855d6329168f..97f8b23241b5f8f5723a6d4d3990c51d5e4aa1cc 100644 (file)
@@ -29,6 +29,6 @@ public class RFXComCamera1MessageTest {
     @Test
     public void checkNotImplemented() {
         assertThrows(RFXComMessageNotImplementedException.class,
-                () -> RFXComMessageFactory.createMessage(PacketType.CAMERA1));
+                () -> RFXComMessageFactoryImpl.INSTANCE.createMessage(PacketType.CAMERA1));
     }
 }
index e5e0d947cc6194a65cb41abf9361f44e58f077bb..aac0556c48634a7eff0b61f131c59e9d04c55fda 100644 (file)
@@ -33,7 +33,7 @@ public class RFXComChimeMessageTest {
     public void testSomeMessages() throws RFXComException {
         String hexMessage = "0716020900A1F350";
         byte[] message = HexUtils.hexToBytes(hexMessage);
-        RFXComChimeMessage msg = (RFXComChimeMessage) RFXComMessageFactory.createMessage(message);
+        RFXComChimeMessage msg = (RFXComChimeMessage) RFXComMessageFactoryImpl.INSTANCE.createMessage(message);
         assertEquals(SubType.SELECTPLUS, msg.subType, "SubType");
         assertEquals(9, msg.seqNbr, "Seq Number");
         assertEquals("41459", msg.getDeviceId(), "Sensor Id");
index a28d7ae7921306209f35468cb116852aea267852..c3a89cf671c71cb62ba01941ad50691c5fb9788f 100644 (file)
@@ -29,7 +29,7 @@ public class RFXComCurrentEnergyMessageTest {
     private void testMessage(String hexMsg, RFXComCurrentEnergyMessage.SubType subType, int seqNbr, String deviceId,
             int count, double channel1, double channel2, double channel3, double totalUsage, int signalLevel,
             int batteryLevel) throws RFXComException {
-        final RFXComCurrentEnergyMessage msg = (RFXComCurrentEnergyMessage) RFXComMessageFactory
+        final RFXComCurrentEnergyMessage msg = (RFXComCurrentEnergyMessage) RFXComMessageFactoryImpl.INSTANCE
                 .createMessage(HexUtils.hexToBytes(hexMsg));
         assertEquals(subType, msg.subType, "SubType");
         assertEquals(seqNbr, (short) (msg.seqNbr & 0xFF), "Seq Number");
index fa4febf71683467b80de3905311857ae61a1147e..54299f7bd61cd2bdb521fbf04940d397eba43ad6 100644 (file)
@@ -32,7 +32,7 @@ public class RFXComCurrentMessageTest {
     public void testSomeMessages() throws RFXComException {
         String message = "0D59010F860004001D0000000049";
 
-        final RFXComCurrentMessage msg = (RFXComCurrentMessage) RFXComMessageFactory
+        final RFXComCurrentMessage msg = (RFXComCurrentMessage) RFXComMessageFactoryImpl.INSTANCE
                 .createMessage(HexUtils.hexToBytes(message));
         assertEquals(SubType.ELEC1, msg.subType, "SubType");
         assertEquals(15, (short) (msg.seqNbr & 0xFF), "Seq Number");
index 30347bd56ed1a09caec8819ca64c79421eaeac62..83ef0d5542b4f913bbf2fe229d1306ea3a818a1a 100644 (file)
@@ -27,12 +27,13 @@ import org.openhab.binding.rfxcom.internal.exceptions.RFXComException;
 public class RFXComCurtain1MessageTest {
     @Test
     public void checkForSupportTest() throws RFXComException {
-        RFXComMessageFactory.createMessage(CURTAIN1);
+        RFXComMessageFactoryImpl.INSTANCE.createMessage(CURTAIN1);
     }
 
     @Test
     public void basicBoundaryCheck() throws RFXComException {
-        RFXComCurtain1Message message = (RFXComCurtain1Message) RFXComMessageFactory.createMessage(CURTAIN1);
+        RFXComCurtain1Message message = (RFXComCurtain1Message) RFXComMessageFactoryImpl.INSTANCE
+                .createMessage(CURTAIN1);
 
         message.subType = RFXComCurtain1Message.SubType.HARRISON;
         message.command = RFXComCurtain1Message.Commands.OPEN;
index 9a469a929b4ee3d271e4fb422d7b0a7980757f88..151458ec2dad8e299d3b299f8f92647c833d23db 100644 (file)
@@ -32,7 +32,7 @@ public class RFXComDateTimeMessageTest {
     public void testSomeMessages() throws RFXComException {
         String hexMessage = "0D580117B90003041D030D150A69";
         byte[] message = HexUtils.hexToBytes(hexMessage);
-        RFXComDateTimeMessage msg = (RFXComDateTimeMessage) RFXComMessageFactory.createMessage(message);
+        RFXComDateTimeMessage msg = (RFXComDateTimeMessage) RFXComMessageFactoryImpl.INSTANCE.createMessage(message);
         assertEquals(RFXComDateTimeMessage.SubType.RTGR328N, msg.subType, "SubType");
         assertEquals(23, (short) (msg.seqNbr & 0xFF), "Seq Number");
         assertEquals("47360", msg.getDeviceId(), "Sensor Id");
index a82d4b9dac6cb81ef902cdf8417643042d26776b..b8463c3d78afee8547ec2b24abb4f6e26fa9d066 100644 (file)
@@ -28,6 +28,7 @@ import org.openhab.binding.rfxcom.internal.exceptions.RFXComMessageNotImplemente
 public class RFXComEdisioTest {
     @Test
     public void checkNotImplemented() {
-        assertThrows(RFXComMessageNotImplementedException.class, () -> RFXComMessageFactory.createMessage(EDISIO));
+        assertThrows(RFXComMessageNotImplementedException.class,
+                () -> RFXComMessageFactoryImpl.INSTANCE.createMessage(EDISIO));
     }
 }
index 63a18df0a63cbb14fbcdab5fee20025256d25d2b..4119415a47d96ff7207f0d37bb77c81877111ed5 100644 (file)
@@ -31,7 +31,7 @@ public class RFXComEnergyMessageTest {
     public void testSomeMessages() throws RFXComException {
         String hexMessage = "115A01071A7300000003F600000000350B89";
         byte[] message = HexUtils.hexToBytes(hexMessage);
-        RFXComEnergyMessage msg = (RFXComEnergyMessage) RFXComMessageFactory.createMessage(message);
+        RFXComEnergyMessage msg = (RFXComEnergyMessage) RFXComMessageFactoryImpl.INSTANCE.createMessage(message);
         assertEquals(ELEC2, msg.subType, "SubType");
         assertEquals(7, msg.seqNbr, "Seq Number");
         assertEquals("6771", msg.getDeviceId(), "Sensor Id");
index c23391486d808d092372dcf181b41c8fd1a4fd25..e8ea4d13eddd6ac0b7979c0af2afd14001fa6b75 100644 (file)
@@ -30,6 +30,6 @@ public class RFXComFS20MessageTest {
     @Test
     public void checkNotImplemented() {
         assertThrows(RFXComMessageNotImplementedException.class,
-                () -> RFXComMessageFactory.createMessage(PacketType.FS20));
+                () -> RFXComMessageFactoryImpl.INSTANCE.createMessage(PacketType.FS20));
     }
 }
index cbbbc324c3fdd3104405802b20afc8cd261e20e4..c475507e8afe58783e6cac727f876f8af1cadccd 100644 (file)
@@ -38,12 +38,12 @@ public class RFXComFanMessageTest {
 
     @Test
     public void checkForSupportTest() throws RFXComException {
-        RFXComMessageFactory.createMessage(FAN);
+        RFXComMessageFactoryImpl.INSTANCE.createMessage(FAN);
     }
 
     @Test
     public void basicBoundaryCheck() throws RFXComException {
-        RFXComFanMessage message = (RFXComFanMessage) RFXComMessageFactory.createMessage(FAN);
+        RFXComFanMessage message = (RFXComFanMessage) RFXComMessageFactoryImpl.INSTANCE.createMessage(FAN);
 
         message.setSubType(RFXComFanMessage.SubType.CASAFAN);
         message.convertFromState(CHANNEL_FAN_SPEED, StringType.valueOf("OFF"));
@@ -54,7 +54,8 @@ public class RFXComFanMessageTest {
     private void testMessage(String hexMsg, int seqNbr, String deviceId, int signalLevel,
             @Nullable State expectedCommand, State expectedLightCommand, @Nullable State expectedFanSpeed,
             RFXComBaseMessage.PacketType packetType) throws RFXComException {
-        final RFXComFanMessage msg = (RFXComFanMessage) RFXComMessageFactory.createMessage(HexUtils.hexToBytes(hexMsg));
+        final RFXComFanMessage msg = (RFXComFanMessage) RFXComMessageFactoryImpl.INSTANCE
+                .createMessage(HexUtils.hexToBytes(hexMsg));
         assertEquals(seqNbr, (short) (msg.seqNbr & 0xFF), "Seq Number");
         assertEquals(deviceId, msg.getDeviceId(), "Sensor Id");
         assertEquals(signalLevel, msg.signalLevel, "Signal Level");
index b3527e28319365b61e93f06a8c5b383921b494c2..b82f3df9cf8946bbd0bcca67fc451ee2d60f6385 100644 (file)
@@ -30,6 +30,6 @@ public class RFXComGasMessageTest {
     @Test
     public void checkNotImplemented() {
         assertThrows(RFXComMessageNotImplementedException.class,
-                () -> RFXComMessageFactory.createMessage(PacketType.GAS));
+                () -> RFXComMessageFactoryImpl.INSTANCE.createMessage(PacketType.GAS));
     }
 }
index a12069b07bc8b089a36ef764e280529eea1db170..28de642f35383e82555b7c4efd9976f2a00587c3 100644 (file)
@@ -12,7 +12,7 @@
  */
 package org.openhab.binding.rfxcom.internal.messages;
 
-import static org.junit.jupiter.api.Assertions.*;
+import static org.junit.jupiter.api.Assertions.assertArrayEquals;
 import static org.openhab.binding.rfxcom.internal.messages.RFXComBaseMessage.PacketType.HOME_CONFORT;
 
 import org.eclipse.jdt.annotation.NonNullByDefault;
@@ -31,7 +31,8 @@ import org.openhab.core.util.HexUtils;
 @NonNullByDefault
 public class RFXComHomeConfortTest {
     private void testMessage(SubType subType, Commands command, String deviceId, String data) throws RFXComException {
-        RFXComHomeConfortMessage message = (RFXComHomeConfortMessage) RFXComMessageFactory.createMessage(HOME_CONFORT);
+        RFXComHomeConfortMessage message = (RFXComHomeConfortMessage) RFXComMessageFactoryImpl.INSTANCE
+                .createMessage(HOME_CONFORT);
         message.setSubType(subType);
         message.command = command;
         message.setDeviceId(deviceId);
index db94e78f805950cf879e020196b58927efbccc1a..7ebb58e0c5dc05d59fabdf5b768e6f245678233e 100644 (file)
@@ -31,7 +31,7 @@ public class RFXComHumidityMessageTest {
     public void testSomeMessages() throws RFXComException {
         String hexMessage = "085101027700360189";
         byte[] message = HexUtils.hexToBytes(hexMessage);
-        RFXComHumidityMessage msg = (RFXComHumidityMessage) RFXComMessageFactory.createMessage(message);
+        RFXComHumidityMessage msg = (RFXComHumidityMessage) RFXComMessageFactoryImpl.INSTANCE.createMessage(message);
         assertEquals(RFXComHumidityMessage.SubType.HUM1, msg.subType, "SubType");
         assertEquals(2, (short) (msg.seqNbr & 0xFF), "Seq Number");
         assertEquals("30464", msg.getDeviceId(), "Sensor Id");
index 633bc9aeb373c731bca2861f1a9e918da5ccbd84..044008fd42d2d73fc60a8738779cf256348dda22 100644 (file)
@@ -30,6 +30,6 @@ public class RFXComIOLinesMessageTest {
     @Test
     public void checkNotImplemented() {
         assertThrows(RFXComMessageNotImplementedException.class,
-                () -> RFXComMessageFactory.createMessage(PacketType.IO_LINES));
+                () -> RFXComMessageFactoryImpl.INSTANCE.createMessage(PacketType.IO_LINES));
     }
 }
index b0168b485235921e99b62208248368850a21c0fe..d4aac629e2ed5aca83a17ffaee3a366e1b7b179f 100644 (file)
@@ -32,7 +32,7 @@ import org.openhab.core.util.HexUtils;
 public class RFXComInterfaceMessageTest {
     private RFXComInterfaceMessage testMessage(String hexMsg, SubType subType, int seqNbr, Commands command)
             throws RFXComException {
-        RFXComInterfaceMessage msg = (RFXComInterfaceMessage) RFXComMessageFactory
+        RFXComInterfaceMessage msg = (RFXComInterfaceMessage) RFXComMessageFactoryImpl.INSTANCE
                 .createMessage(HexUtils.hexToBytes(hexMsg));
         assertEquals(subType, msg.subType, "SubType");
         assertEquals(seqNbr, (short) (msg.seqNbr & 0xFF), "Seq Number");
index d6965663db111723fd3c31ea98fc972a33436d11..de6f5463f074ef8682a45f0f7eb02297c1a420b4 100644 (file)
@@ -30,6 +30,7 @@ public class RFXComInvalidMessageTypeTest {
     @Test
     public void testMessage() {
         byte[] message = HexUtils.hexToBytes("07CC01271356ECC0");
-        assertThrows(RFXComUnsupportedValueException.class, () -> RFXComMessageFactory.createMessage(message));
+        assertThrows(RFXComUnsupportedValueException.class,
+                () -> RFXComMessageFactoryImpl.INSTANCE.createMessage(message));
     }
 }
index f2b04cc52fa300d694a3fb17d1fb75637cb43d07..54af0ef7dcc2f622d9264af27be7b0753d9917fc 100644 (file)
@@ -36,7 +36,7 @@ public class RFXComLighting1MessageTest {
 
     private void testMessage(String hexMsg, RFXComLighting1Message.SubType subType, int seqNbr, String deviceId,
             byte signalLevel, Commands command, String commandString) throws RFXComException {
-        final RFXComLighting1Message msg = (RFXComLighting1Message) RFXComMessageFactory
+        final RFXComLighting1Message msg = (RFXComLighting1Message) RFXComMessageFactoryImpl.INSTANCE
                 .createMessage(HexUtils.hexToBytes(hexMsg));
         assertEquals(subType, msg.subType, "SubType");
         assertEquals(seqNbr, (short) (msg.seqNbr & 0xFF), "Seq Number");
index f71343627a93822e8eb6b5f01390cab5d739517f..f9038dba6d015e757ebd7cec78c8128d83578b1b 100644 (file)
@@ -31,7 +31,7 @@ public class RFXComLighting2MessageTest {
     public void testSomeMessages() throws RFXComException {
         String hexMessage = "0B11000600109B520B000080";
         byte[] message = HexUtils.hexToBytes(hexMessage);
-        RFXComLighting2Message msg = (RFXComLighting2Message) RFXComMessageFactory.createMessage(message);
+        RFXComLighting2Message msg = (RFXComLighting2Message) RFXComMessageFactoryImpl.INSTANCE.createMessage(message);
         assertEquals(RFXComLighting2Message.SubType.AC, msg.subType, "SubType");
         assertEquals(6, (short) (msg.seqNbr & 0xFF), "Seq Number");
         assertEquals("1088338.11", msg.getDeviceId(), "Sensor Id");
index 8fd649b7e5bf91341d4c38ec94aceacd979b4e37..655698e1639919db14d0ffe1d0654dbaefc4d132 100644 (file)
@@ -31,6 +31,6 @@ public class RFXComLighting3MessageTest {
     public void checkNotImplemented() {
         // TODO Note that this message is supported in the 1.9 binding
         assertThrows(RFXComMessageNotImplementedException.class,
-                () -> RFXComMessageFactory.createMessage(PacketType.LIGHTING3));
+                () -> RFXComMessageFactoryImpl.INSTANCE.createMessage(PacketType.LIGHTING3));
     }
 }
index 2b955ac81d558d8b7a036919052e14fd05c217ea..aaea645133fa222b56afe28f82f3fd4273ded800 100644 (file)
@@ -24,8 +24,7 @@ import java.util.List;
 import org.eclipse.jdt.annotation.NonNullByDefault;
 import org.eclipse.jdt.annotation.Nullable;
 import org.junit.jupiter.api.Test;
-import org.openhab.binding.rfxcom.internal.config.RFXComDeviceConfiguration;
-import org.openhab.binding.rfxcom.internal.config.RFXComDeviceConfigurationBuilder;
+import org.openhab.binding.rfxcom.internal.config.RFXComLighting4DeviceConfiguration;
 import org.openhab.binding.rfxcom.internal.exceptions.RFXComException;
 import org.openhab.core.library.types.OnOffType;
 import org.openhab.core.util.HexUtils;
@@ -39,15 +38,19 @@ import org.openhab.core.util.HexUtils;
 public class RFXComLighting4MessageTest {
     @Test
     public void basicBoundaryCheck() throws RFXComException {
-        RFXComLighting4Message message = (RFXComLighting4Message) RFXComMessageFactory.createMessage(LIGHTING4);
-
-        RFXComDeviceConfiguration build = new RFXComDeviceConfigurationBuilder().withDeviceId("90000").withPulse(300)
-                .withSubType("PT2262").build();
-        message.setConfig(build);
+        RFXComLighting4Message message = (RFXComLighting4Message) RFXComMessageFactoryImpl.INSTANCE
+                .createMessage(LIGHTING4);
+
+        RFXComLighting4DeviceConfiguration config = new RFXComLighting4DeviceConfiguration();
+        config.deviceId = "90000";
+        config.subType = "PT2262";
+        config.pulse = 300;
+        message.setConfig(config);
         message.convertFromState(CHANNEL_COMMAND, OnOffType.ON);
 
         byte[] binaryMessage = message.decodeMessage();
-        RFXComLighting4Message msg = (RFXComLighting4Message) RFXComMessageFactory.createMessage(binaryMessage);
+        RFXComLighting4Message msg = (RFXComLighting4Message) RFXComMessageFactoryImpl.INSTANCE
+                .createMessage(binaryMessage);
 
         assertEquals("90000", msg.getDeviceId(), "Sensor Id");
     }
@@ -61,7 +64,7 @@ public class RFXComLighting4MessageTest {
     private void testMessage(String hexMsg, RFXComLighting4Message.SubType subType, String deviceId,
             @Nullable Integer pulse, byte commandByte, @Nullable Integer seqNbr, int signalLevel, int offCommand,
             int onCommand) throws RFXComException {
-        RFXComLighting4Message msg = (RFXComLighting4Message) RFXComMessageFactory
+        RFXComLighting4Message msg = (RFXComLighting4Message) RFXComMessageFactoryImpl.INSTANCE
                 .createMessage(HexUtils.hexToBytes(hexMsg));
         assertEquals(deviceId, msg.getDeviceId(), "Sensor Id");
         assertEquals(commandByte, RFXComTestHelper.getActualIntValue(msg, CHANNEL_COMMAND_ID), "Command");
index 156ed4693a1cb16950de6b586b37acdd78b2fa9d..64aa2bf72003c882f955d02377116a00cb43f8a0 100644 (file)
@@ -37,14 +37,15 @@ public class RFXComLighting5MessageTest {
 
     @Test
     public void convertFromStateItMessage() throws RFXComException {
-        RFXComDeviceMessage itMessageObject = (RFXComDeviceMessage) RFXComMessageFactory.createMessage(LIGHTING5);
+        RFXComDeviceMessage itMessageObject = (RFXComDeviceMessage) RFXComMessageFactoryImpl.INSTANCE
+                .createMessage(LIGHTING5);
         itMessageObject.setDeviceId("2061.1");
         itMessageObject.setSubType(IT);
         itMessageObject.convertFromState(CHANNEL_COMMAND, OnOffType.ON);
         byte[] message = itMessageObject.decodeMessage();
         String hexMessage = HexUtils.bytesToHex(message);
         assertEquals("0A140F0000080D01010000", hexMessage, "Message is not as expected");
-        RFXComLighting5Message msg = (RFXComLighting5Message) RFXComMessageFactory.createMessage(message);
+        RFXComLighting5Message msg = (RFXComLighting5Message) RFXComMessageFactoryImpl.INSTANCE.createMessage(message);
         assertEquals(IT, msg.subType, "SubType");
         assertEquals("2061.1", msg.getDeviceId(), "Sensor Id");
         assertEquals(ON, msg.command, "Command");
@@ -52,7 +53,8 @@ public class RFXComLighting5MessageTest {
 
     @Test
     public void basicBoundaryCheck() throws RFXComException {
-        RFXComLighting5Message message = (RFXComLighting5Message) RFXComMessageFactory.createMessage(LIGHTING5);
+        RFXComLighting5Message message = (RFXComLighting5Message) RFXComMessageFactoryImpl.INSTANCE
+                .createMessage(LIGHTING5);
 
         message.subType = RFXComLighting5Message.SubType.LIGHTWAVERF;
         message.command = ON;
index cdd85499d6034926430682f0b07e4f393db6f5aa..65cbe0f22162bccb082e365f12b472437d427969 100644 (file)
@@ -31,7 +31,7 @@ public class RFXComLighting6MessageTest {
     public void testSomeMessages() throws RFXComException {
         String hexMessage = "0B150005D950450101011D80";
         byte[] message = HexUtils.hexToBytes(hexMessage);
-        RFXComLighting6Message msg = (RFXComLighting6Message) RFXComMessageFactory.createMessage(message);
+        RFXComLighting6Message msg = (RFXComLighting6Message) RFXComMessageFactoryImpl.INSTANCE.createMessage(message);
         assertEquals(RFXComLighting6Message.SubType.BLYSS, msg.subType, "SubType");
         assertEquals(5, (short) (msg.seqNbr & 0xFF), "Seq Number");
         assertEquals("55632.E.1", msg.getDeviceId(), "Sensor Id");
index 491a02f82e4f262f75dac0ea267e4c66ab553ea6..639763e6d78c22fdbb69eb1889d11d7bee737fa2 100644 (file)
@@ -29,6 +29,6 @@ public class RFXComPowerMessageTest {
     public void checkNotImplemented() {
         // TODO Note that this message is supported in the 1.9 binding
         assertThrows(RFXComMessageNotImplementedException.class,
-                () -> RFXComMessageFactory.createMessage(RFXComBaseMessage.PacketType.POWER));
+                () -> RFXComMessageFactoryImpl.INSTANCE.createMessage(RFXComBaseMessage.PacketType.POWER));
     }
 }
index a0e1da1d0ebd7562f214ab8d14e5d9c2427a916a..5d0b48f24d9e61a3c16a7e38240996977f4145e1 100644 (file)
@@ -30,6 +30,6 @@ public class RFXComRFXMeterMessageTest {
     @Test
     public void checkNotImplemented() {
         assertThrows(RFXComMessageNotImplementedException.class,
-                () -> RFXComMessageFactory.createMessage(PacketType.RFXMETER));
+                () -> RFXComMessageFactoryImpl.INSTANCE.createMessage(PacketType.RFXMETER));
     }
 }
index 3e2e2be7a41622ef282531f108a349370131bc1b..2f9a401aadb9bd05d50bc091df389781daacbd7c 100644 (file)
@@ -39,7 +39,7 @@ public class RFXComRFXSensorMessageTest {
             @Nullable Double temperature, @Nullable Double voltage, @Nullable Double referenceVoltage,
             @Nullable Double expectedPressure, @Nullable Double expectedHumidity, int signalLevel,
             DeviceState deviceState) throws RFXComException {
-        final RFXComRFXSensorMessage msg = (RFXComRFXSensorMessage) RFXComMessageFactory
+        final RFXComRFXSensorMessage msg = (RFXComRFXSensorMessage) RFXComMessageFactoryImpl.INSTANCE
                 .createMessage(DatatypeConverter.parseHexBinary(hexMsg));
         assertEquals(subType, msg.subType, "SubType");
         assertEquals(seqNbr, (short) (msg.seqNbr & 0xFF), "Seq Number");
index d169437d6198718597f9af3617383227b9fbcd6f..088f600b8b1f5805ae60c6b817e56953dc0fbfcf 100644 (file)
@@ -28,6 +28,7 @@ import org.openhab.binding.rfxcom.internal.exceptions.RFXComMessageNotImplemente
 public class RFXComRadiator1MessageTest {
     @Test
     public void checkNotImplemented() {
-        assertThrows(RFXComMessageNotImplementedException.class, () -> RFXComMessageFactory.createMessage(RADIATOR1));
+        assertThrows(RFXComMessageNotImplementedException.class,
+                () -> RFXComMessageFactoryImpl.INSTANCE.createMessage(RADIATOR1));
     }
 }
index e9bfe248f96b5af638757acb4bb1035a5c886c94..41baa59030e5db860f7c22b48e1f1a8849408e59 100644 (file)
@@ -32,7 +32,7 @@ public class RFXComRainMessageTest {
     public void testSomeMessages() throws RFXComException {
         String hexMessage = "0B550217B6000000004D3C69";
         byte[] message = HexUtils.hexToBytes(hexMessage);
-        RFXComRainMessage msg = (RFXComRainMessage) RFXComMessageFactory.createMessage(message);
+        RFXComRainMessage msg = (RFXComRainMessage) RFXComMessageFactoryImpl.INSTANCE.createMessage(message);
         assertEquals(RAIN2, msg.subType, "SubType");
         assertEquals(23, msg.seqNbr, "Seq Number");
         assertEquals("46592", msg.getDeviceId(), "Sensor Id");
index f3baebb59bda8799223201a24fd8ce7678e33fa2..188c7fc8b6209c990f9e53a0fcc4176241165edd 100644 (file)
@@ -18,9 +18,13 @@ import java.nio.ByteBuffer;
 
 import org.eclipse.jdt.annotation.NonNullByDefault;
 import org.junit.jupiter.api.Test;
+import org.openhab.binding.rfxcom.internal.RFXComBindingConstants;
+import org.openhab.binding.rfxcom.internal.config.RFXComRawDeviceConfiguration;
 import org.openhab.binding.rfxcom.internal.exceptions.RFXComException;
-import org.openhab.binding.rfxcom.internal.exceptions.RFXComMessageTooLongException;
+import org.openhab.binding.rfxcom.internal.exceptions.RFXComInvalidStateException;
 import org.openhab.binding.rfxcom.internal.messages.RFXComBaseMessage.PacketType;
+import org.openhab.core.library.types.OnOffType;
+import org.openhab.core.types.Type;
 import org.openhab.core.util.HexUtils;
 
 /**
@@ -31,9 +35,10 @@ import org.openhab.core.util.HexUtils;
 @NonNullByDefault
 public class RFXComRawMessageTest {
 
-    private void testMessage(String hexMsg, RFXComRawMessage.SubType subType, int seqNbr, int repeat, String pulses)
+    private void testMessageRx(String hexMsg, RFXComRawMessage.SubType subType, int seqNbr, int repeat, String pulses)
             throws RFXComException {
-        final RFXComRawMessage msg = (RFXComRawMessage) RFXComMessageFactory.createMessage(HexUtils.hexToBytes(hexMsg));
+        final RFXComRawMessage msg = (RFXComRawMessage) RFXComMessageFactoryImpl.INSTANCE
+                .createMessage(HexUtils.hexToBytes(hexMsg));
         assertEquals(subType, msg.subType, "SubType");
         assertEquals(seqNbr, (short) (msg.seqNbr & 0xFF), "Seq Number");
         assertEquals("RAW", msg.getDeviceId(), "Device Id");
@@ -41,25 +46,43 @@ public class RFXComRawMessageTest {
         byte[] payload = new byte[msg.pulses.length * 2];
         ByteBuffer.wrap(payload).asShortBuffer().put(msg.pulses);
         assertEquals(pulses, HexUtils.bytesToHex(payload), "Pulses");
+    }
+
+    @Test
+    public void testSomeRxMessages() throws RFXComException {
+        testMessageRx("087F0027051356ECC0", RFXComRawMessage.SubType.RAW_PACKET1, 0x27, 5, "1356ECC0");
+    }
 
+    private void testMessageTx(RFXComRawDeviceConfiguration config, Type command, String hexMsg)
+            throws RFXComException {
+        RFXComRawMessage msg = (RFXComRawMessage) RFXComMessageFactoryImpl.INSTANCE.createMessage(PacketType.RAW);
+        msg.setConfig(config);
+        msg.convertFromState(RFXComBindingConstants.CHANNEL_COMMAND, command);
         byte[] decoded = msg.decodeMessage();
 
-        assertEquals(hexMsg, HexUtils.bytesToHex(decoded), "Message converted back");
+        assertEquals(hexMsg, HexUtils.bytesToHex(decoded), "Transmitted message");
     }
 
     @Test
-    public void testSomeMessages() throws RFXComException {
-        testMessage("087F0027051356ECC0", RFXComRawMessage.SubType.RAW_PACKET1, 0x27, 5, "1356ECC0");
+    public void testTxBasicPulses() throws RFXComException {
+        RFXComRawDeviceConfiguration config = new RFXComRawDeviceConfiguration();
+        config.deviceId = "RAW";
+        config.subType = "RAW_PACKET1";
+        config.repeat = 5;
+        config.onPulsesArray = new short[] { 0x10, 0x20, 0x30, 0x40 };
+
+        testMessageTx(config, OnOffType.ON, "0C7F0000050010002000300040");
     }
 
     @Test
-    public void testLongMessage() throws RFXComException {
-        RFXComRawMessage msg = (RFXComRawMessage) RFXComMessageFactory.createMessage(PacketType.RAW);
-        msg.subType = RFXComRawMessage.SubType.RAW_PACKET1;
-        msg.seqNbr = 1;
-        msg.repeat = 5;
-        msg.pulses = new short[125];
+    public void testTxMissingPulses() throws RFXComException {
+        RFXComRawDeviceConfiguration config = new RFXComRawDeviceConfiguration();
+        config.deviceId = "RAW";
+        config.subType = "RAW_PACKET1";
+        config.repeat = 5;
+        config.onPulsesArray = new short[] { 0x10, 0x20, 0x30, 0x40 };
 
-        assertThrows(RFXComMessageTooLongException.class, () -> msg.decodeMessage());
+        assertThrows(RFXComInvalidStateException.class,
+                () -> testMessageTx(config, OnOffType.OFF, "0C7F0000050010002000300040"));
     }
 }
index ffb7e3b9579a82cc65560d00fa18a07254bb5df9..6480e870ebbadfc84df99fb430987345cdf64efa 100644 (file)
@@ -29,6 +29,6 @@ public class RFXComRemoteControlMessageTest {
     @Test
     public void checkNotImplemented() {
         assertThrows(RFXComMessageNotImplementedException.class,
-                () -> RFXComMessageFactory.createMessage(PacketType.REMOTE_CONTROL));
+                () -> RFXComMessageFactoryImpl.INSTANCE.createMessage(PacketType.REMOTE_CONTROL));
     }
 }
index 1e08bab536cc2d4b51a48b95c88dab621b0db114..bc51015ed478f81e7e376c6a69926a74773b7520 100644 (file)
@@ -12,7 +12,7 @@
  */
 package org.openhab.binding.rfxcom.internal.messages;
 
-import static org.junit.jupiter.api.Assertions.*;
+import static org.junit.jupiter.api.Assertions.assertArrayEquals;
 import static org.openhab.binding.rfxcom.internal.messages.RFXComBaseMessage.PacketType.RFY;
 
 import org.eclipse.jdt.annotation.NonNullByDefault;
@@ -32,7 +32,7 @@ public class RFXComRfyMessageTest {
 
     @Test
     public void basicBoundaryCheck() throws RFXComException {
-        RFXComRfyMessage message = (RFXComRfyMessage) RFXComMessageFactory.createMessage(RFY);
+        RFXComRfyMessage message = (RFXComRfyMessage) RFXComMessageFactoryImpl.INSTANCE.createMessage(RFY);
 
         message.subType = SubType.RFY;
         message.command = Commands.UP;
@@ -41,7 +41,7 @@ public class RFXComRfyMessageTest {
     }
 
     private void testMessage(SubType subType, Commands command, String deviceId, String data) throws RFXComException {
-        RFXComRfyMessage message = (RFXComRfyMessage) RFXComMessageFactory.createMessage(RFY);
+        RFXComRfyMessage message = (RFXComRfyMessage) RFXComMessageFactoryImpl.INSTANCE.createMessage(RFY);
         message.setSubType(subType);
         message.command = command;
         message.setDeviceId(deviceId);
index 44c97e8c300436e098fd1ab7db1e265636b9d847..9a0ba69f7e49b433a5e32665dbdf56a3cbaf4c83 100644 (file)
@@ -37,7 +37,7 @@ public class RFXComSecurity1MessageTest {
             @Nullable String deviceId, int batteryLevel, @Nullable Contact contact, @Nullable Motion motion,
             @Nullable Status status, int signalLevel) throws RFXComException {
         byte[] message = HexUtils.hexToBytes(hexMessage);
-        RFXComSecurity1Message msg = (RFXComSecurity1Message) RFXComMessageFactory.createMessage(message);
+        RFXComSecurity1Message msg = (RFXComSecurity1Message) RFXComMessageFactoryImpl.INSTANCE.createMessage(message);
         assertEquals(subType, msg.subType, "SubType");
         assertEquals(sequenceNumber, (short) (msg.seqNbr & 0xFF), "Seq Number");
         assertEquals(deviceId, msg.getDeviceId(), "Sensor Id");
index a77396f8c8c7310fcad66e9372a0fb247e645896..1a1149bf8cb26ea31fe8cdb6dfb134516dc62bad 100644 (file)
@@ -34,7 +34,7 @@ public class RFXComSecurity2MessageTest {
         String hexMessage = "1C21020000000000131211C30000000000000000000000000000000045";
         byte[] message = HexUtils.hexToBytes(hexMessage);
 
-        RFXComSecurity2Message msg = (RFXComSecurity2Message) RFXComMessageFactory.createMessage(message);
+        RFXComSecurity2Message msg = (RFXComSecurity2Message) RFXComMessageFactoryImpl.INSTANCE.createMessage(message);
         assertEquals(SubType.RAW_AES_KEELOQ, msg.subType, "SubType");
         assertEquals(0, msg.seqNbr, "Seq Number");
         assertEquals("51450387", msg.getDeviceId(), "Sensor Id");
index d1fbcea2d686475e1c975f2e93c8b7c13393721c..dd728dc4a670866b1546fc56762d8076c72502fc 100644 (file)
@@ -34,7 +34,7 @@ public class RFXComTemperatureHumidityBarometricMessageTest {
     public void testSomeMessages() throws RFXComException {
         String hexMessage = "0D54020EE90000C9270203E70439";
         byte[] message = HexUtils.hexToBytes(hexMessage);
-        RFXComTemperatureHumidityBarometricMessage msg = (RFXComTemperatureHumidityBarometricMessage) RFXComMessageFactory
+        RFXComTemperatureHumidityBarometricMessage msg = (RFXComTemperatureHumidityBarometricMessage) RFXComMessageFactoryImpl.INSTANCE
                 .createMessage(message);
         assertEquals(THB2, msg.subType, "SubType");
         assertEquals(14, msg.seqNbr, "Seq Number");
index 96c4e67914d53dc901f1779f2b94f5e8080282df..90403279280de276def82c748e7b36df5d683022 100644 (file)
@@ -35,7 +35,7 @@ public class RFXComTemperatureHumidityMessageTest {
             double temperature, int humidity, HumidityStatus humidityStatus, int signalLevel, int batteryLevel)
             throws RFXComException {
         byte[] binaryMessage = HexUtils.hexToBytes(hexMsg);
-        final RFXComTemperatureHumidityMessage msg = (RFXComTemperatureHumidityMessage) RFXComMessageFactory
+        final RFXComTemperatureHumidityMessage msg = (RFXComTemperatureHumidityMessage) RFXComMessageFactoryImpl.INSTANCE
                 .createMessage(binaryMessage);
         assertEquals(subType, msg.subType, "SubType");
         assertEquals(seqNbr, (short) (msg.seqNbr & 0xFF), "Seq Number");
index 7a4f69ab79e3609823175b683b3541f874117e58..6fcf16cf7cdc66858722f43d971e083b3193fcb6 100644 (file)
@@ -29,7 +29,7 @@ import org.openhab.core.util.HexUtils;
 public class RFXComTemperatureMessageTest {
     private void testMessage(String hexMsg, RFXComTemperatureMessage.SubType subType, int seqNbr, String deviceId,
             double temperature, int signalLevel, int bateryLevel) throws RFXComException {
-        final RFXComTemperatureMessage msg = (RFXComTemperatureMessage) RFXComMessageFactory
+        final RFXComTemperatureMessage msg = (RFXComTemperatureMessage) RFXComMessageFactoryImpl.INSTANCE
                 .createMessage(HexUtils.hexToBytes(hexMsg));
         assertEquals(subType, msg.subType, "SubType");
         assertEquals(seqNbr, (short) (msg.seqNbr & 0xFF), "Seq Number");
index e3ce1f079d7aac13261251851f1200568792cdf9..8cfb55d5e73a8a1614aa594ebf683a963d8a289d 100644 (file)
@@ -31,7 +31,8 @@ public class RFXComTemperatureRainMessageTest {
     public void testSomeMessages() throws RFXComException {
         String hexMessage = "0A4F01CCF001004F03B759";
         byte[] message = HexUtils.hexToBytes(hexMessage);
-        RFXComTemperatureRainMessage msg = (RFXComTemperatureRainMessage) RFXComMessageFactory.createMessage(message);
+        RFXComTemperatureRainMessage msg = (RFXComTemperatureRainMessage) RFXComMessageFactoryImpl.INSTANCE
+                .createMessage(message);
         assertEquals(WS1200, msg.subType, "SubType");
         assertEquals(204, (short) (msg.seqNbr & 0xFF), "Seq Number");
         assertEquals("61441", msg.getDeviceId(), "Sensor Id");
index 81d5e0a2e512f542bf86c6524fe6d0e3fc4c3413..e8d3e0f5374ce5f3e16d9e3ee59eda25bc3b9a85 100644 (file)
@@ -31,7 +31,8 @@ public class RFXComThermostat1MessageTest {
     public void testSomeMessages() throws RFXComException {
         String hexMessage = "0940001B6B1816150270";
         byte[] message = HexUtils.hexToBytes(hexMessage);
-        RFXComThermostat1Message msg = (RFXComThermostat1Message) RFXComMessageFactory.createMessage(message);
+        RFXComThermostat1Message msg = (RFXComThermostat1Message) RFXComMessageFactoryImpl.INSTANCE
+                .createMessage(message);
         assertEquals(RFXComThermostat1Message.SubType.DIGIMAX, msg.subType, "SubType");
         assertEquals(27, (short) (msg.seqNbr & 0xFF), "Seq Number");
         assertEquals("27416", msg.getDeviceId(), "Sensor Id");
index 724e687918ed8ed37d05d38edd6a78d1c4c5c8cb..c582dc67426f9da6247f18b358fb19ebea283771 100644 (file)
@@ -30,6 +30,6 @@ public class RFXComThermostat2MessageTest {
     public void checkNotImplemented() {
         // TODO Note that this message is supported in the 1.9 binding
         assertThrows(RFXComMessageNotImplementedException.class,
-                () -> RFXComMessageFactory.createMessage(PacketType.THERMOSTAT2));
+                () -> RFXComMessageFactoryImpl.INSTANCE.createMessage(PacketType.THERMOSTAT2));
     }
 }
index 746fff66b52bdefcfb31a6488b7306ad712b8518..fc4319441bd56ebd84ff3378909c44048944c216 100644 (file)
@@ -41,12 +41,13 @@ public class RFXComThermostat3MessageTest {
 
     @Test
     public void checkForSupportTest() throws RFXComException {
-        RFXComMessageFactory.createMessage(THERMOSTAT3);
+        RFXComMessageFactoryImpl.INSTANCE.createMessage(THERMOSTAT3);
     }
 
     @Test
     public void basicBoundaryCheck() throws RFXComException {
-        RFXComThermostat3Message message = (RFXComThermostat3Message) RFXComMessageFactory.createMessage(THERMOSTAT3);
+        RFXComThermostat3Message message = (RFXComThermostat3Message) RFXComMessageFactoryImpl.INSTANCE
+                .createMessage(THERMOSTAT3);
 
         message.subType = RFXComThermostat3Message.SubType.MERTIK__G6R_H4S_TRANSMIT_ONLY;
         message.command = RFXComThermostat3Message.Commands.ON;
@@ -68,7 +69,8 @@ public class RFXComThermostat3MessageTest {
             @Nullable State secondCommandChannel, State controlChannel, State commandStringChannel)
             throws RFXComException {
         byte[] message = HexUtils.hexToBytes(hexMessage);
-        RFXComThermostat3Message msg = (RFXComThermostat3Message) RFXComMessageFactory.createMessage(message);
+        RFXComThermostat3Message msg = (RFXComThermostat3Message) RFXComMessageFactoryImpl.INSTANCE
+                .createMessage(message);
         assertEquals(subtype, msg.subType, "SubType");
         assertEquals(sequenceNumber, (short) (msg.seqNbr & 0xFF), "Seq Number");
         assertEquals(sensorId, msg.getDeviceId(), "Sensor Id");
index e7bd3d552418cd143dc0b4d87438928d5c35ba19..a724aa902462bad4da592e10c3efc987fd2c45da 100644 (file)
@@ -28,6 +28,7 @@ import org.openhab.binding.rfxcom.internal.exceptions.RFXComMessageNotImplemente
 public class RFXComThermostat4MessageTest {
     @Test
     public void checkNotImplemented() {
-        assertThrows(RFXComMessageNotImplementedException.class, () -> RFXComMessageFactory.createMessage(THERMOSTAT4));
+        assertThrows(RFXComMessageNotImplementedException.class,
+                () -> RFXComMessageFactoryImpl.INSTANCE.createMessage(THERMOSTAT4));
     }
 }
index f8d05a7c31b4b6c42dc8792ef1212e5729c4f03f..f9e55b7478892bc0f640285f855c3558b6a47a04 100644 (file)
@@ -31,7 +31,7 @@ import org.openhab.core.util.HexUtils;
 @NonNullByDefault
 public class RFXComTransmitterMessageTest {
     private void testMessage(String hexMsg, Response response, SubType subType, int seqNbr) throws RFXComException {
-        final RFXComTransmitterMessage msg = (RFXComTransmitterMessage) RFXComMessageFactory
+        final RFXComTransmitterMessage msg = (RFXComTransmitterMessage) RFXComMessageFactoryImpl.INSTANCE
                 .createMessage(HexUtils.hexToBytes(hexMsg));
         assertEquals(subType, msg.subType, "SubType");
         assertEquals(response, msg.response, "Response");
index 30ac76f7a7a0accf4873d44ca7e82a11c1c6b840..4e63d8efc2e2fe875c2804ad9ad56c1c2c005d38 100644 (file)
@@ -32,7 +32,7 @@ public class RFXComUVMessageTest {
         String hexMessage = "095703123421194731E9";
 
         byte[] message = HexUtils.hexToBytes(hexMessage);
-        RFXComUVMessage msg = (RFXComUVMessage) RFXComMessageFactory.createMessage(message);
+        RFXComUVMessage msg = (RFXComUVMessage) RFXComMessageFactoryImpl.INSTANCE.createMessage(message);
 
         assertEquals(RFXComUVMessage.SubType.UV3, msg.subType, "SubType");
         assertEquals(18, msg.seqNbr, "Seq Number");
@@ -54,7 +54,7 @@ public class RFXComUVMessageTest {
         String hexMessage = "09570312342119C731E9";
 
         byte[] message = HexUtils.hexToBytes(hexMessage);
-        RFXComUVMessage msg = (RFXComUVMessage) RFXComMessageFactory.createMessage(message);
+        RFXComUVMessage msg = (RFXComUVMessage) RFXComMessageFactoryImpl.INSTANCE.createMessage(message);
 
         assertEquals(RFXComUVMessage.SubType.UV3, msg.subType, "SubType");
         assertEquals(18, msg.seqNbr, "Seq Number");
index 798b2450e6d2100b61acb58c149a5cf648081821..0fe249b5edfcc9c33ba3c5f84bbec8411abbacb9 100644 (file)
@@ -32,7 +32,7 @@ public class RFXComUndecodedRFMessageTest {
 
     private void testMessage(String hexMsg, RFXComUndecodedRFMessage.SubType subType, int seqNbr, String rawPayload)
             throws RFXComException {
-        final RFXComUndecodedRFMessage msg = (RFXComUndecodedRFMessage) RFXComMessageFactory
+        final RFXComUndecodedRFMessage msg = (RFXComUndecodedRFMessage) RFXComMessageFactoryImpl.INSTANCE
                 .createMessage(HexUtils.hexToBytes(hexMsg));
         assertEquals(subType, msg.subType, "SubType");
         assertEquals(seqNbr, (short) (msg.seqNbr & 0xFF), "Seq Number");
@@ -51,7 +51,7 @@ public class RFXComUndecodedRFMessageTest {
 
     @Test
     public void testLongMessage() throws RFXComException {
-        RFXComUndecodedRFMessage msg = (RFXComUndecodedRFMessage) RFXComMessageFactory
+        RFXComUndecodedRFMessage msg = (RFXComUndecodedRFMessage) RFXComMessageFactoryImpl.INSTANCE
                 .createMessage(PacketType.UNDECODED_RF_MESSAGE);
         msg.subType = RFXComUndecodedRFMessage.SubType.ARC;
         msg.seqNbr = 1;
index 47c152057ced911ad9b975358392954a5b821aa4..163fd5c635f06cb5a1e77483bbb2705a04914644 100644 (file)
@@ -30,6 +30,6 @@ public class RFXComWaterMessageTest {
     @Test
     public void checkNotImplemented() {
         assertThrows(RFXComMessageNotImplementedException.class,
-                () -> RFXComMessageFactory.createMessage(PacketType.WATER));
+                () -> RFXComMessageFactoryImpl.INSTANCE.createMessage(PacketType.WATER));
     }
 }
index 98cec4aaff419f20d5551c6d28d29dfe44afa961..96789f029278e7aee4d0cbf4adcdc3d4dd1d37c4 100644 (file)
@@ -30,6 +30,6 @@ public class RFXComWeightMessageTest {
     public void checkNotImplemented() {
         // TODO Note that this message is supported in the 1.9 binding
         assertThrows(RFXComMessageNotImplementedException.class,
-                () -> RFXComMessageFactory.createMessage(PacketType.WEIGHT));
+                () -> RFXComMessageFactoryImpl.INSTANCE.createMessage(PacketType.WEIGHT));
     }
 }
index b089960ba03701746afef2fdf19dfb62e715598b..d6d621c2e43f9154cb63feaa23ba23c1c2bbb94e 100644 (file)
@@ -31,7 +31,7 @@ public class RFXComWindMessageTest {
     public void testSomeMessages() throws RFXComException {
         String hexMessage = "105601122F000087000000140000000079";
         byte[] message = HexUtils.hexToBytes(hexMessage);
-        RFXComWindMessage msg = (RFXComWindMessage) RFXComMessageFactory.createMessage(message);
+        RFXComWindMessage msg = (RFXComWindMessage) RFXComMessageFactoryImpl.INSTANCE.createMessage(message);
         assertEquals(WIND1, msg.subType, "SubType");
         assertEquals(18, msg.seqNbr, "Seq Number");
         assertEquals("12032", msg.getDeviceId(), "Sensor Id");