2 * Copyright (c) 2010-2022 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.*;
17 import org.openhab.binding.rfxcom.internal.config.RFXComDeviceConfiguration;
18 import org.openhab.binding.rfxcom.internal.exceptions.RFXComException;
19 import org.openhab.binding.rfxcom.internal.exceptions.RFXComInvalidStateException;
20 import org.openhab.binding.rfxcom.internal.exceptions.RFXComUnsupportedChannelException;
21 import org.openhab.binding.rfxcom.internal.exceptions.RFXComUnsupportedValueException;
22 import org.openhab.binding.rfxcom.internal.handler.DeviceState;
23 import org.openhab.core.library.types.IncreaseDecreaseType;
24 import org.openhab.core.library.types.OnOffType;
25 import org.openhab.core.library.types.OpenClosedType;
26 import org.openhab.core.library.types.StringType;
27 import org.openhab.core.types.Command;
28 import org.openhab.core.types.State;
29 import org.openhab.core.types.Type;
30 import org.openhab.core.types.UnDefType;
33 * RFXCOM data class for lighting1 message. See X10, ARC, etc..
35 * @author Evert van Es, Cycling Engineer - Initial contribution
36 * @author Pauli Anttila
38 public class RFXComLighting1Message extends RFXComDeviceMessageImpl<RFXComLighting1Message.SubType> {
40 public enum SubType implements ByteEnumWrapper {
54 private final int subType;
56 SubType(int subType) {
57 this.subType = subType;
61 public byte toByte() {
62 return (byte) subType;
66 public enum Commands implements ByteEnumWrapper {
75 private final int command;
77 Commands(int command) {
78 this.command = command;
82 public byte toByte() {
83 return (byte) command;
87 public SubType subType;
88 public char houseCode;
90 public Commands command;
93 private static byte[] lastUnit = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
95 public RFXComLighting1Message() {
96 super(PacketType.LIGHTING1);
99 public RFXComLighting1Message(byte[] data) throws RFXComException {
104 public String toString() {
107 str += super.toString();
108 str += ", Sub type = " + subType;
109 str += ", Device Id = " + getDeviceId();
110 str += ", Command = " + command;
111 str += ", Signal level = " + signalLevel;
117 public void encodeMessage(byte[] data) throws RFXComException {
118 super.encodeMessage(data);
120 subType = ByteEnumUtil.fromByte(SubType.class, super.subType);
121 houseCode = (char) data[4];
122 command = ByteEnumUtil.fromByte(Commands.class, data[6]);
124 if ((command == Commands.GROUP_ON) || (command == Commands.GROUP_OFF)) {
126 } else if ((data[5] == 0) && ((command == Commands.DIM) || (command == Commands.BRIGHT))) {
127 // SS13 switches broadcast DIM/BRIGHT to X0 and the dimmers ignore
128 // the message unless the last X<n> ON they saw was for them. So we
129 // redirect an incoming broadcast DIM/BRIGHT to the correct item
130 // based on the last X<n> we saw or sent.
131 unitCode = lastUnit[houseCode - 'A'];
134 if (command == Commands.ON) {
135 lastUnit[houseCode - 'A'] = unitCode;
139 signalLevel = (byte) ((data[7] & 0xF0) >> 4);
143 public byte[] decodeMessage() {
144 // Example data 07 10 01 00 42 01 01 70
145 // 07 10 01 00 42 10 06 70
147 byte[] data = new byte[8];
150 data[1] = PacketType.LIGHTING1.toByte();
151 data[2] = subType.toByte();
153 data[4] = (byte) houseCode;
155 data[6] = command.toByte();
156 data[7] = (byte) ((signalLevel & 0x0F) << 4);
162 public String getDeviceId() {
163 return houseCode + ID_DELIMITER + unitCode;
167 public Command convertToCommand(String channelId, RFXComDeviceConfiguration config, DeviceState deviceState)
168 throws RFXComUnsupportedChannelException, RFXComInvalidStateException {
170 case CHANNEL_COMMAND:
174 return OnOffType.OFF;
181 return IncreaseDecreaseType.DECREASE;
184 return IncreaseDecreaseType.INCREASE;
190 throw new RFXComUnsupportedChannelException(
191 "Channel " + channelId + " does not accept " + command);
195 return super.convertToCommand(channelId, config, deviceState);
200 public State convertToState(String channelId, RFXComDeviceConfiguration config, DeviceState deviceState)
201 throws RFXComUnsupportedChannelException {
203 case CHANNEL_COMMAND:
208 return OnOffType.OFF;
217 throw new RFXComUnsupportedChannelException(
218 "Channel " + channelId + " does not accept " + command);
221 case CHANNEL_COMMAND_STRING:
222 return command == null ? UnDefType.UNDEF : StringType.valueOf(command.toString());
224 case CHANNEL_CONTACT:
229 return OpenClosedType.CLOSED;
235 return OpenClosedType.OPEN;
238 throw new RFXComUnsupportedChannelException(
239 "Channel " + channelId + " does not accept " + command);
243 throw new RFXComUnsupportedChannelException("Channel " + channelId + " is not relevant here");
248 public void setSubType(SubType subType) {
249 this.subType = subType;
253 public void setDeviceId(String deviceId) throws RFXComException {
254 String[] ids = deviceId.split("\\" + ID_DELIMITER);
255 if (ids.length != 2) {
256 throw new RFXComException("Invalid device id '" + deviceId + "'");
259 houseCode = ids[0].charAt(0);
261 // Get unitcode, 0 means group
262 unitCode = Byte.parseByte(ids[1]);
270 public void convertFromState(String channelId, Type type) throws RFXComUnsupportedChannelException {
272 case CHANNEL_COMMAND:
273 if (type instanceof OnOffType) {
275 command = (type == OnOffType.ON ? Commands.GROUP_ON : Commands.GROUP_OFF);
278 command = (type == OnOffType.ON ? Commands.ON : Commands.OFF);
281 throw new RFXComUnsupportedChannelException("Channel " + channelId + " does not accept " + type);
285 case CHANNEL_COMMAND_STRING:
286 command = Commands.valueOf(type.toString().toUpperCase());
290 throw new RFXComUnsupportedChannelException("Channel " + channelId + " is not relevant here");
295 public SubType convertSubType(String subType) throws RFXComUnsupportedValueException {
296 return ByteEnumUtil.convertSubType(SubType.class, subType);