2 * Copyright (c) 2010-2021 Contributors to the openHAB project
4 * See the NOTICE file(s) distributed with this work for additional
7 * This program and the accompanying materials are made available under the
8 * terms of the Eclipse Public License 2.0 which is available at
9 * http://www.eclipse.org/legal/epl-2.0
11 * SPDX-License-Identifier: EPL-2.0
13 package org.openhab.binding.rfxcom.internal.messages;
15 import static org.openhab.binding.rfxcom.internal.RFXComBindingConstants.*;
16 import static org.openhab.binding.rfxcom.internal.config.RFXComLighting4DeviceConfiguration.*;
17 import static org.openhab.binding.rfxcom.internal.messages.ByteEnumUtil.fromByte;
19 import org.openhab.binding.rfxcom.internal.config.RFXComDeviceConfiguration;
20 import org.openhab.binding.rfxcom.internal.config.RFXComLighting4DeviceConfiguration;
21 import org.openhab.binding.rfxcom.internal.exceptions.RFXComException;
22 import org.openhab.binding.rfxcom.internal.exceptions.RFXComUnsupportedChannelException;
23 import org.openhab.binding.rfxcom.internal.exceptions.RFXComUnsupportedValueException;
24 import org.openhab.binding.rfxcom.internal.handler.DeviceState;
25 import org.openhab.core.config.discovery.DiscoveryResultBuilder;
26 import org.openhab.core.library.types.DecimalType;
27 import org.openhab.core.library.types.OnOffType;
28 import org.openhab.core.library.types.OpenClosedType;
29 import org.openhab.core.types.State;
30 import org.openhab.core.types.Type;
31 import org.slf4j.Logger;
32 import org.slf4j.LoggerFactory;
35 * RFXCOM data class for lighting4 message.
37 * a Lighting4 Base command is composed of 24 bit DATA plus PULSE information
41 * S1- S24 = <0000 0001 0100 0101 0101> <0100>
42 * first 20 are DeviceID last 4 are for Command
47 * Tested on a PT2262 remote PlugIn module
51 * Switch TESTout "TestOut" (All) {rfxcom=">83205.350:LIGHTING4.PT2262:Command"}
52 * (SendCommand DeviceID(int).Pulse(int):LIGHTING4.Subtype:Command )
54 * Switch TESTin "TestIn" (All) {rfxcom="<83205:Command"}
55 * (ReceiveCommand ON/OFF Command )
57 * @author Alessandro Ballini (ITA) - Initial contribution
58 * @author Pauli Anttila - Migrated to OH2
59 * @author Martin van Wingerden - Extended support for more complex PT2262 devices
61 public class RFXComLighting4Message extends RFXComDeviceMessageImpl<RFXComLighting4Message.SubType> {
62 // this logger is used from a static context, so is static as well
63 private static final Logger LOGGER = LoggerFactory.getLogger(RFXComLighting4Message.class);
65 private static final byte DEFAULT_OFF_COMMAND_ID = Commands.OFF_4.toByte();
66 private static final byte DEFAULT_ON_COMMAND_ID = Commands.ON_1.toByte();
68 public enum SubType implements ByteEnumWrapper {
71 private final int subType;
73 SubType(int subType) {
74 this.subType = subType;
78 public byte toByte() {
79 return (byte) subType;
83 public enum Commands implements ByteEnumWrapper {
101 private final int command;
102 private final boolean on;
104 Commands(int command, boolean on) {
105 this.command = command;
110 public byte toByte() {
111 return (byte) command;
114 public boolean isOn() {
118 public static Commands fromByte(int input) {
119 for (Commands c : Commands.values()) {
120 if (c.command == input) {
125 "A not completely supported command with value {} was received, we can send it but please report "
126 + "it as an issue including what the command means, this helps to extend the binding with better support.",
132 private SubType subType;
133 private int sensorId;
135 private Commands command;
136 private int commandId;
137 private int offCommandId;
138 private int onCommandId;
140 public RFXComLighting4Message() {
141 super(PacketType.LIGHTING4);
144 public RFXComLighting4Message(byte[] data) throws RFXComException {
149 public String toString() {
152 str += super.toString();
153 str += ", Sub type = " + subType;
154 str += ", Device Id = " + getDeviceId();
155 str += ", Command = " + command + "(" + commandId + ")";
156 str += ", Pulse = " + pulse;
162 public void encodeMessage(byte[] data) throws RFXComException {
163 super.encodeMessage(data);
165 subType = fromByte(SubType.class, super.subType);
166 sensorId = (data[4] & 0xFF) << 12 | (data[5] & 0xFF) << 4 | (data[6] & 0xF0) >> 4;
168 commandId = (data[6] & 0x0F);
169 command = Commands.fromByte(commandId);
170 onCommandId = command.isOn() ? commandId : DEFAULT_ON_COMMAND_ID;
171 offCommandId = command.isOn() ? DEFAULT_OFF_COMMAND_ID : commandId;
173 pulse = (data[7] & 0xFF) << 8 | (data[8] & 0xFF);
175 signalLevel = (byte) ((data[9] & 0xF0) >> 4);
179 public byte[] decodeMessage() {
180 byte[] data = new byte[10];
183 data[1] = PacketType.LIGHTING4.toByte();
184 data[2] = subType.toByte();
187 // SENSOR_ID + COMMAND
188 data[4] = (byte) ((sensorId >> 12) & 0xFF);
189 data[5] = (byte) ((sensorId >> 4) & 0xFF);
190 data[6] = (byte) ((sensorId << 4 & 0xF0) | (commandId & 0x0F));
193 data[7] = (byte) (pulse >> 8 & 0xFF);
194 data[8] = (byte) (pulse & 0xFF);
197 data[9] = (byte) ((signalLevel & 0x0F) << 4);
203 public String getDeviceId() {
204 return String.valueOf(sensorId);
208 public State convertToState(String channelId, DeviceState deviceState) throws RFXComUnsupportedChannelException {
210 case CHANNEL_COMMAND:
212 return command.isOn() ? OnOffType.ON : OnOffType.OFF;
214 case CHANNEL_CONTACT:
215 return command.isOn() ? OpenClosedType.OPEN : OpenClosedType.CLOSED;
217 case CHANNEL_COMMAND_ID:
218 return new DecimalType(commandId);
221 return super.convertToState(channelId, deviceState);
226 public void setSubType(SubType subType) {
227 this.subType = subType;
231 public void setDeviceId(String deviceId) {
232 sensorId = Integer.parseInt(deviceId);
236 public void convertFromState(String channelId, Type type) throws RFXComUnsupportedChannelException {
238 case CHANNEL_COMMAND:
239 if (type instanceof OnOffType) {
240 command = Commands.fromByte(type == OnOffType.ON ? onCommandId : offCommandId);
241 commandId = command.toByte();
244 throw new RFXComUnsupportedChannelException("Channel " + channelId + " does not accept " + type);
248 case CHANNEL_COMMAND_ID:
249 if (type instanceof DecimalType) {
250 commandId = ((DecimalType) type).toBigDecimal().byteValue();
251 command = Commands.fromByte(commandId);
254 throw new RFXComUnsupportedChannelException("Channel " + channelId + " does not accept " + type);
259 throw new RFXComUnsupportedChannelException("Channel " + channelId + " is not relevant here");
264 public SubType convertSubType(String subType) throws RFXComUnsupportedValueException {
265 return ByteEnumUtil.convertSubType(SubType.class, subType);
269 public void addDevicePropertiesTo(DiscoveryResultBuilder discoveryResultBuilder) throws RFXComException {
270 super.addDevicePropertiesTo(discoveryResultBuilder);
271 discoveryResultBuilder.withProperty(PULSE_LABEL, pulse);
272 discoveryResultBuilder.withProperty(ON_COMMAND_ID_LABEL, onCommandId);
273 discoveryResultBuilder.withProperty(OFF_COMMAND_ID_LABEL, offCommandId);
277 public void setConfig(RFXComDeviceConfiguration config) throws RFXComException {
278 RFXComLighting4DeviceConfiguration lighting4Config = (RFXComLighting4DeviceConfiguration) config;
279 super.setConfig(lighting4Config);
280 this.pulse = lighting4Config.pulse != null ? lighting4Config.pulse : 350;
281 this.onCommandId = valueOrDefault(lighting4Config.onCommandId, DEFAULT_ON_COMMAND_ID);
282 this.offCommandId = valueOrDefault(lighting4Config.offCommandId, DEFAULT_OFF_COMMAND_ID);
285 private int valueOrDefault(Integer commandId, byte defaultValue) {
286 if (commandId != null) {