2 * Copyright (c) 2010-2020 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.exceptions.RFXComException;
18 import org.openhab.binding.rfxcom.internal.exceptions.RFXComUnsupportedChannelException;
19 import org.openhab.binding.rfxcom.internal.exceptions.RFXComUnsupportedValueException;
20 import org.openhab.binding.rfxcom.internal.handler.DeviceState;
21 import org.openhab.core.library.types.IncreaseDecreaseType;
22 import org.openhab.core.library.types.OnOffType;
23 import org.openhab.core.library.types.OpenClosedType;
24 import org.openhab.core.library.types.StringType;
25 import org.openhab.core.types.Command;
26 import org.openhab.core.types.State;
27 import org.openhab.core.types.Type;
28 import org.openhab.core.types.UnDefType;
31 * RFXCOM data class for lighting1 message. See X10, ARC, etc..
33 * @author Evert van Es, Cycling Engineer - Initial contribution
34 * @author Pauli Anttila
36 public class RFXComLighting1Message extends RFXComDeviceMessageImpl<RFXComLighting1Message.SubType> {
38 public enum SubType implements ByteEnumWrapper {
52 private final int subType;
54 SubType(int subType) {
55 this.subType = subType;
59 public byte toByte() {
60 return (byte) subType;
64 public enum Commands implements ByteEnumWrapper {
73 private final int command;
75 Commands(int command) {
76 this.command = command;
80 public byte toByte() {
81 return (byte) command;
85 public SubType subType;
86 public char houseCode;
88 public Commands command;
91 private static byte[] lastUnit = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
93 public RFXComLighting1Message() {
94 super(PacketType.LIGHTING1);
97 public RFXComLighting1Message(byte[] data) throws RFXComException {
102 public String toString() {
105 str += super.toString();
106 str += ", Sub type = " + subType;
107 str += ", Device Id = " + getDeviceId();
108 str += ", Command = " + command;
109 str += ", Signal level = " + signalLevel;
115 public void encodeMessage(byte[] data) throws RFXComException {
116 super.encodeMessage(data);
118 subType = ByteEnumUtil.fromByte(SubType.class, super.subType);
119 houseCode = (char) data[4];
120 command = ByteEnumUtil.fromByte(Commands.class, data[6]);
122 if ((command == Commands.GROUP_ON) || (command == Commands.GROUP_OFF)) {
124 } else if ((data[5] == 0) && ((command == Commands.DIM) || (command == Commands.BRIGHT))) {
125 // SS13 switches broadcast DIM/BRIGHT to X0 and the dimmers ignore
126 // the message unless the last X<n> ON they saw was for them. So we
127 // redirect an incoming broadcast DIM/BRIGHT to the correct item
128 // based on the last X<n> we saw or sent.
129 unitCode = lastUnit[(int) houseCode - (int) 'A'];
132 if (command == Commands.ON) {
133 lastUnit[(int) houseCode - (int) 'A'] = unitCode;
137 signalLevel = (byte) ((data[7] & 0xF0) >> 4);
141 public byte[] decodeMessage() {
142 // Example data 07 10 01 00 42 01 01 70
143 // 07 10 01 00 42 10 06 70
145 byte[] data = new byte[8];
148 data[1] = PacketType.LIGHTING1.toByte();
149 data[2] = subType.toByte();
151 data[4] = (byte) houseCode;
153 data[6] = command.toByte();
154 data[7] = (byte) ((signalLevel & 0x0F) << 4);
160 public String getDeviceId() {
161 return houseCode + ID_DELIMITER + unitCode;
165 public Command convertToCommand(String channelId, DeviceState deviceState)
166 throws RFXComUnsupportedChannelException {
168 case CHANNEL_COMMAND:
172 return OnOffType.OFF;
179 return IncreaseDecreaseType.DECREASE;
182 return IncreaseDecreaseType.INCREASE;
188 throw new RFXComUnsupportedChannelException(
189 "Channel " + channelId + " does not accept " + command);
193 return super.convertToCommand(channelId, deviceState);
197 public State convertToState(String channelId, DeviceState deviceState) throws RFXComUnsupportedChannelException {
199 case CHANNEL_COMMAND:
204 return OnOffType.OFF;
213 throw new RFXComUnsupportedChannelException(
214 "Channel " + channelId + " does not accept " + command);
217 case CHANNEL_COMMAND_STRING:
218 return command == null ? UnDefType.UNDEF : StringType.valueOf(command.toString());
220 case CHANNEL_CONTACT:
225 return OpenClosedType.CLOSED;
231 return OpenClosedType.OPEN;
234 throw new RFXComUnsupportedChannelException(
235 "Channel " + channelId + " does not accept " + command);
239 throw new RFXComUnsupportedChannelException("Channel " + channelId + " is not relevant here");
244 public void setSubType(SubType subType) {
245 this.subType = subType;
249 public void setDeviceId(String deviceId) throws RFXComException {
250 String[] ids = deviceId.split("\\" + ID_DELIMITER);
251 if (ids.length != 2) {
252 throw new RFXComException("Invalid device id '" + deviceId + "'");
255 houseCode = ids[0].charAt(0);
257 // Get unitcode, 0 means group
258 unitCode = Byte.parseByte(ids[1]);
266 public void convertFromState(String channelId, Type type) throws RFXComUnsupportedChannelException {
268 case CHANNEL_COMMAND:
269 if (type instanceof OnOffType) {
271 command = (type == OnOffType.ON ? Commands.GROUP_ON : Commands.GROUP_OFF);
274 command = (type == OnOffType.ON ? Commands.ON : Commands.OFF);
277 throw new RFXComUnsupportedChannelException("Channel " + channelId + " does not accept " + type);
281 case CHANNEL_COMMAND_STRING:
282 command = Commands.valueOf(type.toString().toUpperCase());
286 throw new RFXComUnsupportedChannelException("Channel " + channelId + " is not relevant here");
291 public SubType convertSubType(String subType) throws RFXComUnsupportedValueException {
292 return ByteEnumUtil.convertSubType(SubType.class, subType);