diff --git a/bundles/org.openhab.binding.rfxcom/RESPONSES.md b/bundles/org.openhab.binding.rfxcom/RESPONSES.md new file mode 100644 index 000000000..f91e8b873 --- /dev/null +++ b/bundles/org.openhab.binding.rfxcom/RESPONSES.md @@ -0,0 +1,57 @@ +# Responses + +Record of responses to some commands for working out how things work. + +## Interface Message - Status Response + +These messages were received when testing different firmwares. + +``` +Ext 250 0D0100010253FA0400070001031C +Ext 251 0D0100010253FB0400070001031C +Ext 1001 140100010253010400070001031C03000000000000 +Pro1 1044 1401000102532C04000700010300055D0000000000 +Type1 1024 140100010253180000270001031C01000000000000 +Type1 95 0D01000102535F0000270001031C +Type2 195 0D0100010253C30080270001031C +Type2 1022 140100010253160080270001031C02000000000000 +``` + +## RFXMngr mode setting + +These messages were sent by RFXMngr when enabling single modes. + +On Pro1 firmware 1044 RFXtrx443 at 433.92MHZ +``` +enableUndecodedPackets 0D 00 00 03 03 53 00 80 00 00 00 00 00 00 +enableImagintronixOpusPackets 0D 00 00 04 03 53 00 40 00 00 00 00 00 00 +enableByronSXPackets 0D 00 00 05 03 53 00 20 00 00 00 00 00 00 +enableRSLPackets 0D 00 00 06 03 53 00 10 00 00 00 00 00 00 +enableLighting4Packets 0D 00 00 07 03 53 00 08 00 00 00 00 00 00 +enableFineOffsetPackets 0D 00 00 08 03 53 00 04 00 00 00 00 00 00 +enableRubicsonPackets 0D 00 00 09 03 53 00 02 00 00 00 00 00 00 +enableAEPackets 0D 00 00 0A 03 53 00 01 00 00 00 00 00 00 + +enableBlindsT1T2T3T4Packets 0D 00 00 0B 03 53 00 00 80 00 00 00 00 00 +enableBlindsT0Packets 0D 00 00 0C 03 53 00 00 40 00 00 00 00 00 +? Blank in RFXmngr 0D 00 00 0C 03 53 00 00 20 00 00 00 00 00 +Legrand CAD 0D 00 00 0E 03 53 00 00 10 00 00 00 00 00 +enableProGuardPackets Not in RFXmngr +enableFS20Packets Not in RFXmngr +enableLaCrossePackets 0D 00 00 0F 03 53 00 00 08 00 00 00 00 00 +enableHidekiUPMPackets 0D 00 00 10 03 53 00 00 04 00 00 00 00 00 +enableADPackets 0D 00 00 11 03 53 00 00 02 00 00 00 00 00 +enableMertikPackets 0D 00 00 12 03 53 00 00 01 00 00 00 00 00 + +enableVisonicPackets 0D 00 00 13 03 53 00 00 00 80 00 00 00 00 +enableATIPackets 0D 00 00 14 03 53 00 00 00 40 00 00 00 00 +enableOregonPackets 0D 00 00 14 03 53 00 00 00 20 00 00 00 00 +enableMeiantechPackets 0D 00 00 14 03 53 00 00 00 10 00 00 00 00 +enableHomeEasyPackets 0D 00 00 14 03 53 00 00 00 08 00 00 00 00 +enableACPackets 0D 00 00 14 03 53 00 00 00 04 00 00 00 00 +enableARCPackets 0D 00 00 14 03 53 00 00 00 02 00 00 00 00 +enableX10Packets 0D 00 00 14 03 53 00 00 00 01 00 00 00 00 + +enableHomeConfortPackets 0D 00 00 14 03 53 00 00 00 00 02 00 00 00 +enableKEELOQPackets 0D 00 00 14 03 53 00 00 00 00 01 00 00 00 +``` \ No newline at end of file diff --git a/bundles/org.openhab.binding.rfxcom/src/main/java/org/openhab/binding/rfxcom/internal/handler/RFXComBridgeHandler.java b/bundles/org.openhab.binding.rfxcom/src/main/java/org/openhab/binding/rfxcom/internal/handler/RFXComBridgeHandler.java index cc33c8e35..5ea7f9a9c 100644 --- a/bundles/org.openhab.binding.rfxcom/src/main/java/org/openhab/binding/rfxcom/internal/handler/RFXComBridgeHandler.java +++ b/bundles/org.openhab.binding.rfxcom/src/main/java/org/openhab/binding/rfxcom/internal/handler/RFXComBridgeHandler.java @@ -253,6 +253,15 @@ public class RFXComBridgeHandler extends BaseBridgeHandler { logger.debug("RFXCOM transceiver/receiver type: {}, hw version: {}.{}, fw version: {}", msg.transceiverType, msg.hardwareVersion1, msg.hardwareVersion2, msg.firmwareVersion); + if (msg.firmwareVersion < 1000) { + /** + * Versions before 1000 had some different behaviour, so lets encourage upgrading. + * 1001 was released in Feb 2016! + */ + logger.warn( + "RFXCOM device using outdated firmware (version {}), consider flashing with more a more recent version", + msg.firmwareVersion); + } thing.setProperty(Thing.PROPERTY_HARDWARE_VERSION, msg.hardwareVersion1 + "." + msg.hardwareVersion2); thing.setProperty(Thing.PROPERTY_FIRMWARE_VERSION, Integer.toString(msg.firmwareVersion)); diff --git a/bundles/org.openhab.binding.rfxcom/src/main/java/org/openhab/binding/rfxcom/internal/messages/RFXComInterfaceControlMessage.java b/bundles/org.openhab.binding.rfxcom/src/main/java/org/openhab/binding/rfxcom/internal/messages/RFXComInterfaceControlMessage.java index 1d7716f99..1ffe4d6b4 100644 --- a/bundles/org.openhab.binding.rfxcom/src/main/java/org/openhab/binding/rfxcom/internal/messages/RFXComInterfaceControlMessage.java +++ b/bundles/org.openhab.binding.rfxcom/src/main/java/org/openhab/binding/rfxcom/internal/messages/RFXComInterfaceControlMessage.java @@ -34,6 +34,17 @@ public class RFXComInterfaceControlMessage extends RFXComBaseMessage { data[5] = transceiverType.toByte(); data[6] = (byte) (configuration.transmitPower + 18); + /* + * These are actually dependent on the type of device and + * firmware, this list is mainly for RFXtrx443 at 433.92MHz, + * which most of our users use. + * + * TODO: At some point, we should reconcile this with the SDK + * and accommodate for other devices and protocols. This is + * probably not worth doing until someone needs it and has + * suitable devices to test with! + */ + //@formatter:off data[7] = (byte) ( (configuration.enableUndecoded ? 0x80 : 0x00) diff --git a/bundles/org.openhab.binding.rfxcom/src/main/java/org/openhab/binding/rfxcom/internal/messages/RFXComInterfaceMessage.java b/bundles/org.openhab.binding.rfxcom/src/main/java/org/openhab/binding/rfxcom/internal/messages/RFXComInterfaceMessage.java index fa70cc852..bf09db4bf 100644 --- a/bundles/org.openhab.binding.rfxcom/src/main/java/org/openhab/binding/rfxcom/internal/messages/RFXComInterfaceMessage.java +++ b/bundles/org.openhab.binding.rfxcom/src/main/java/org/openhab/binding/rfxcom/internal/messages/RFXComInterfaceMessage.java @@ -14,6 +14,7 @@ package org.openhab.binding.rfxcom.internal.messages; import static org.openhab.binding.rfxcom.internal.messages.ByteEnumUtil.fromByte; +import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; import org.openhab.binding.rfxcom.internal.exceptions.RFXComException; @@ -74,47 +75,68 @@ public class RFXComInterfaceMessage extends RFXComBaseMessage { } public enum TransceiverType implements ByteEnumWrapper { - _310MHZ(80), - _315MHZ(81), - _433_92MHZ_RECEIVER_ONLY(82), - _433_92MHZ_TRANSCEIVER(83), - _868_00MHZ(85), - _868_00MHZ_FSK(86), - _868_30MHZ(87), - _868_30MHZ_FSK(88), - _868_35MHZ(89), - _868_35MHZ_FSK(90), - _868_95MHZ_FSK(91); + _310MHZ(0x50, "RFXtrx315 operating at 310MHz"), + _315MHZ(0x51, "RFXtrx315 operating at 315MHz"), + _433_92MHZ_RECEIVER_ONLY(0x52, "RFXrec433 operating at 433.92MHz (receiver only)"), + _433_92MHZ_TRANSCEIVER(0x53, "RFXtrx433 operating at 433.92MHz"), + _433_42MHZ(0x54, "RFXtrx433 operating at 433.42MHz"), + _868_00MHZ(0x55, "RFXtrx868X operating at 868MHz"), + _868_00MHZ_FSK(0x56, "RFXtrx868X operating at 868.00MHz FSK"), + _868_30MHZ(0x57, "RFXtrx868X operating at 868.30MHz"), + _868_30MHZ_FSK(0x58, "RFXtrx868X operating at 868.30MHz FSK"), + _868_35MHZ(0x59, "RFXtrx868X operating at 868.35MHz"), + _868_35MHZ_FSK(0x5A, "RFXtrx868X operating at 868.35MHz FSK"), + _868_95MHZ_FSK(0x5B, "RFXtrx868X operating at 868.95MHz"), + _433_92MHZ_IOT(0x5C, "RFXtrxIOT operating at 433.92MHz"), + _868_00MHZ_IOT(0x5D, "RFXtrxIOT operating at 868MHz"), + _434_50MHZ(0x5F, "RFXtrx433 operating at 434.50MHz"); private final int type; + private final String name; - TransceiverType(int type) { + TransceiverType(int type, String name) { this.type = type; + this.name = name; } @Override public byte toByte() { return (byte) type; } + + @Override + public String toString() { + return name; + } } public enum FirmwareType implements ByteEnumWrapper { - TYPE1_RX_ONLY(0), - TYPE1(1), - TYPE2(2), - EXT(3), - EXT2(4); + TYPE1_RX_ONLY(0x00, "Type1 RFXrec receive only firmware"), + TYPE1(0x01, "Type1"), + TYPE2(0x02, "Type2"), + EXT(0x03, "Ext"), + EXT2(0x04, "Ext2"), + PRO1(0x05, "Pro1"), + PRO2(0x06, "Pro2"), + PROXL1(0x10, "ProXL 1"); private final int type; + private final String name; - FirmwareType(int type) { + FirmwareType(int type, String name) { this.type = type; + this.name = name; } @Override public byte toByte() { return (byte) type; } + + @Override + public String toString() { + return name; + } } public SubType subType; @@ -222,83 +244,104 @@ public class RFXComInterfaceMessage extends RFXComBaseMessage { subType = fromByte(SubType.class, super.subType); if (subType == SubType.RESPONSE) { - command = fromByte(Commands.class, data[4]); - transceiverType = fromByte(TransceiverType.class, data[5]); - - firmwareVersion = data[6] & 0xFF; - - enableUndecodedPackets = (data[7] & 0x80) != 0; - enableImagintronixOpusPackets = (data[7] & 0x40) != 0; - enableByronSXPackets = (data[7] & 0x20) != 0; - enableRSLPackets = (data[7] & 0x10) != 0; - enableLighting4Packets = (data[7] & 0x08) != 0; - enableFineOffsetPackets = (data[7] & 0x04) != 0; - enableRubicsonPackets = (data[7] & 0x02) != 0; - enableAEPackets = (data[7] & 0x01) != 0; - - enableBlindsT1T2T3T4Packets = (data[8] & 0x80) != 0; - enableBlindsT0Packets = (data[8] & 0x40) != 0; - enableProGuardPackets = (data[8] & 0x20) != 0; - enableFS20Packets = (data[8] & 0x10) != 0; - enableLaCrossePackets = (data[8] & 0x08) != 0; - enableHidekiUPMPackets = (data[8] & 0x04) != 0; - enableADPackets = (data[8] & 0x02) != 0; - enableMertikPackets = (data[8] & 0x01) != 0; - - enableVisonicPackets = (data[9] & 0x80) != 0; - enableATIPackets = (data[9] & 0x40) != 0; - enableOregonPackets = (data[9] & 0x20) != 0; - enableMeiantechPackets = (data[9] & 0x10) != 0; - enableHomeEasyPackets = (data[9] & 0x08) != 0; - enableACPackets = (data[9] & 0x04) != 0; - enableARCPackets = (data[9] & 0x02) != 0; - enableX10Packets = (data[9] & 0x01) != 0; - - /* - * Different firmware versions have slightly different message formats. - * The firmware version numbering is unique to each hardware version - * but the location of the hardware version in the message is one of - * those things whose position varies. So we have to just look at the - * firmware version and pray. This condition below is taken from the - * openhab1-addons binding. - */ - if ((firmwareVersion >= 95 && firmwareVersion <= 100) || (firmwareVersion >= 195 && firmwareVersion <= 200) - || (firmwareVersion >= 251)) { - enableHomeConfortPackets = (data[10] & 0x02) != 0; - enableKEELOQPackets = (data[10] & 0x01) != 0; - - hardwareVersion1 = data[11]; - hardwareVersion2 = data[12]; - - outputPower = data[13] - 18; - firmwareType = fromByte(FirmwareType.class, data[14]); - } else { - hardwareVersion1 = data[10]; - hardwareVersion2 = data[11]; - } - - text = ""; + encodeResponseMessage(data); } else if (subType == SubType.START_RECEIVER) { - command = fromByte(Commands.class, data[4]); - - final int len = 16; - final int dataOffset = 5; - - byte[] byteArray = new byte[len]; - - for (int i = dataOffset; i < (dataOffset + len); i++) { - byteArray[i - dataOffset] += data[i]; - } - - text = new String(byteArray, StandardCharsets.US_ASCII); + encodeStartReceiverMessage(data); } else { // We don't handle the other subTypes but to avoid null pointer // exceptions we set command to something. It doesn't really - // matter what but it may b printed in log messages so... + // matter what but it may be printed in log messages so... command = Commands.UNSUPPORTED_COMMAND; } } + private void encodeResponseMessage(byte[] data) throws RFXComException { + command = fromByte(Commands.class, data[4]); + transceiverType = fromByte(TransceiverType.class, data[5]); + + hardwareVersion1 = data[11]; + hardwareVersion2 = data[12]; + + outputPower = data[13] - 18; + + /* + * Firmware versions before 1000 did not include a firmware + * type in their response. Instead, versions 0-99 were for + * Type 1, versions 100-199 were for Type 2, and versions + * above 200 were for Ext. + * + * From version 1000, the response includes a longer message + * which adds a byte for firmware type. The version is calculated + * from the single byte, to which 1000 is added. + * + * Discovered through hints in the release notes and experimentation + * with RFXmngr. See RESPONSES.md for data. + */ + if (data.length > 14) { + firmwareVersion = Byte.toUnsignedInt(data[6]) + 1000; + firmwareType = fromByte(FirmwareType.class, data[14]); + } else { + firmwareVersion = Byte.toUnsignedInt(data[6]); + + if (firmwareVersion < 100) { + firmwareType = FirmwareType.TYPE1; + } else if (firmwareVersion < 200) { + firmwareType = FirmwareType.TYPE2; + } else { + firmwareType = FirmwareType.EXT; + } + } + + /* + * These are actually dependent on the type of device and + * firmware, this list is mainly for RFXtrx443 at 433.92MHz, + * which most of our users use. + * + * TODO: At some point, we should reconcile this with the SDK + * and accommodate for other devices and protocols. This is + * probably not worth doing until someone needs it and has + * suitable devices to test with! + */ + enableUndecodedPackets = (data[7] & 0x80) != 0; + enableImagintronixOpusPackets = (data[7] & 0x40) != 0; + enableByronSXPackets = (data[7] & 0x20) != 0; + enableRSLPackets = (data[7] & 0x10) != 0; + enableLighting4Packets = (data[7] & 0x08) != 0; + enableFineOffsetPackets = (data[7] & 0x04) != 0; + enableRubicsonPackets = (data[7] & 0x02) != 0; + enableAEPackets = (data[7] & 0x01) != 0; + + enableBlindsT1T2T3T4Packets = (data[8] & 0x80) != 0; + enableBlindsT0Packets = (data[8] & 0x40) != 0; + enableProGuardPackets = (data[8] & 0x20) != 0; + enableFS20Packets = (data[8] & 0x10) != 0; + enableLaCrossePackets = (data[8] & 0x08) != 0; + enableHidekiUPMPackets = (data[8] & 0x04) != 0; + enableADPackets = (data[8] & 0x02) != 0; + enableMertikPackets = (data[8] & 0x01) != 0; + + enableVisonicPackets = (data[9] & 0x80) != 0; + enableATIPackets = (data[9] & 0x40) != 0; + enableOregonPackets = (data[9] & 0x20) != 0; + enableMeiantechPackets = (data[9] & 0x10) != 0; + enableHomeEasyPackets = (data[9] & 0x08) != 0; + enableACPackets = (data[9] & 0x04) != 0; + enableARCPackets = (data[9] & 0x02) != 0; + enableX10Packets = (data[9] & 0x01) != 0; + + enableHomeConfortPackets = (data[10] & 0x02) != 0; + enableKEELOQPackets = (data[10] & 0x01) != 0; + + text = ""; + } + + private void encodeStartReceiverMessage(byte[] data) throws RFXComException { + command = fromByte(Commands.class, data[4]); + + ByteBuffer text_bytes = ByteBuffer.wrap(data, 5, data.length - 5); + text = StandardCharsets.US_ASCII.decode(text_bytes).toString(); + } + @Override public byte[] decodeMessage() { throw new UnsupportedOperationException(); diff --git a/bundles/org.openhab.binding.rfxcom/src/test/java/org/openhab/binding/rfxcom/internal/messages/RFXComInterfaceMessageTest.java b/bundles/org.openhab.binding.rfxcom/src/test/java/org/openhab/binding/rfxcom/internal/messages/RFXComInterfaceMessageTest.java index 6771efa07..16a45f922 100644 --- a/bundles/org.openhab.binding.rfxcom/src/test/java/org/openhab/binding/rfxcom/internal/messages/RFXComInterfaceMessageTest.java +++ b/bundles/org.openhab.binding.rfxcom/src/test/java/org/openhab/binding/rfxcom/internal/messages/RFXComInterfaceMessageTest.java @@ -13,16 +13,14 @@ package org.openhab.binding.rfxcom.internal.messages; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.openhab.binding.rfxcom.internal.messages.RFXComInterfaceMessage.Commands.*; -import static org.openhab.binding.rfxcom.internal.messages.RFXComInterfaceMessage.SubType.*; -import static org.openhab.binding.rfxcom.internal.messages.RFXComInterfaceMessage.SubType.START_RECEIVER; -import static org.openhab.binding.rfxcom.internal.messages.RFXComInterfaceMessage.TransceiverType._433_92MHZ_TRANSCEIVER; import org.eclipse.jdt.annotation.NonNullByDefault; import org.junit.jupiter.api.Test; import org.openhab.binding.rfxcom.internal.exceptions.RFXComException; import org.openhab.binding.rfxcom.internal.messages.RFXComInterfaceMessage.Commands; +import org.openhab.binding.rfxcom.internal.messages.RFXComInterfaceMessage.FirmwareType; import org.openhab.binding.rfxcom.internal.messages.RFXComInterfaceMessage.SubType; +import org.openhab.binding.rfxcom.internal.messages.RFXComInterfaceMessage.TransceiverType; import org.openhab.core.util.HexUtils; /** @@ -45,24 +43,73 @@ public class RFXComInterfaceMessageTest { @Test public void testWelcomeCopyRightMessage() throws RFXComException { - RFXComInterfaceMessage msg = testMessage("1401070307436F7079726967687420524658434F4D", START_RECEIVER, 3, - Commands.START_RECEIVER); + RFXComInterfaceMessage msg = testMessage("1401070307436F7079726967687420524658434F4D", SubType.START_RECEIVER, + 3, Commands.START_RECEIVER); assertEquals("Copyright RFXCOM", msg.text, "text"); } @Test public void testRespondOnUnknownMessage() throws RFXComException { - testMessage("0D01FF190053E2000C2701020000", UNKNOWN_COMMAND, 25, UNSUPPORTED_COMMAND); + testMessage("0D01FF190053E2000C2701020000", SubType.UNKNOWN_COMMAND, 25, Commands.UNSUPPORTED_COMMAND); + } + + private void testStatus(String message, TransceiverType transceiverType, FirmwareType firmwareType, + int firewareVersion) throws RFXComException { + RFXComInterfaceMessage msg = testMessage(message, SubType.RESPONSE, 1, Commands.GET_STATUS); + + assertEquals(transceiverType, msg.transceiverType, "transceiverType"); + assertEquals(firmwareType, msg.firmwareType, "firmwareType"); + assertEquals(firewareVersion, msg.firmwareVersion, "firmwareVersion"); } @Test - public void testStatusMessage() throws RFXComException { - RFXComInterfaceMessage msg = testMessage("1401000102530C0800270001031C04524658434F4D", RESPONSE, 1, GET_STATUS); + public void testStatus_Rfxtrx443_Ext_250() throws RFXComException { + testStatus("0D0100010253FA0400070001031C", TransceiverType._433_92MHZ_TRANSCEIVER, FirmwareType.EXT, 250); + } - assertEquals(_433_92MHZ_TRANSCEIVER, msg.transceiverType, "Command"); + @Test + public void testStatus_Rfxtrx443_Ext_251() throws RFXComException { + testStatus("0D0100010253FB0400070001031C", TransceiverType._433_92MHZ_TRANSCEIVER, FirmwareType.EXT, 251); + } - // TODO this is not correct, improvements for this have been made in the OH1 repo - assertEquals(12, msg.firmwareVersion, "firmwareVersion"); + @Test + public void testStatus_Rfxtrx443_Ext_1001() throws RFXComException { + testStatus("140100010253010400070001031C03000000000000", TransceiverType._433_92MHZ_TRANSCEIVER, + FirmwareType.EXT, 1001); + } + + @Test + public void testStatus_Rfxtrx443_Pro1_1044() throws RFXComException { + testStatus("1401000102532C04000700010300055D0000000000", TransceiverType._433_92MHZ_TRANSCEIVER, + FirmwareType.PRO1, 1044); + } + + @Test + public void testStatus_Rfxtrx443_Type1_95() throws RFXComException { + testStatus("0D01000102535F0000270001031C", TransceiverType._433_92MHZ_TRANSCEIVER, FirmwareType.TYPE1, 95); + } + + @Test + public void testStatus_Rfxtrx443_Type1_1024() throws RFXComException { + testStatus("140100010253180000270001031C01000000000000", TransceiverType._433_92MHZ_TRANSCEIVER, + FirmwareType.TYPE1, 1024); + } + + @Test + public void testStatus_Rfxtrx443_Type2_195() throws RFXComException { + testStatus("0D0100010253C30080270001031C", TransceiverType._433_92MHZ_TRANSCEIVER, FirmwareType.TYPE2, 195); + } + + @Test + public void testStatus_Rfxtrx443_Type2_1022() throws RFXComException { + testStatus("140100010253160080270001031C02000000000000", TransceiverType._433_92MHZ_TRANSCEIVER, + FirmwareType.TYPE2, 1022); + } + + @Test + public void testStatus_Rfxtrx443_Ext2_1012() throws RFXComException { + testStatus("1401000102530C0800270001031C04524658434F4D", TransceiverType._433_92MHZ_TRANSCEIVER, + FirmwareType.EXT2, 1012); } }