2 * Copyright (c) 2010-2023 Contributors to the openHAB project
4 * See the NOTICE file(s) distributed with this work for additional
7 * This program and the accompanying materials are made available under the
8 * terms of the Eclipse Public License 2.0 which is available at
9 * http://www.eclipse.org/legal/epl-2.0
11 * SPDX-License-Identifier: EPL-2.0
13 package org.openhab.binding.rfxcom.internal.messages;
15 import static org.junit.jupiter.api.Assertions.*;
16 import static org.openhab.binding.rfxcom.internal.RFXComBindingConstants.*;
17 import static org.openhab.binding.rfxcom.internal.RFXComTestHelper.*;
18 import static org.openhab.binding.rfxcom.internal.messages.RFXComBaseMessage.PacketType.LIGHTING4;
19 import static org.openhab.binding.rfxcom.internal.messages.RFXComLighting4Message.SubType.PT2262;
21 import java.util.Arrays;
22 import java.util.List;
25 import org.eclipse.jdt.annotation.NonNullByDefault;
26 import org.eclipse.jdt.annotation.Nullable;
27 import org.junit.jupiter.api.Test;
28 import org.openhab.binding.rfxcom.internal.RFXComTestHelper;
29 import org.openhab.binding.rfxcom.internal.config.RFXComDeviceConfiguration;
30 import org.openhab.binding.rfxcom.internal.config.RFXComLighting4DeviceConfiguration;
31 import org.openhab.binding.rfxcom.internal.exceptions.RFXComException;
32 import org.openhab.binding.rfxcom.internal.exceptions.RFXComInvalidStateException;
33 import org.openhab.binding.rfxcom.internal.messages.RFXComBaseMessage.PacketType;
34 import org.openhab.core.config.discovery.DiscoveryResultBuilder;
35 import org.openhab.core.library.types.OnOffType;
36 import org.openhab.core.library.types.OpenClosedType;
37 import org.openhab.core.thing.ChannelUID;
38 import org.openhab.core.thing.ThingUID;
39 import org.openhab.core.types.Command;
40 import org.openhab.core.util.HexUtils;
43 * Test for RFXCom-binding
45 * @author Martin van Wingerden - Initial contribution
48 public class RFXComLighting4MessageTest {
49 static public final ChannelUID contactChannelUID = new ChannelUID(thingUID, CHANNEL_CONTACT);
51 static public void checkDiscoveryResult(RFXComDeviceMessage<RFXComLighting4Message.SubType> msg, String deviceId,
52 @Nullable Integer pulse, String subType) throws RFXComException {
53 String thingUID = "homeduino:rfxcom:fssfsd:thing";
54 DiscoveryResultBuilder builder = DiscoveryResultBuilder.create(new ThingUID(thingUID));
56 // check whether the pulse is stored
57 msg.addDevicePropertiesTo(builder);
59 Map<String, Object> properties = builder.build().getProperties();
60 assertEquals(deviceId, properties.get("deviceId"), "Device Id");
61 assertEquals(subType, properties.get("subType"), "Sub type");
63 assertEquals(pulse, properties.get("pulse"), "Pulse");
68 public void basicBoundaryCheck() throws RFXComException {
69 RFXComLighting4DeviceConfiguration config = new RFXComLighting4DeviceConfiguration();
70 config.deviceId = "90000";
71 config.subType = "PT2262";
74 RFXComLighting4Message message = (RFXComLighting4Message) RFXComMessageFactoryImpl.INSTANCE
75 .createMessage(LIGHTING4, config, commandChannelUID, OnOffType.ON);
77 byte[] binaryMessage = message.decodeMessage();
78 RFXComLighting4Message msg = (RFXComLighting4Message) RFXComMessageFactoryImpl.INSTANCE
79 .createMessage(binaryMessage);
81 assertEquals("90000", msg.getDeviceId(), "Sensor Id");
84 private void testMessageWithoutCommandIds(String hexMsg, RFXComLighting4Message.SubType subType, String deviceId,
85 @Nullable Integer pulse, int commandByte, @Nullable Integer seqNbr, int signalLevel, Command command)
86 throws RFXComException {
87 // These tests rely on the deprecated behaviour of a "known" set of ON/OFF values and will
88 // be removed in a later release to be replaced with test that check we throw an exception
89 // if the config isn't specified (see the open/closed tests).
90 RFXComLighting4DeviceConfiguration config = new RFXComLighting4DeviceConfiguration();
91 config.deviceId = deviceId;
92 config.subType = subType.toString();
94 RFXComLighting4Message msg = (RFXComLighting4Message) RFXComMessageFactoryImpl.INSTANCE
95 .createMessage(HexUtils.hexToBytes(hexMsg));
96 assertEquals(deviceId, msg.getDeviceId(), "Sensor Id");
97 assertEquals(commandByte, RFXComTestHelper.getActualIntValue(msg, config, CHANNEL_COMMAND_ID), "Command");
99 assertEquals(seqNbr.shortValue(), (short) (msg.seqNbr & 0xFF), "Seq Number");
101 assertEquals(signalLevel, RFXComTestHelper.getActualIntValue(msg, config, CHANNEL_SIGNAL_LEVEL),
103 assertEquals(command, msg.convertToCommand(CHANNEL_COMMAND, config, null));
105 byte[] decoded = msg.decodeMessage();
107 assertEquals(hexMsg, HexUtils.bytesToHex(decoded), "Message converted back");
109 checkDiscoveryResult(msg, deviceId, pulse, subType.toString());
113 public void testSomeMessages() throws RFXComException {
114 testMessageWithoutCommandIds("091300E1D8AD59018F70", PT2262, "887509", 399, 9, 225, 2, OnOffType.ON);
115 testMessageWithoutCommandIds("0913005FA9A9C901A170", PT2262, "694940", 417, 9, 95, 2, OnOffType.ON);
116 testMessageWithoutCommandIds("091300021D155C01E960", PT2262, "119125", 489, 12, 2, 2, OnOffType.ON);
117 testMessageWithoutCommandIds("091300D345DD99018C50", PT2262, "286169", 396, 9, 211, 2, OnOffType.ON);
118 testMessageWithoutCommandIds("09130035D149A2017750", PT2262, "857242", 375, 2, 53, 2, OnOffType.OFF);
119 testMessageWithoutCommandIds("0913000B4E462A012280", PT2262, "320610", 290, 10, 11, 3, OnOffType.ON);
120 testMessageWithoutCommandIds("09130009232D2E013970", PT2262, "144082", 313, 14, 9, 2, OnOffType.OFF);
121 testMessageWithoutCommandIds("091300CA0F8D2801AA70", PT2262, "63698", 426, 8, 202, 2, OnOffType.ON);
125 public void testSomeAlarmRemote() throws RFXComException {
126 testMessageWithoutCommandIds("0913004A0D8998016E60", PT2262, "55449", 366, 8, 74, 2, OnOffType.ON);
130 public void testCheapPirSensor() throws RFXComException {
131 testMessageWithoutCommandIds("091300EF505FC6019670", PT2262, "329212", 406, 6, 239, 2, OnOffType.ON);
135 public void testSomeConradMessages() throws RFXComException {
136 testMessageWithoutCommandIds("0913003554545401A150", PT2262, "345413", 417, 4, 53, 2, OnOffType.OFF);
140 public void testPhenixMessages() throws RFXComException {
141 List<String> onMessages = Arrays.asList("09130046044551013780", "09130048044551013780", "0913004A044551013980",
142 "0913004C044551013780", "0913004E044551013780");
144 for (String message : onMessages) {
145 testMessageWithoutCommandIds(message, PT2262, "17493", null, 1, null, 3, OnOffType.ON);
148 List<String> offMessages = Arrays.asList("09130051044554013980", "09130053044554013680", "09130055044554013680",
149 "09130057044554013680", "09130059044554013680", "0913005B044554013680", "0913005D044554013480",
150 "09130060044554013980", "09130062044554013680", "09130064044554013280");
152 for (String message : offMessages) {
153 testMessageWithoutCommandIds(message, PT2262, "17493", null, 4, null, 3, OnOffType.OFF);
157 private void testRxWithConfig(String hexMsg, RFXComDeviceConfiguration config,
158 RFXComLighting4Message.SubType subType, String deviceId, @Nullable Integer pulse, int commandByte,
159 @Nullable Integer seqNbr, int signalLevel, ChannelUID channelUID, Command command) throws RFXComException {
160 RFXComLighting4Message msg = (RFXComLighting4Message) RFXComMessageFactoryImpl.INSTANCE
161 .createMessage(HexUtils.hexToBytes(hexMsg));
162 assertEquals(deviceId, msg.getDeviceId(), "Sensor Id");
163 assertEquals(commandByte, RFXComTestHelper.getActualIntValue(msg, config, CHANNEL_COMMAND_ID), "Command");
164 if (seqNbr != null) {
165 assertEquals(seqNbr.shortValue(), (short) (msg.seqNbr & 0xFF), "Seq Number");
167 assertEquals(signalLevel, RFXComTestHelper.getActualIntValue(msg, config, CHANNEL_SIGNAL_LEVEL),
169 assertEquals(command, msg.convertToCommand(channelUID.getId(), config, null));
171 byte[] decoded = msg.decodeMessage();
173 assertEquals(hexMsg, HexUtils.bytesToHex(decoded), "Message converted back");
175 checkDiscoveryResult(msg, deviceId, pulse, subType.toString());
179 public void testRxWithFullConfig() throws RFXComException {
180 RFXComLighting4DeviceConfiguration config = new RFXComLighting4DeviceConfiguration();
181 config.deviceId = "12345";
182 config.subType = PT2262.toString();
183 config.onCommandId = 0xA;
184 config.offCommandId = 0xB;
185 config.openCommandId = 0xC;
186 config.closedCommandId = 0xD;
188 testRxWithConfig("0913003503039A01A150", config, PT2262, "12345", 417, 0xA, 53, 2, commandChannelUID,
190 testRxWithConfig("0913003503039B01A150", config, PT2262, "12345", 417, 0xB, 53, 2, commandChannelUID,
192 testRxWithConfig("0913003503039C01A150", config, PT2262, "12345", 417, 0xC, 53, 2, contactChannelUID,
193 OpenClosedType.OPEN);
194 testRxWithConfig("0913003503039D01A150", config, PT2262, "12345", 417, 0xD, 53, 2, contactChannelUID,
195 OpenClosedType.CLOSED);
199 public void testRxWithPartialConfig() throws RFXComException {
200 RFXComLighting4DeviceConfiguration config = new RFXComLighting4DeviceConfiguration();
201 config.deviceId = "12345";
202 config.subType = PT2262.toString();
203 config.onCommandId = 0xA;
204 config.openCommandId = 0xC;
206 testRxWithConfig("0913003503039A01A150", config, PT2262, "12345", 417, 0xA, 53, 2, commandChannelUID,
208 assertThrows(RFXComInvalidStateException.class, () -> testRxWithConfig("0913003503039B01A150", config, PT2262,
209 "12345", 417, 0xB, 53, 2, commandChannelUID, OnOffType.OFF));
210 testRxWithConfig("0913003503039C01A150", config, PT2262, "12345", 417, 0xC, 53, 2, contactChannelUID,
211 OpenClosedType.OPEN);
212 assertThrows(RFXComInvalidStateException.class, () -> testRxWithConfig("0913003503039D01A150", config, PT2262,
213 "12345", 417, 0xD, 53, 2, contactChannelUID, OpenClosedType.CLOSED));
217 public void testRxWithNoConfig() throws RFXComException {
218 RFXComLighting4DeviceConfiguration config = new RFXComLighting4DeviceConfiguration();
219 config.deviceId = "12345";
220 config.subType = PT2262.toString();
222 // These will fall back on deprecated behaviour, but should all be assertThrows in the future.
223 testRxWithConfig("0913003503039A01A150", config, PT2262, "12345", 417, 0xA, 53, 2, commandChannelUID,
225 testRxWithConfig("0913003503039B01A150", config, PT2262, "12345", 417, 0xB, 53, 2, commandChannelUID,
227 testRxWithConfig("0913003503039C01A150", config, PT2262, "12345", 417, 0xC, 53, 2, contactChannelUID,
228 OpenClosedType.OPEN);
229 testRxWithConfig("0913003503039D01A150", config, PT2262, "12345", 417, 0xD, 53, 2, contactChannelUID,
230 OpenClosedType.OPEN);
233 private void testTxWithConfig(RFXComDeviceConfiguration config, ChannelUID channelUID, Command command,
234 RFXComLighting4Message.SubType subType, String deviceId, @Nullable Integer pulse, int commandByte,
235 String hexMsg) throws RFXComException {
236 RFXComLighting4Message msg = (RFXComLighting4Message) RFXComMessageFactoryImpl.INSTANCE
237 .createMessage(PacketType.LIGHTING4, config, channelUID, command);
238 assertEquals(deviceId, msg.getDeviceId(), "Sensor Id");
239 assertEquals(commandByte, RFXComTestHelper.getActualIntValue(msg, config, CHANNEL_COMMAND_ID), "Command");
240 assertEquals(0, msg.seqNbr & 0xFF, "Seq Number");
241 assertEquals(0, RFXComTestHelper.getActualIntValue(msg, config, CHANNEL_SIGNAL_LEVEL), "Signal Level");
242 assertEquals(hexMsg, HexUtils.bytesToHex(msg.decodeMessage()), "Message bytes");
246 void testTxWithFullConfig() throws RFXComException {
247 RFXComLighting4DeviceConfiguration config = new RFXComLighting4DeviceConfiguration();
248 config.deviceId = "703696";
249 config.subType = PT2262.toString();
250 config.onCommandId = 0xA;
251 config.offCommandId = 0xB;
252 config.openCommandId = 0xC;
253 config.closedCommandId = 0xD;
256 testTxWithConfig(config, commandChannelUID, OnOffType.ON, PT2262, "703696", 417, 0xA, "09130000ABCD0A01A100");
257 testTxWithConfig(config, commandChannelUID, OnOffType.OFF, PT2262, "703696", 417, 0xB, "09130000ABCD0B01A100");
258 testTxWithConfig(config, contactChannelUID, OpenClosedType.OPEN, PT2262, "703696", 417, 0xC,
259 "09130000ABCD0C01A100");
260 testTxWithConfig(config, contactChannelUID, OpenClosedType.CLOSED, PT2262, "703696", 417, 0xD,
261 "09130000ABCD0D01A100");
265 void testTxWithPartialConfig() throws RFXComException {
266 RFXComLighting4DeviceConfiguration config = new RFXComLighting4DeviceConfiguration();
267 config.deviceId = "703696";
268 config.subType = PT2262.toString();
269 config.onCommandId = 0xA;
270 config.openCommandId = 0xC;
273 testTxWithConfig(config, commandChannelUID, OnOffType.ON, PT2262, "703696", 417, 0xA, "09130000ABCD0A01A100");
274 // Falls back on deprecated behaviour, but should be assertThrows in the future.
275 testTxWithConfig(config, commandChannelUID, OnOffType.OFF, PT2262, "703696", 417, 0x4, "09130000ABCD0401A100");
276 testTxWithConfig(config, contactChannelUID, OpenClosedType.OPEN, PT2262, "703696", 417, 0xC,
277 "09130000ABCD0C01A100");
278 assertThrows(RFXComInvalidStateException.class, () -> testTxWithConfig(config, contactChannelUID,
279 OpenClosedType.CLOSED, PT2262, "703696", 417, 0xD, "??"));
283 void testTxWithNoConfig() throws RFXComException {
284 RFXComLighting4DeviceConfiguration config = new RFXComLighting4DeviceConfiguration();
285 config.deviceId = "703696";
286 config.subType = PT2262.toString();
289 // Falls back on deprecated behaviour, but should be assertThrows in the future.
290 testTxWithConfig(config, commandChannelUID, OnOffType.ON, PT2262, "703696", 417, 0x1, "09130000ABCD0101A100");
291 // Falls back on deprecated behaviour, but should be assertThrows in the future.
292 testTxWithConfig(config, commandChannelUID, OnOffType.OFF, PT2262, "703696", 417, 0x4, "09130000ABCD0401A100");
293 assertThrows(RFXComInvalidStateException.class, () -> testTxWithConfig(config, contactChannelUID,
294 OpenClosedType.OPEN, PT2262, "703696", 417, 0xC, "??"));
295 assertThrows(RFXComInvalidStateException.class, () -> testTxWithConfig(config, contactChannelUID,
296 OpenClosedType.CLOSED, PT2262, "703696", 417, 0xD, "??"));