[rfxcom] Enable Raw message transmission (#10866)

This enables raw message transmission by configuring a raw thing with pulses to
send for either ON, OFF, OPEN or CLOSED commands.

To enable extended config, this includes a refactor for the RFXComHandler to
support different Configuration objects depending on the thing type, and moves
the parsing, validation, and message matching logic to the Configuration objects
where the logic is more appropriate.

To enable testing of the RFXComHandler, the RFXComMessageFactory was abstracted
out and injected as a dependency.

Signed-off-by: James Hewitt <james.hewitt@uk.ibm.com>
This commit is contained in:
James Hewitt
2021-06-24 18:37:37 +01:00
committed by GitHub
parent c5c2cab0a7
commit 6403e03cea
74 changed files with 1199 additions and 330 deletions

View File

@@ -12,6 +12,7 @@
*/
package org.openhab.binding.rfxcom.internal;
import java.util.AbstractMap;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
@@ -20,6 +21,9 @@ import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.rfxcom.internal.config.RFXComDeviceConfiguration;
import org.openhab.binding.rfxcom.internal.config.RFXComLighting4DeviceConfiguration;
import org.openhab.binding.rfxcom.internal.config.RFXComRawDeviceConfiguration;
import org.openhab.binding.rfxcom.internal.messages.RFXComBaseMessage.PacketType;
import org.openhab.core.thing.ThingTypeUID;
@@ -65,6 +69,7 @@ public class RFXComBindingConstants {
// List of all Channel ids
public static final String CHANNEL_RAW_MESSAGE = "rawMessage";
public static final String CHANNEL_RAW_PAYLOAD = "rawPayload";
public static final String CHANNEL_PULSES = "pulses";
public static final String CHANNEL_SHUTTER = "shutter";
public static final String CHANNEL_VENETIAN_BLIND = "venetianBlind";
public static final String CHANNEL_SUN_WIND_DETECTOR = "sunWindDetector";
@@ -188,6 +193,16 @@ public class RFXComBindingConstants {
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 Device ThingTypeUIDs to their Configuration class
*/
public static final Map<ThingTypeUID, Class<? extends RFXComDeviceConfiguration>> THING_TYPE_UID_CONFIGURATION_CLASS_MAP = Map
.ofEntries(
new AbstractMap.SimpleEntry<ThingTypeUID, Class<? extends RFXComDeviceConfiguration>>(
THING_TYPE_RAW, RFXComRawDeviceConfiguration.class),
new AbstractMap.SimpleEntry<ThingTypeUID, Class<? extends RFXComDeviceConfiguration>>(
THING_TYPE_LIGHTNING4, RFXComLighting4DeviceConfiguration.class));
/**
* Map RFXCOM packet types to RFXCOM Thing types and vice versa.
*/

View File

@@ -64,7 +64,7 @@ public class RFXComHandlerFactory extends BaseThingHandlerFactory {
if (RFXComBindingConstants.SUPPORTED_BRIDGE_THING_TYPES_UIDS.contains(thingTypeUID)) {
return new RFXComBridgeHandler((Bridge) thing, serialPortManager);
} else if (supportsThingType(thingTypeUID)) {
} else if (RFXComBindingConstants.SUPPORTED_DEVICE_THING_TYPES_UIDS.contains(thingTypeUID)) {
return new RFXComHandler(thing);
}

View File

@@ -12,22 +12,17 @@
*/
package org.openhab.binding.rfxcom.internal.config;
import org.openhab.binding.rfxcom.internal.exceptions.RFXComInvalidParameterException;
import org.openhab.binding.rfxcom.internal.messages.RFXComDeviceMessage;
/**
* Configuration class for RfxcomBinding device.
* Configuration interface for RFXCom devices.
*
* @author Pauli Anttila - Initial contribution
* @author James Hewitt-Thomas - Convert to interface and add validation and matching
*/
public interface RFXComDeviceConfiguration {
public void parseAndValidate() throws RFXComInvalidParameterException;
public class RFXComDeviceConfiguration {
public static final String DEVICE_ID_LABEL = "deviceId";
public static final String SUB_TYPE_LABEL = "subType";
public static final String PULSE_LABEL = "pulse";
public static final String ON_COMMAND_ID_LABEL = "onCommandId";
public static final String OFF_COMMAND_ID_LABEL = "offCommandId";
public String deviceId;
public String subType;
public Integer pulse;
public Integer onCommandId;
public Integer offCommandId;
public boolean matchesMessage(RFXComDeviceMessage message);
}

View File

@@ -0,0 +1,44 @@
/**
* 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.config;
import org.openhab.binding.rfxcom.internal.exceptions.RFXComInvalidParameterException;
import org.openhab.binding.rfxcom.internal.messages.RFXComDeviceMessage;
/**
* Configuration class for generic RFXCOM device.
*
* @author Pauli Anttila - Initial contribution
* @author James Hewitt-Thomas - Add validations and matching
*/
public class RFXComGenericDeviceConfiguration implements RFXComDeviceConfiguration {
public static final String DEVICE_ID_LABEL = "deviceId";
public static final String SUB_TYPE_LABEL = "subType";
public String deviceId;
public String subType;
@Override
public void parseAndValidate() throws RFXComInvalidParameterException {
if (deviceId == null) {
throw new RFXComInvalidParameterException("deviceId", null, "RFXCOM device missing deviceId");
}
if (subType == null) {
throw new RFXComInvalidParameterException("subType", null, "RFXCOM device missing subType");
}
}
@Override
public boolean matchesMessage(RFXComDeviceMessage message) {
return deviceId.equals(message.getDeviceId());
}
}

View File

@@ -0,0 +1,27 @@
/**
* 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.config;
/**
* Configuration class for Lighting4 RFXCOM device.
*
* @author James Hewitt-Thomas - Initial contribution
*/
public class RFXComLighting4DeviceConfiguration extends RFXComGenericDeviceConfiguration {
public static final String PULSE_LABEL = "pulse";
public static final String ON_COMMAND_ID_LABEL = "onCommandId";
public static final String OFF_COMMAND_ID_LABEL = "offCommandId";
public Integer pulse;
public Integer onCommandId;
public Integer offCommandId;
}

View File

@@ -0,0 +1,99 @@
/**
* 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.config;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.rfxcom.internal.exceptions.RFXComInvalidParameterException;
/**
* Configuration class for Raw RFXCOM device.
*
* @author James Hewitt-Thomas - Initial contribution
*/
@NonNullByDefault
public class RFXComRawDeviceConfiguration extends RFXComGenericDeviceConfiguration {
public static final String REPEAT_LABEL = "repeat";
public int repeat;
public static final String ON_PULSES_LABEL = "onPulses";
public static final String OFF_PULSES_LABEL = "offPulses";
@Nullable
public String onPulses;
@Nullable
public String offPulses;
public short @Nullable [] onPulsesArray;
public short @Nullable [] offPulsesArray;
public static final String OPEN_PULSES_LABEL = "openPulses";
public static final String CLOSED_PULSES_LABEL = "closedPulses";
@Nullable
public String openPulses;
@Nullable
public String closedPulses;
public short @Nullable [] openPulsesArray;
public short @Nullable [] closedPulsesArray;
@Override
public void parseAndValidate() throws RFXComInvalidParameterException {
super.parseAndValidate();
onPulsesArray = parseAndValidatePulses("onPulses", onPulses);
offPulsesArray = parseAndValidatePulses("offPulses", offPulses);
openPulsesArray = parseAndValidatePulses("openPulses", openPulses);
closedPulsesArray = parseAndValidatePulses("closedPulses", closedPulses);
}
private static short @Nullable [] parseAndValidatePulses(String parameter, @Nullable String pulses)
throws RFXComInvalidParameterException {
if (pulses != null) {
return parseAndValidatePulsesNonNull(parameter, pulses);
} else {
return null;
}
}
private static short[] parseAndValidatePulsesNonNull(String parameter, String pulses)
throws RFXComInvalidParameterException {
String[] strings = pulses.trim().split("\\s+");
if (strings.length > 124) {
throw new RFXComInvalidParameterException(parameter, pulses, "Cannot have more than 124 pulses");
}
if (strings.length % 2 != 0) {
throw new RFXComInvalidParameterException(parameter, pulses, "Pulses must be in pairs");
}
try {
short[] shorts = new short[strings.length];
for (int i = 0; i < strings.length; i++) {
int pulse = Integer.parseInt(strings[i]);
if (pulse > 65535) {
throw new RFXComInvalidParameterException(parameter, pulses, "Cannot have pulse above 65535 usec");
} else if (pulse < 0) {
throw new RFXComInvalidParameterException(parameter, pulses, "Cannot have negative pulse");
} else if (pulse == 0) {
// The user guide suggests that received pulses of size 0 should be
// replaced with something above 8000, as they represent gaps.
shorts[i] = 10000;
} else {
shorts[i] = (short) pulse;
}
}
return shorts;
} catch (NumberFormatException e) {
throw new RFXComInvalidParameterException(parameter, pulses, e.getMessage(), e);
}
}
}

View File

@@ -0,0 +1,39 @@
/**
* 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.exceptions;
/**
* Exception for when RFXCOM messages have a value that we don't understand.
*
* @author James Hewitt-Thomas - Initial contribution
*/
public class RFXComInvalidParameterException extends RFXComException {
private static final long serialVersionUID = -2778120072474013560L;
public RFXComInvalidParameterException(String parameter, String value) {
super("Invalid value '" + value + "' for parameter " + parameter);
}
public RFXComInvalidParameterException(String parameter, String value, String reason) {
super("Invalid value '" + value + "' for parameter " + parameter + ": " + reason);
}
public RFXComInvalidParameterException(String parameter, String value, Throwable cause) {
super("Invalid value '" + value + "' for parameter " + parameter, cause);
}
public RFXComInvalidParameterException(String parameter, String value, String reason, Throwable cause) {
super("Invalid value '" + value + "' for parameter " + parameter + ": " + reason, cause);
}
}

View File

@@ -0,0 +1,31 @@
/**
* 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.exceptions;
/**
* Exception for when RFXCOM messages have a value that we don't understand.
*
* @author James Hewitt-Thomas - Initial contribution
*/
public class RFXComInvalidStateException extends RFXComException {
private static final long serialVersionUID = -2770653643474013560L;
public RFXComInvalidStateException(String channel, String state) {
super("Invalid state '" + state + "' for parameter " + channel);
}
public RFXComInvalidStateException(String channel, String state, String reason) {
super("Invalid state '" + state + "' for parameter " + channel + ": " + reason);
}
}

View File

@@ -41,6 +41,7 @@ import org.openhab.binding.rfxcom.internal.messages.RFXComInterfaceMessage.Comma
import org.openhab.binding.rfxcom.internal.messages.RFXComInterfaceMessage.SubType;
import org.openhab.binding.rfxcom.internal.messages.RFXComMessage;
import org.openhab.binding.rfxcom.internal.messages.RFXComMessageFactory;
import org.openhab.binding.rfxcom.internal.messages.RFXComMessageFactoryImpl;
import org.openhab.binding.rfxcom.internal.messages.RFXComTransmitterMessage;
import org.openhab.core.io.transport.serial.SerialPortManager;
import org.openhab.core.thing.Bridge;
@@ -75,6 +76,8 @@ public class RFXComBridgeHandler extends BaseBridgeHandler {
private SerialPortManager serialPortManager;
private RFXComMessageFactory messageFactory;
private class TransmitQueue {
private Queue<RFXComBaseMessage> queue = new LinkedBlockingQueue<>();
@@ -116,6 +119,14 @@ public class RFXComBridgeHandler extends BaseBridgeHandler {
public RFXComBridgeHandler(@NonNull Bridge br, SerialPortManager serialPortManager) {
super(br);
this.serialPortManager = serialPortManager;
this.messageFactory = RFXComMessageFactoryImpl.INSTANCE;
}
public RFXComBridgeHandler(@NonNull Bridge br, SerialPortManager serialPortManager,
RFXComMessageFactory messageFactory) {
super(br);
this.serialPortManager = serialPortManager;
this.messageFactory = messageFactory;
}
@Override
@@ -198,7 +209,7 @@ public class RFXComBridgeHandler extends BaseBridgeHandler {
connector.connect(configuration);
logger.debug("Reset controller");
connector.sendMessage(RFXComMessageFactory.CMD_RESET);
connector.sendMessage(RFXComInterfaceMessage.CMD_RESET);
// controller does not response immediately after reset,
// so wait a while
@@ -207,7 +218,7 @@ public class RFXComBridgeHandler extends BaseBridgeHandler {
connector.addEventListener(eventListener);
logger.debug("Get status of controller");
connector.sendMessage(RFXComMessageFactory.CMD_GET_STATUS);
connector.sendMessage(RFXComInterfaceMessage.CMD_GET_STATUS);
}
} catch (IOException e) {
logger.error("Connection to RFXCOM transceiver failed", e);
@@ -243,7 +254,7 @@ public class RFXComBridgeHandler extends BaseBridgeHandler {
@Override
public void packetReceived(byte[] packet) {
try {
RFXComMessage message = RFXComMessageFactory.createMessage(packet);
RFXComMessage message = messageFactory.createMessage(packet);
logger.debug("Message received: {}", message);
if (message instanceof RFXComInterfaceMessage) {
@@ -299,7 +310,7 @@ public class RFXComBridgeHandler extends BaseBridgeHandler {
// regardless of whether it fails and the RFXCOM's buffer
// is big enough to queue up the command.
logger.debug("Start receiver");
connector.sendMessage(RFXComMessageFactory.CMD_START_RECEIVER);
connector.sendMessage(RFXComInterfaceMessage.CMD_START_RECEIVER);
}
} else if (msg.subType == SubType.START_RECEIVER) {
updateStatus(ThingStatus.ONLINE);

View File

@@ -19,15 +19,22 @@ import java.util.concurrent.ConcurrentHashMap;
import org.eclipse.jdt.annotation.NonNull;
import org.openhab.binding.rfxcom.internal.DeviceMessageListener;
import org.openhab.binding.rfxcom.internal.RFXComBindingConstants;
import org.openhab.binding.rfxcom.internal.config.RFXComDeviceConfiguration;
import org.openhab.binding.rfxcom.internal.config.RFXComGenericDeviceConfiguration;
import org.openhab.binding.rfxcom.internal.exceptions.RFXComException;
import org.openhab.binding.rfxcom.internal.exceptions.RFXComInvalidParameterException;
import org.openhab.binding.rfxcom.internal.exceptions.RFXComInvalidStateException;
import org.openhab.binding.rfxcom.internal.exceptions.RFXComMessageNotImplementedException;
import org.openhab.binding.rfxcom.internal.exceptions.RFXComUnsupportedChannelException;
import org.openhab.binding.rfxcom.internal.messages.RFXComBaseMessage.PacketType;
import org.openhab.binding.rfxcom.internal.messages.RFXComDeviceMessage;
import org.openhab.binding.rfxcom.internal.messages.RFXComMessage;
import org.openhab.binding.rfxcom.internal.messages.RFXComMessageFactory;
import org.openhab.binding.rfxcom.internal.messages.RFXComMessageFactoryImpl;
import org.openhab.core.library.types.DecimalType;
import org.openhab.core.library.types.OnOffType;
import org.openhab.core.thing.Bridge;
import org.openhab.core.thing.Channel;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.Thing;
@@ -58,10 +65,22 @@ public class RFXComHandler extends BaseThingHandler implements DeviceMessageList
private final Map<String, Type> stateMap = new ConcurrentHashMap<>();
private RFXComBridgeHandler bridgeHandler;
private Class<? extends RFXComDeviceConfiguration> configType;
private RFXComDeviceConfiguration config;
private RFXComMessageFactory messageFactory;
public RFXComHandler(@NonNull Thing thing) {
this(thing, RFXComMessageFactoryImpl.INSTANCE);
}
public RFXComHandler(@NonNull Thing thing, RFXComMessageFactory messageFactory) {
super(thing);
this.messageFactory = messageFactory;
configType = RFXComBindingConstants.THING_TYPE_UID_CONFIGURATION_CLASS_MAP.getOrDefault(thing.getThingTypeUID(),
RFXComGenericDeviceConfiguration.class);
}
@Override
@@ -73,10 +92,10 @@ public class RFXComHandler extends BaseThingHandler implements DeviceMessageList
logger.trace("Received unsupported Refresh command");
} else {
try {
PacketType packetType = RFXComMessageFactory
PacketType packetType = RFXComMessageFactoryImpl
.convertPacketType(getThing().getThingTypeUID().getId().toUpperCase());
RFXComMessage msg = RFXComMessageFactory.createMessage(packetType);
RFXComMessage msg = messageFactory.createMessage(packetType);
msg.setConfig(config);
msg.convertFromState(channelUID.getId(), command);
@@ -84,6 +103,10 @@ public class RFXComHandler extends BaseThingHandler implements DeviceMessageList
bridgeHandler.sendMessage(msg);
} catch (RFXComMessageNotImplementedException e) {
logger.error("Message not supported", e);
} catch (RFXComUnsupportedChannelException e) {
logger.error("Channel not supported", e);
} catch (RFXComInvalidStateException e) {
logger.error("Invalid state supplied for channel", e);
} catch (RFXComException e) {
logger.error("Transmitting error", e);
}
@@ -94,8 +117,14 @@ public class RFXComHandler extends BaseThingHandler implements DeviceMessageList
@Override
public void initialize() {
logger.debug("Initializing thing {}", getThing().getUID());
initializeBridge((getBridge() == null) ? null : getBridge().getHandler(),
(getBridge() == null) ? null : getBridge().getStatus());
Bridge bridge = getBridge();
if (bridge == null) {
initializeBridge(null, null);
} else {
initializeBridge(bridge.getHandler(), bridge.getStatus());
}
stateMap.clear();
}
@@ -103,27 +132,36 @@ public class RFXComHandler extends BaseThingHandler implements DeviceMessageList
@Override
public void bridgeStatusChanged(ThingStatusInfo bridgeStatusInfo) {
logger.debug("bridgeStatusChanged {} for thing {}", bridgeStatusInfo, getThing().getUID());
initializeBridge((getBridge() == null) ? null : getBridge().getHandler(), bridgeStatusInfo.getStatus());
Bridge bridge = getBridge();
if (bridge == null) {
initializeBridge(null, bridgeStatusInfo.getStatus());
} else {
initializeBridge(bridge.getHandler(), bridgeStatusInfo.getStatus());
}
}
private void initializeBridge(ThingHandler thingHandler, ThingStatus bridgeStatus) {
logger.debug("initializeBridge {} for thing {}", bridgeStatus, getThing().getUID());
config = getConfigAs(RFXComDeviceConfiguration.class);
if (config.deviceId == null || config.subType == null) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
"RFXCOM device missing deviceId or subType");
} else if (thingHandler != null && bridgeStatus != null) {
bridgeHandler = (RFXComBridgeHandler) thingHandler;
bridgeHandler.registerDeviceStatusListener(this);
try {
config = getConfigAs(configType);
config.parseAndValidate();
if (thingHandler != null && bridgeStatus != null) {
bridgeHandler = (RFXComBridgeHandler) thingHandler;
bridgeHandler.registerDeviceStatusListener(this);
if (bridgeStatus == ThingStatus.ONLINE) {
updateStatus(ThingStatus.ONLINE);
if (bridgeStatus == ThingStatus.ONLINE) {
updateStatus(ThingStatus.ONLINE);
} else {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE);
}
} else {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE);
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_UNINITIALIZED);
}
} else {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_UNINITIALIZED);
} catch (RFXComInvalidParameterException e) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, e.getMessage());
}
}
@@ -140,8 +178,7 @@ public class RFXComHandler extends BaseThingHandler implements DeviceMessageList
@Override
public void onDeviceMessageReceived(ThingUID bridge, RFXComDeviceMessage message) {
try {
String id = message.getDeviceId();
if (config.deviceId.equals(id)) {
if (config.matchesMessage(message)) {
String receivedId = PACKET_TYPE_THING_TYPE_UID_MAP.get(message.getPacketType()).getId();
logger.debug("Received message from bridge: {} message: {}", bridge, message);

View File

@@ -15,6 +15,7 @@ package org.openhab.binding.rfxcom.internal.messages;
import static org.openhab.binding.rfxcom.internal.RFXComBindingConstants.CHANNEL_SIGNAL_LEVEL;
import org.openhab.binding.rfxcom.internal.config.RFXComDeviceConfiguration;
import org.openhab.binding.rfxcom.internal.config.RFXComGenericDeviceConfiguration;
import org.openhab.binding.rfxcom.internal.exceptions.RFXComException;
import org.openhab.binding.rfxcom.internal.exceptions.RFXComUnsupportedChannelException;
import org.openhab.binding.rfxcom.internal.handler.DeviceState;
@@ -41,8 +42,9 @@ abstract class RFXComDeviceMessageImpl<T> extends RFXComBaseMessage implements R
@Override
public void setConfig(RFXComDeviceConfiguration config) throws RFXComException {
this.setSubType(convertSubType(config.subType));
this.setDeviceId(config.deviceId);
RFXComGenericDeviceConfiguration genericConfig = (RFXComGenericDeviceConfiguration) config;
this.setSubType(convertSubType(genericConfig.subType));
this.setDeviceId(genericConfig.deviceId);
}
@Override
@@ -67,8 +69,9 @@ abstract class RFXComDeviceMessageImpl<T> extends RFXComBaseMessage implements R
String subTypeString = convertSubType(String.valueOf(subType)).toString();
String label = getPacketType() + "-" + getDeviceId();
discoveryResultBuilder.withLabel(label).withProperty(RFXComDeviceConfiguration.DEVICE_ID_LABEL, getDeviceId())
.withProperty(RFXComDeviceConfiguration.SUB_TYPE_LABEL, subTypeString);
discoveryResultBuilder.withLabel(label)
.withProperty(RFXComGenericDeviceConfiguration.DEVICE_ID_LABEL, getDeviceId())
.withProperty(RFXComGenericDeviceConfiguration.SUB_TYPE_LABEL, subTypeString);
}
/**

View File

@@ -373,4 +373,32 @@ public class RFXComInterfaceMessage extends RFXComBaseMessage {
public void convertFromState(String channelId, Type type) {
throw new UnsupportedOperationException();
}
/**
* Command to reset RFXCOM controller.
*
*/
public static final byte[] CMD_RESET = new byte[] { 0x0D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00 };
/**
* Command to get RFXCOM controller status.
*
*/
public static final byte[] CMD_GET_STATUS = new byte[] { 0x0D, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00 };
/**
* Command to save RFXCOM controller configuration.
*
*/
public static final byte[] CMD_SAVE = new byte[] { 0x0D, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00 };
/**
* Command to start RFXCOM receiver.
*
*/
public static final byte[] CMD_START_RECEIVER = new byte[] { 0x0D, 0x00, 0x00, 0x03, 0x07, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00 };
}

View File

@@ -13,10 +13,11 @@
package org.openhab.binding.rfxcom.internal.messages;
import static org.openhab.binding.rfxcom.internal.RFXComBindingConstants.*;
import static org.openhab.binding.rfxcom.internal.config.RFXComDeviceConfiguration.*;
import static org.openhab.binding.rfxcom.internal.config.RFXComLighting4DeviceConfiguration.*;
import static org.openhab.binding.rfxcom.internal.messages.ByteEnumUtil.fromByte;
import org.openhab.binding.rfxcom.internal.config.RFXComDeviceConfiguration;
import org.openhab.binding.rfxcom.internal.config.RFXComLighting4DeviceConfiguration;
import org.openhab.binding.rfxcom.internal.exceptions.RFXComException;
import org.openhab.binding.rfxcom.internal.exceptions.RFXComUnsupportedChannelException;
import org.openhab.binding.rfxcom.internal.exceptions.RFXComUnsupportedValueException;
@@ -274,10 +275,11 @@ public class RFXComLighting4Message extends RFXComDeviceMessageImpl<RFXComLighti
@Override
public void setConfig(RFXComDeviceConfiguration config) throws RFXComException {
super.setConfig(config);
this.pulse = config.pulse != null ? config.pulse : 350;
this.onCommandId = valueOrDefault(config.onCommandId, DEFAULT_ON_COMMAND_ID);
this.offCommandId = valueOrDefault(config.offCommandId, DEFAULT_OFF_COMMAND_ID);
RFXComLighting4DeviceConfiguration lighting4Config = (RFXComLighting4DeviceConfiguration) config;
super.setConfig(lighting4Config);
this.pulse = lighting4Config.pulse != null ? lighting4Config.pulse : 350;
this.onCommandId = valueOrDefault(lighting4Config.onCommandId, DEFAULT_ON_COMMAND_ID);
this.offCommandId = valueOrDefault(lighting4Config.offCommandId, DEFAULT_OFF_COMMAND_ID);
}
private int valueOrDefault(Integer commandId, byte defaultValue) {

View File

@@ -14,6 +14,7 @@ package org.openhab.binding.rfxcom.internal.messages;
import org.openhab.binding.rfxcom.internal.config.RFXComDeviceConfiguration;
import org.openhab.binding.rfxcom.internal.exceptions.RFXComException;
import org.openhab.binding.rfxcom.internal.exceptions.RFXComInvalidStateException;
import org.openhab.binding.rfxcom.internal.exceptions.RFXComUnsupportedChannelException;
import org.openhab.core.types.Type;
@@ -40,8 +41,12 @@ public interface RFXComMessage {
/**
* Procedure for converting openHAB state to RFXCOM object.
*
* @throws RFXComUnsupportedChannelException If we do not support setting this channel
* @throws RFXComInvalidStateException If the state (type) is invalid for the channel
*/
void convertFromState(String channelId, Type type) throws RFXComUnsupportedChannelException;
void convertFromState(String channelId, Type type)
throws RFXComUnsupportedChannelException, RFXComInvalidStateException;
/**
* Procedure to pass configuration to a message

View File

@@ -12,152 +12,18 @@
*/
package org.openhab.binding.rfxcom.internal.messages;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import org.openhab.binding.rfxcom.internal.exceptions.RFXComException;
import org.openhab.binding.rfxcom.internal.exceptions.RFXComMessageNotImplementedException;
import org.openhab.binding.rfxcom.internal.messages.RFXComBaseMessage.PacketType;
/**
* Factory to create RFXCom messages from either bytes delivered by the RFXCom device
* or from openhab state to transmit.
*
* @author Pauli Anttila - Initial contribution
* @author James Hewitt-Thomas - Convert to interface to allow dependency injection
*/
public class RFXComMessageFactory {
public interface RFXComMessageFactory {
public RFXComMessage createMessage(PacketType packetType) throws RFXComException;
@SuppressWarnings("serial")
private static final Map<PacketType, Class<? extends RFXComMessage>> MESSAGE_CLASSES = Collections
.unmodifiableMap(new HashMap<PacketType, Class<? extends RFXComMessage>>() {
{
put(PacketType.INTERFACE_CONTROL, RFXComInterfaceControlMessage.class);
put(PacketType.INTERFACE_MESSAGE, RFXComInterfaceMessage.class);
put(PacketType.TRANSMITTER_MESSAGE, RFXComTransmitterMessage.class);
put(PacketType.UNDECODED_RF_MESSAGE, RFXComUndecodedRFMessage.class);
put(PacketType.LIGHTING1, RFXComLighting1Message.class);
put(PacketType.LIGHTING2, RFXComLighting2Message.class);
// put(PacketType.LIGHTING3, RFXComLighting3Message.class);
put(PacketType.LIGHTING4, RFXComLighting4Message.class);
put(PacketType.LIGHTING5, RFXComLighting5Message.class);
put(PacketType.LIGHTING6, RFXComLighting6Message.class);
put(PacketType.CHIME, RFXComChimeMessage.class);
put(PacketType.FAN, RFXComFanMessage.class);
// put(PacketType.FAN_SF01, RFXComFanMessage.class);
// put(PacketType.FAN_ITHO, RFXComFanMessage.class);
// put(PacketType.FAN_SEAV, RFXComFanMessage.class);
put(PacketType.FAN_LUCCI_DC, RFXComFanMessage.class);
// put(PacketType.FAN_FT1211R, RFXComFanMessage.class);
put(PacketType.FAN_FALMEC, RFXComFanMessage.class);
put(PacketType.FAN_LUCCI_DC_II, RFXComFanMessage.class);
put(PacketType.FAN_NOVY, RFXComFanMessage.class);
put(PacketType.CURTAIN1, RFXComCurtain1Message.class);
put(PacketType.BLINDS1, RFXComBlinds1Message.class);
put(PacketType.RFY, RFXComRfyMessage.class);
put(PacketType.HOME_CONFORT, RFXComHomeConfortMessage.class);
put(PacketType.SECURITY1, RFXComSecurity1Message.class);
put(PacketType.SECURITY2, RFXComSecurity2Message.class);
// put(PacketType.CAMERA1, RFXComCamera1Message.class);
// put(PacketType.REMOTE_CONTROL, RFXComRemoteControlMessage.class);
put(PacketType.THERMOSTAT1, RFXComThermostat1Message.class);
// put(PacketType.THERMOSTAT2, RFXComThermostat2Message.class);
put(PacketType.THERMOSTAT3, RFXComThermostat3Message.class);
// put(PacketType.RADIATOR1, RFXComRadiator1Message.class);
put(PacketType.BBQ, RFXComBBQTemperatureMessage.class);
put(PacketType.TEMPERATURE_RAIN, RFXComTemperatureRainMessage.class);
put(PacketType.TEMPERATURE, RFXComTemperatureMessage.class);
put(PacketType.HUMIDITY, RFXComHumidityMessage.class);
put(PacketType.TEMPERATURE_HUMIDITY, RFXComTemperatureHumidityMessage.class);
// put(PacketType.BAROMETRIC, RFXComBarometricMessage.class);
put(PacketType.TEMPERATURE_HUMIDITY_BAROMETRIC, RFXComTemperatureHumidityBarometricMessage.class);
put(PacketType.RAIN, RFXComRainMessage.class);
put(PacketType.WIND, RFXComWindMessage.class);
put(PacketType.UV, RFXComUVMessage.class);
put(PacketType.DATE_TIME, RFXComDateTimeMessage.class);
put(PacketType.CURRENT, RFXComCurrentMessage.class);
put(PacketType.ENERGY, RFXComEnergyMessage.class);
put(PacketType.CURRENT_ENERGY, RFXComCurrentEnergyMessage.class);
// put(PacketType.POWER, RFXComPowerMessage.class);
// put(PacketType.WEIGHT, RFXComWeightMessage.class);
// put(PacketType.GAS, RFXComGasMessage.class);
// put(PacketType.WATER, RFXComWaterMessage.class);
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);
}
});
/**
* Command to reset RFXCOM controller.
*
*/
public static final byte[] CMD_RESET = new byte[] { 0x0D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00 };
/**
* Command to get RFXCOM controller status.
*
*/
public static final byte[] CMD_GET_STATUS = new byte[] { 0x0D, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00 };
/**
* Command to save RFXCOM controller configuration.
*
*/
public static final byte[] CMD_SAVE = new byte[] { 0x0D, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00 };
/**
* Command to start RFXCOM receiver.
*
*/
public static final byte[] CMD_START_RECEIVER = new byte[] { 0x0D, 0x00, 0x00, 0x03, 0x07, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00 };
public static RFXComMessage createMessage(PacketType packetType) throws RFXComException {
try {
Class<? extends RFXComMessage> cl = MESSAGE_CLASSES.get(packetType);
if (cl == null) {
throw new RFXComMessageNotImplementedException("Message " + packetType + " not implemented");
}
return cl.newInstance();
} catch (IllegalAccessException | InstantiationException e) {
throw new RFXComException(e);
}
}
public static RFXComMessage createMessage(byte[] packet) throws RFXComException {
PacketType packetType = ByteEnumUtil.fromByte(PacketType.class, packet[1]);
try {
Class<? extends RFXComMessage> cl = MESSAGE_CLASSES.get(packetType);
if (cl == null) {
throw new RFXComMessageNotImplementedException("Message " + packetType + " not implemented");
}
Constructor<?> c = cl.getConstructor(byte[].class);
return (RFXComMessage) c.newInstance(packet);
} catch (InvocationTargetException e) {
if (e.getCause() instanceof RFXComException) {
throw (RFXComException) e.getCause();
} else {
throw new RFXComException(e);
}
} catch (NoSuchMethodException | IllegalAccessException | InstantiationException e) {
throw new RFXComException(e);
}
}
public static PacketType convertPacketType(String packetType) throws IllegalArgumentException {
for (PacketType p : PacketType.values()) {
if (p.toString().replace("_", "").equals(packetType.replace("_", ""))) {
return p;
}
}
throw new IllegalArgumentException("Unknown packet type " + packetType);
}
public RFXComMessage createMessage(byte[] packet) throws RFXComException;
}

View File

@@ -0,0 +1,147 @@
/**
* 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 java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import org.openhab.binding.rfxcom.internal.exceptions.RFXComException;
import org.openhab.binding.rfxcom.internal.exceptions.RFXComMessageNotImplementedException;
import org.openhab.binding.rfxcom.internal.messages.RFXComBaseMessage.PacketType;
/**
* Factory to create RFXCom messages from either bytes delivered by the RFXCom device
* or from openhab state to transmit.
*
* @author Pauli Anttila - Initial contribution
* @author James Hewitt-Thomas - Use the enum singleton pattern to allow dependency injection
*/
public enum RFXComMessageFactoryImpl implements RFXComMessageFactory {
INSTANCE();
@SuppressWarnings("serial")
private static final Map<PacketType, Class<? extends RFXComMessage>> MESSAGE_CLASSES = Collections
.unmodifiableMap(new HashMap<PacketType, Class<? extends RFXComMessage>>() {
{
put(PacketType.INTERFACE_CONTROL, RFXComInterfaceControlMessage.class);
put(PacketType.INTERFACE_MESSAGE, RFXComInterfaceMessage.class);
put(PacketType.TRANSMITTER_MESSAGE, RFXComTransmitterMessage.class);
put(PacketType.UNDECODED_RF_MESSAGE, RFXComUndecodedRFMessage.class);
put(PacketType.LIGHTING1, RFXComLighting1Message.class);
put(PacketType.LIGHTING2, RFXComLighting2Message.class);
// put(PacketType.LIGHTING3, RFXComLighting3Message.class);
put(PacketType.LIGHTING4, RFXComLighting4Message.class);
put(PacketType.LIGHTING5, RFXComLighting5Message.class);
put(PacketType.LIGHTING6, RFXComLighting6Message.class);
put(PacketType.CHIME, RFXComChimeMessage.class);
put(PacketType.FAN, RFXComFanMessage.class);
// put(PacketType.FAN_SF01, RFXComFanMessage.class);
// put(PacketType.FAN_ITHO, RFXComFanMessage.class);
// put(PacketType.FAN_SEAV, RFXComFanMessage.class);
put(PacketType.FAN_LUCCI_DC, RFXComFanMessage.class);
// put(PacketType.FAN_FT1211R, RFXComFanMessage.class);
put(PacketType.FAN_FALMEC, RFXComFanMessage.class);
put(PacketType.FAN_LUCCI_DC_II, RFXComFanMessage.class);
put(PacketType.FAN_NOVY, RFXComFanMessage.class);
put(PacketType.CURTAIN1, RFXComCurtain1Message.class);
put(PacketType.BLINDS1, RFXComBlinds1Message.class);
put(PacketType.RFY, RFXComRfyMessage.class);
put(PacketType.HOME_CONFORT, RFXComHomeConfortMessage.class);
put(PacketType.SECURITY1, RFXComSecurity1Message.class);
put(PacketType.SECURITY2, RFXComSecurity2Message.class);
// put(PacketType.CAMERA1, RFXComCamera1Message.class);
// put(PacketType.REMOTE_CONTROL, RFXComRemoteControlMessage.class);
put(PacketType.THERMOSTAT1, RFXComThermostat1Message.class);
// put(PacketType.THERMOSTAT2, RFXComThermostat2Message.class);
put(PacketType.THERMOSTAT3, RFXComThermostat3Message.class);
// put(PacketType.RADIATOR1, RFXComRadiator1Message.class);
put(PacketType.BBQ, RFXComBBQTemperatureMessage.class);
put(PacketType.TEMPERATURE_RAIN, RFXComTemperatureRainMessage.class);
put(PacketType.TEMPERATURE, RFXComTemperatureMessage.class);
put(PacketType.HUMIDITY, RFXComHumidityMessage.class);
put(PacketType.TEMPERATURE_HUMIDITY, RFXComTemperatureHumidityMessage.class);
// put(PacketType.BAROMETRIC, RFXComBarometricMessage.class);
put(PacketType.TEMPERATURE_HUMIDITY_BAROMETRIC, RFXComTemperatureHumidityBarometricMessage.class);
put(PacketType.RAIN, RFXComRainMessage.class);
put(PacketType.WIND, RFXComWindMessage.class);
put(PacketType.UV, RFXComUVMessage.class);
put(PacketType.DATE_TIME, RFXComDateTimeMessage.class);
put(PacketType.CURRENT, RFXComCurrentMessage.class);
put(PacketType.ENERGY, RFXComEnergyMessage.class);
put(PacketType.CURRENT_ENERGY, RFXComCurrentEnergyMessage.class);
// put(PacketType.POWER, RFXComPowerMessage.class);
// put(PacketType.WEIGHT, RFXComWeightMessage.class);
// put(PacketType.GAS, RFXComGasMessage.class);
// put(PacketType.WATER, RFXComWaterMessage.class);
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);
}
});
/**
* Create message for transmission from the packet type associated with the thing.
*/
@Override
public RFXComMessage createMessage(PacketType packetType) throws RFXComException {
try {
Class<? extends RFXComMessage> cl = MESSAGE_CLASSES.get(packetType);
if (cl == null) {
throw new RFXComMessageNotImplementedException("Message " + packetType + " not implemented");
}
return cl.getDeclaredConstructor().newInstance();
} catch (ReflectiveOperationException e) {
throw new RFXComException(e);
}
}
/**
* Create message from received bytes.
*/
@Override
public RFXComMessage createMessage(byte[] packet) throws RFXComException {
PacketType packetType = ByteEnumUtil.fromByte(PacketType.class, packet[1]);
try {
Class<? extends RFXComMessage> cl = MESSAGE_CLASSES.get(packetType);
if (cl == null) {
throw new RFXComMessageNotImplementedException("Message " + packetType + " not implemented");
}
Constructor<?> c = cl.getConstructor(byte[].class);
return (RFXComMessage) c.newInstance(packet);
} catch (InvocationTargetException e) {
if (e.getCause() instanceof RFXComException) {
throw (RFXComException) e.getCause();
} else {
throw new RFXComException(e);
}
} catch (NoSuchMethodException | IllegalAccessException | InstantiationException e) {
throw new RFXComException(e);
}
}
public static PacketType convertPacketType(String packetType) throws IllegalArgumentException {
for (PacketType p : PacketType.values()) {
if (p.toString().replace("_", "").equals(packetType.replace("_", ""))) {
return p;
}
}
throw new IllegalArgumentException("Unknown packet type " + packetType);
}
}

View File

@@ -16,12 +16,19 @@ import static org.openhab.binding.rfxcom.internal.RFXComBindingConstants.*;
import static org.openhab.binding.rfxcom.internal.messages.RFXComBaseMessage.PacketType.RAW;
import java.nio.ByteBuffer;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import org.openhab.binding.rfxcom.internal.config.RFXComDeviceConfiguration;
import org.openhab.binding.rfxcom.internal.config.RFXComRawDeviceConfiguration;
import org.openhab.binding.rfxcom.internal.exceptions.RFXComException;
import org.openhab.binding.rfxcom.internal.exceptions.RFXComInvalidStateException;
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.OnOffType;
import org.openhab.core.library.types.OpenClosedType;
import org.openhab.core.library.types.StringType;
import org.openhab.core.types.State;
import org.openhab.core.types.Type;
@@ -68,6 +75,8 @@ public class RFXComRawMessage extends RFXComDeviceMessageImpl<RFXComRawMessage.S
public byte repeat;
public short[] pulses;
private RFXComRawDeviceConfiguration config;
public RFXComRawMessage() {
super(RAW);
pulses = new short[0];
@@ -114,7 +123,7 @@ public class RFXComRawMessage extends RFXComDeviceMessageImpl<RFXComRawMessage.S
data[1] = RAW.toByte();
data[2] = subType.toByte();
data[3] = seqNbr;
data[4] = repeat;
data[4] = (byte) config.repeat;
ByteBuffer.wrap(data, 5, pulsesByteLen).asShortBuffer().put(pulses);
@@ -126,6 +135,12 @@ public class RFXComRawMessage extends RFXComDeviceMessageImpl<RFXComRawMessage.S
return "RAW";
}
@Override
public void setConfig(RFXComDeviceConfiguration config) throws RFXComException {
super.setConfig(config);
this.config = (RFXComRawDeviceConfiguration) config;
}
@Override
public State convertToState(String channelId, DeviceState deviceState) throws RFXComUnsupportedChannelException {
switch (channelId) {
@@ -137,6 +152,11 @@ public class RFXComRawMessage extends RFXComDeviceMessageImpl<RFXComRawMessage.S
ByteBuffer.wrap(payload).asShortBuffer().put(pulses);
return new StringType(HexUtils.bytesToHex(payload));
case CHANNEL_PULSES:
return new StringType(IntStream.range(0, pulses.length)
.mapToObj(s -> Integer.toString(Short.toUnsignedInt(pulses[s])))
.collect(Collectors.joining(" ")));
default:
throw new RFXComUnsupportedChannelException("Nothing relevant for " + channelId);
}
@@ -144,34 +164,47 @@ public class RFXComRawMessage extends RFXComDeviceMessageImpl<RFXComRawMessage.S
@Override
public void setSubType(SubType subType) {
throw new UnsupportedOperationException();
this.subType = subType;
}
@Override
public void setDeviceId(String deviceId) {
throw new UnsupportedOperationException();
// Nothing to do here
}
@Override
public void convertFromState(String channelId, Type type) throws RFXComUnsupportedChannelException {
public void convertFromState(String channelId, Type type)
throws RFXComUnsupportedChannelException, RFXComInvalidStateException {
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");
case CHANNEL_RAW_PAYLOAD:
case CHANNEL_PULSES:
throw new RFXComUnsupportedChannelException("Cannot send on channel " + channelId);
case CHANNEL_COMMAND:
if (type instanceof OnOffType) {
if (type == OnOffType.ON) {
this.pulses = config.onPulsesArray;
} else {
this.pulses = config.offPulsesArray;
}
} else if (type instanceof OpenClosedType) {
if (type == OpenClosedType.OPEN) {
this.pulses = config.openPulsesArray;
} else {
this.pulses = config.closedPulsesArray;
}
} 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);
if (this.pulses == null) {
throw new RFXComInvalidStateException(channelId, null,
"No pulses provided in the device configuration for command" + type);
}
break;
default:
throw new RFXComUnsupportedChannelException("Channel " + channelId + " is not relevant here");
}

View File

@@ -18,6 +18,12 @@
<description>Hexadecimal representation of payload of raw and undecoded RFXCOM messages</description>
</channel-type>
<channel-type id="pulses">
<item-type>String</item-type>
<label>Pulses</label>
<description>Decimal representation of the pulse lengths for a raw message in usec.</description>
</channel-type>
<channel-type id="command">
<item-type>Switch</item-type>
<label>Command</label>

View File

@@ -18,12 +18,15 @@
<channels>
<channel id="rawMessage" typeId="rawmessage"/>
<channel id="rawPayload" typeId="rawpayload"/>
<channel id="pulses" typeId="pulses"/>
<channel id="command" typeId="command"/>
</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>
<description>Received raw message cannot provide a device ID, so to receive raw messages the device id must be RAW.
For transmit-only things, use any device id.</description>
</parameter>
<parameter name="subType" type="text" required="true">
<label>Sub Type</label>
@@ -35,6 +38,35 @@
<option value="RAW_PACKET4">RAW_PACKET4</option>
</options>
</parameter>
<parameter name="repeat" type="integer" min="1" max="255">
<label>Repeat</label>
<description>Number of times to repeat. Defaults to 5.</description>
<default>5</default>
</parameter>
<parameter name="onPulses" type="text" required="false">
<label>On Pulses</label>
<description>Pulses to send for an ON command. Space delimited pulse lengths in usec. Must be an even number of
pulse lengths, with a maximum of 142 total pulses. Max pulse length is 65535. Pulses of value 0 will be transmitted
as 10000. See the RFXtfx user guide for more information.</description>
</parameter>
<parameter name="offPulses" type="text" required="false">
<label>Off Pulses</label>
<description>Pulses to send for an OFF command. Space delimited pulse lengths in usec. Must be an even number of
pulse lengths, with a maximum of 142 total pulses. Max pulse length is 65535. Pulses of value 0 will be transmitted
as 10000. See the RFXtfx user guide for more information.</description>
</parameter>
<parameter name="openPulses" type="text" required="false">
<label>Open Pulses</label>
<description>Pulses to send for an OPEN command. Space delimited pulse lengths in usec. Must be an even number of
pulse lengths, with a maximum of 142 total pulses. Max pulse length is 65535. Pulses of value 0 will be transmitted
as 10000. See the RFXtfx user guide for more information.</description>
</parameter>
<parameter name="closedPulses" type="text" required="false">
<label>Closed Pulses</label>
<description>Pulses to send for an CLOSED command. Space delimited pulse lengths in usec. Must be an even number of
pulse lengths, with a maximum of 142 total pulses. Max pulse length is 65535. Pulses of value 0 will be transmitted
as 10000. See the RFXtfx user guide for more information.</description>
</parameter>
</config-description>
</thing-type>