Skip to content

Commit

Permalink
[rfxcom] Add support for receiving RAW messages (openhab#10833)
Browse files Browse the repository at this point in the history
This is a new feature in the Pro firmwares that provides the real raw RF
pulse lengths as shorts. Good for being able to parrot switches that aren't
otherwise supported, once we add the tx support as well.

Signed-off-by: James Hewitt <james.hewitt@uk.ibm.com>
  • Loading branch information
Jamstah authored and thinkingstone committed Nov 7, 2021
1 parent 09e9080 commit 784a336
Show file tree
Hide file tree
Showing 8 changed files with 338 additions and 17 deletions.
28 changes: 27 additions & 1 deletion bundles/org.openhab.binding.rfxcom/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ This binding currently supports following channel types:
| 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 |
| rawpayload | String | Hexadecimal representation of payload RFXCOM messages |
| rawpayload | String | Hexadecimal representation of the payload of RFXCOM messages |
| setpoint | Number | Requested temperature. |
| shutter | Rollershutter | Shutter/blind channel. |
| status | String | Status channel. |
Expand Down Expand Up @@ -229,6 +229,7 @@ This binding currently supports the following things / message types:
* [lighting5 - RFXCOM Lighting5 Actuator](#lighting5---rfxcom-lighting5-actuator)
* [lighting6 - RFXCOM Lighting6 Actuator](#lighting6---rfxcom-lighting6-actuator)
* [rain - RFXCOM Rain Sensor](#rain---rfxcom-rain-sensor)
* [raw - RFXCOM Raw Messages](#raw---rfxcom-raw-messages)
* [rfxsensor - RFXCOM rfxsensor](#rfxsensor)
* [rfy - RFXCOM Rfy Actuator](#rfy---rfxcom-rfy-actuator)
* [security1 - RFXCOM Security1 Sensor](#security1---rfxcom-security1-sensor)
Expand Down Expand Up @@ -884,6 +885,31 @@ A Rain device
* RAIN6 - La Crosse TX5
* RAIN9 - TFA 30.3233.1

### raw - RFXCOM Raw Messages

Raw messages.

#### Channels

| Name | Channel Type | Item Type | Remarks |
|------------|---------------------------|-----------|-------------|
| rawMessage | [rawmessage](#channels) | String | |
| rawPayload | [rawpayload](#channels) | String | |

#### Configuration Options

* deviceId - Device Id
* Raw items cannot provide a device ID, so this value is always RAW.

* subType - Sub Type
* Specifies message sub type.

* RAW_PACKET1
* RAW_PACKET2
* RAW_PACKET3
* RAW_PACKET4


### rfxsensor - RFXCOM RFXSensor

A RFXSensor sensor
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ public class RFXComBindingConstants {
private static final ThingTypeUID THING_TYPE_POWER = new ThingTypeUID(BINDING_ID, "power");
private static final ThingTypeUID THING_TYPE_RADIATOR1 = new ThingTypeUID(BINDING_ID, "radiator1");
private static final ThingTypeUID THING_TYPE_RAIN = new ThingTypeUID(BINDING_ID, "rain");
private static final ThingTypeUID THING_TYPE_RAW = new ThingTypeUID(BINDING_ID, "raw");
private static final ThingTypeUID THING_TYPE_REMOTE_CONTROL = new ThingTypeUID(BINDING_ID, "remotecontrol");
private static final ThingTypeUID THING_TYPE_RFX_METER = new ThingTypeUID(BINDING_ID, "rfxmeter");
private static final ThingTypeUID THING_TYPE_RFX_SENSOR = new ThingTypeUID(BINDING_ID, "rfxsensor");
Expand All @@ -171,19 +172,20 @@ public class RFXComBindingConstants {
/**
* Presents all supported Thing types by RFXCOM binding.
*/
public static final Set<ThingTypeUID> SUPPORTED_DEVICE_THING_TYPES_UIDS = Collections.unmodifiableSet(Stream.of(
THING_TYPE_BAROMETRIC, THING_TYPE_BBQ_TEMPERATURE, THING_TYPE_BLINDS1, THING_TYPE_CAMERA1, THING_TYPE_CHIME,
THING_TYPE_CURRENT, THING_TYPE_CURRENT_ENERGY, THING_TYPE_CURTAIN1, THING_TYPE_DATE_TIME, THING_TYPE_ENERGY,
THING_TYPE_FAN, THING_TYPE_FAN_SF01, THING_TYPE_FAN_ITHO, THING_TYPE_FAN_SEAV, THING_TYPE_FAN_LUCCI_DC,
THING_TYPE_FAN_FT1211R, THING_TYPE_FAN_FALMEC, THING_TYPE_FAN_LUCCI_DC_II, THING_TYPE_GAS_USAGE,
THING_TYPE_HOME_CONFORT, THING_TYPE_HUMIDITY, THING_TYPE_IO_LINES, THING_TYPE_LIGHTNING1,
THING_TYPE_LIGHTNING2, THING_TYPE_LIGHTNING3, THING_TYPE_LIGHTNING4, THING_TYPE_LIGHTNING5,
THING_TYPE_LIGHTNING6, THING_TYPE_POWER, THING_TYPE_RADIATOR1, THING_TYPE_RAIN, THING_TYPE_REMOTE_CONTROL,
THING_TYPE_RFX_METER, THING_TYPE_RFX_SENSOR, THING_TYPE_RFY, THING_TYPE_SECURITY1, THING_TYPE_SECURITY2,
THING_TYPE_TEMPERATURE, THING_TYPE_TEMPERATURE_HUMIDITY, THING_TYPE_TEMPERATURE_HUMIDITY_BAROMETRIC,
THING_TYPE_TEMPERATURE_RAIN, THING_TYPE_THERMOSTAT1, 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()));
public static final Set<ThingTypeUID> SUPPORTED_DEVICE_THING_TYPES_UIDS = Collections
.unmodifiableSet(Stream.of(THING_TYPE_BAROMETRIC, THING_TYPE_BBQ_TEMPERATURE, THING_TYPE_BLINDS1,
THING_TYPE_CAMERA1, THING_TYPE_CHIME, THING_TYPE_CURRENT, THING_TYPE_CURRENT_ENERGY,
THING_TYPE_CURTAIN1, THING_TYPE_DATE_TIME, THING_TYPE_ENERGY, THING_TYPE_FAN, THING_TYPE_FAN_SF01,
THING_TYPE_FAN_ITHO, THING_TYPE_FAN_SEAV, THING_TYPE_FAN_LUCCI_DC, THING_TYPE_FAN_FT1211R,
THING_TYPE_FAN_FALMEC, THING_TYPE_FAN_LUCCI_DC_II, THING_TYPE_GAS_USAGE, THING_TYPE_HOME_CONFORT,
THING_TYPE_HUMIDITY, THING_TYPE_IO_LINES, THING_TYPE_LIGHTNING1, THING_TYPE_LIGHTNING2,
THING_TYPE_LIGHTNING3, THING_TYPE_LIGHTNING4, THING_TYPE_LIGHTNING5, THING_TYPE_LIGHTNING6,
THING_TYPE_POWER, THING_TYPE_RADIATOR1, THING_TYPE_RAIN, THING_TYPE_RAW, THING_TYPE_REMOTE_CONTROL,
THING_TYPE_RFX_METER, THING_TYPE_RFX_SENSOR, THING_TYPE_RFY, THING_TYPE_SECURITY1,
THING_TYPE_SECURITY2, THING_TYPE_TEMPERATURE, THING_TYPE_TEMPERATURE_HUMIDITY,
THING_TYPE_TEMPERATURE_HUMIDITY_BAROMETRIC, THING_TYPE_TEMPERATURE_RAIN, THING_TYPE_THERMOSTAT1,
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 RFXCOM packet types to RFXCOM Thing types and vice versa.
Expand Down Expand Up @@ -223,6 +225,7 @@ public class RFXComBindingConstants {
put(PacketType.POWER, RFXComBindingConstants.THING_TYPE_POWER);
put(PacketType.RADIATOR1, RFXComBindingConstants.THING_TYPE_RADIATOR1);
put(PacketType.RAIN, RFXComBindingConstants.THING_TYPE_RAIN);
put(PacketType.RAW, RFXComBindingConstants.THING_TYPE_RAW);
put(PacketType.REMOTE_CONTROL, RFXComBindingConstants.THING_TYPE_REMOTE_CONTROL);
put(PacketType.RFXMETER, RFXComBindingConstants.THING_TYPE_RFX_METER);
put(PacketType.RFXSENSOR, RFXComBindingConstants.THING_TYPE_RFX_SENSOR);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ public enum PacketType implements ByteEnumWrapper {
RFXSENSOR(112),
RFXMETER(113),
FS20(114),
RAW(127),
IO_LINES(128);

private final int packetType;
Expand Down Expand Up @@ -163,7 +164,7 @@ public String toString() {
}

str += ", Packet type = " + packetType;
str += ", Seq number = " + (short) (seqNbr & 0xFF);
str += ", Seq number = " + Byte.toUnsignedInt(seqNbr);

return str;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ public class RFXComMessageFactory {
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);
}
});
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
/**
* 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 static org.openhab.binding.rfxcom.internal.RFXComBindingConstants.*;
import static org.openhab.binding.rfxcom.internal.messages.RFXComBaseMessage.PacketType.RAW;

import java.nio.ByteBuffer;

import org.openhab.binding.rfxcom.internal.exceptions.RFXComException;
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.StringType;
import org.openhab.core.types.State;
import org.openhab.core.types.Type;
import org.openhab.core.util.HexUtils;

/**
* RFXCOM data class for raw messages.
*
* @author James Hewitt-Thomas - New addition to the PRO RFXCom firmware
*/
public class RFXComRawMessage extends RFXComDeviceMessageImpl<RFXComRawMessage.SubType> {

public enum SubType implements ByteEnumWrapper {
RAW_PACKET1(0x00),
RAW_PACKET2(0x01),
RAW_PACKET3(0x02),
RAW_PACKET4(0x03),

UNKNOWN(0xFF);

private final int subType;

SubType(int subType) {
this.subType = subType;
}

@Override
public byte toByte() {
return (byte) subType;
}

public static SubType fromByte(int input) {
for (SubType c : SubType.values()) {
if (c.subType == input) {
return c;
}
}

return SubType.UNKNOWN;
}
}

public SubType subType;
public byte repeat;
public short[] pulses;

public RFXComRawMessage() {
super(RAW);
pulses = new short[0];
}

public RFXComRawMessage(byte[] message) throws RFXComException {
encodeMessage(message);
}

@Override
public String toString() {
String str = super.toString();

str += ", Sub type = " + subType;

return str;
}

@Override
public void encodeMessage(byte[] message) throws RFXComException {
super.encodeMessage(message);

final int pulsesByteLen = rawMessage.length - 5;
if (pulsesByteLen % 4 != 0) {
throw new RFXComException("Incorrect byte length for pulses - must be divisible by 4");
}

subType = SubType.fromByte(super.subType);
repeat = rawMessage[4];
pulses = new short[pulsesByteLen / 2];
ByteBuffer.wrap(rawMessage, 5, rawMessage.length - 5).asShortBuffer().get(pulses);
}

@Override
public byte[] decodeMessage() throws RFXComException {
if (pulses.length > 124) {
throw new RFXComMessageTooLongException("Longest payload according to RFXtrx SDK is 124 shorts.");
}

final int pulsesByteLen = pulses.length * 2;
byte[] data = new byte[5 + pulsesByteLen];

data[0] = (byte) (data.length - 1);
data[1] = RAW.toByte();
data[2] = subType.toByte();
data[3] = seqNbr;
data[4] = repeat;

ByteBuffer.wrap(data, 5, pulsesByteLen).asShortBuffer().put(pulses);

return data;
}

@Override
public String getDeviceId() {
return "RAW";
}

@Override
public State convertToState(String channelId, DeviceState deviceState) throws RFXComUnsupportedChannelException {
switch (channelId) {
case CHANNEL_RAW_MESSAGE:
return new StringType(HexUtils.bytesToHex(rawMessage));

case CHANNEL_RAW_PAYLOAD:
byte[] payload = new byte[pulses.length * 2];
ByteBuffer.wrap(payload).asShortBuffer().put(pulses);
return new StringType(HexUtils.bytesToHex(payload));

default:
throw new RFXComUnsupportedChannelException("Nothing relevant for " + channelId);
}
}

@Override
public void setSubType(SubType subType) {
throw new UnsupportedOperationException();
}

@Override
public void setDeviceId(String deviceId) {
throw new UnsupportedOperationException();
}

@Override
public void convertFromState(String channelId, Type type) throws RFXComUnsupportedChannelException {
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");
} 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);
}

default:
throw new RFXComUnsupportedChannelException("Channel " + channelId + " is not relevant here");
}
}

@Override
public SubType convertSubType(String subType) throws RFXComUnsupportedValueException {
return ByteEnumUtil.convertSubType(SubType.class, subType);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@
<channel-type id="rawmessage">
<item-type>String</item-type>
<label>Raw Message</label>
<description>Hexadecimal representation of undecoded RFXCOM messages including header and payload</description>
<description>Hexadecimal representation of RFXCOM messages including header and payload</description>
</channel-type>

<channel-type id="rawpayload">
<item-type>String</item-type>
<label>Raw Payload</label>
<description>Hexadecimal representation of payload of undecoded RFXCOM messages</description>
<description>Hexadecimal representation of payload of raw and undecoded RFXCOM messages</description>
</channel-type>

<channel-type id="command">
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="rfxcom"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">

<thing-type id="raw">
<supported-bridge-type-refs>
<bridge-type-ref id="bridge"/>
<bridge-type-ref id="tcpbridge"/>
<bridge-type-ref id="RFXtrx433"/>
<bridge-type-ref id="RFXrec433"/>
</supported-bridge-type-refs>

<label>RFXCOM Raw Messages</label>
<description>Raw messages.</description>

<channels>
<channel id="rawMessage" typeId="rawmessage"/>
<channel id="rawPayload" typeId="rawpayload"/>
</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>
</parameter>
<parameter name="subType" type="text" required="true">
<label>Sub Type</label>
<description>Specifies device sub type.</description>
<options>
<option value="RAW_PACKET1">RAW_PACKET1</option>
<option value="RAW_PACKET2">RAW_PACKET2</option>
<option value="RAW_PACKET3">RAW_PACKET3</option>
<option value="RAW_PACKET4">RAW_PACKET4</option>
</options>
</parameter>
</config-description>
</thing-type>

</thing:thing-descriptions>
Loading

0 comments on commit 784a336

Please sign in to comment.