Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[rfxcom] Add support for receiving RAW messages #10833

Merged
merged 1 commit into from
Jun 14, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -883,6 +884,31 @@ A Rain device
* RAIN5 - WS2300
* RAIN6 - La Crosse TX5

### 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 @@ -145,6 +145,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");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just out of curiosity what is the difference with undecoded

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

UNDECODED is where the RFXCOM understands the type, but just hasn't broken it down into values. RAW is where the RFXCOM has received an RF message and hasn't tried to do anything to it at all, so the values are the ms pulse timings that would need to be processed into stable bytes before they could even be decoded.

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 @@ -169,19 +170,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 @@ -221,6 +223,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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a TODO, what should be done and can it be completed before merging the PR?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is really a TODO for when I implement tx, which is next. There is value in merging rx.

// 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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a TODO, what should be done and can it be completed before merging the PR?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is really a TODO for when I implement tx, which is next. There is value in merging rx.

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