[rfxcom] Update interface message support ()

Based on both the SDK and experimentation, this commit correctly identifies the
firmware and hardware version. A warning has been added for people with really
old firmware that may be different, but we didn't handle those different cases
well anyway.

Also includes updated firmware types and device types and support for pretty-
printing of the device and firmware type.

Signed-off-by: James Hewitt <james.hewitt@uk.ibm.com>
This commit is contained in:
James Hewitt 2021-06-15 18:37:07 +01:00 committed by GitHub
parent 82dba8d400
commit 8c7c37a7f5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 266 additions and 99 deletions
bundles/org.openhab.binding.rfxcom
RESPONSES.md
src
main/java/org/openhab/binding/rfxcom/internal
test/java/org/openhab/binding/rfxcom/internal/messages

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

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

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

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

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