2 * Copyright (c) 2010-2023 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.messages.ByteEnumUtil.fromByte;
17 import static org.openhab.binding.rfxcom.internal.messages.RFXComThermostat3Message.SubType.*;
19 import java.util.Arrays;
20 import java.util.List;
22 import org.openhab.binding.rfxcom.internal.config.RFXComDeviceConfiguration;
23 import org.openhab.binding.rfxcom.internal.exceptions.RFXComException;
24 import org.openhab.binding.rfxcom.internal.exceptions.RFXComInvalidStateException;
25 import org.openhab.binding.rfxcom.internal.exceptions.RFXComUnsupportedChannelException;
26 import org.openhab.binding.rfxcom.internal.exceptions.RFXComUnsupportedValueException;
27 import org.openhab.binding.rfxcom.internal.handler.DeviceState;
28 import org.openhab.core.library.types.OnOffType;
29 import org.openhab.core.library.types.PercentType;
30 import org.openhab.core.library.types.StopMoveType;
31 import org.openhab.core.library.types.StringType;
32 import org.openhab.core.library.types.UpDownType;
33 import org.openhab.core.types.State;
34 import org.openhab.core.types.Type;
35 import org.openhab.core.types.UnDefType;
38 * RFXCOM data class for thermostat3message.
40 * Mertik G6R-XXX Thermostat RF sensor operational
42 * @author Sander Biesenbeek - Initial contribution
43 * @author Ruud Beukema - Initial contribution (parallel development)
44 * @author Martin van Wingerden - Joined contribution of Sander & Ruud
46 public class RFXComThermostat3Message extends RFXComDeviceMessageImpl<RFXComThermostat3Message.SubType> {
47 public enum SubType implements ByteEnumWrapper {
49 MERTIK__G6R_H4TB__G6R_H4T__G6R_H4T21_Z22(1),
50 MERTIK__G6R_H4TD__G6R_H4T16(2),
51 MERTIK__G6R_H4S_TRANSMIT_ONLY(3);
53 private final int subType;
55 SubType(int subType) {
56 this.subType = subType;
60 public byte toByte() {
61 return (byte) subType;
65 public enum Commands implements ByteEnumWrapperWithSupportedSubTypes<SubType> {
70 RUN_UP(4, MERTIK__G6R_H4T1),
71 SECOND_OFF(4, MERTIK__G6R_H4TB__G6R_H4T__G6R_H4T21_Z22),
72 RUN_DOWN(5, MERTIK__G6R_H4T1),
73 SECOND_ON(5, MERTIK__G6R_H4TB__G6R_H4T__G6R_H4T21_Z22),
74 STOP(6, MERTIK__G6R_H4T1);
76 private final int command;
77 private final List<SubType> supportedBySubTypes;
79 Commands(int command) {
80 this(command, SubType.values());
83 Commands(int command, SubType... supportedBySubTypes) {
84 this.command = command;
85 this.supportedBySubTypes = Arrays.asList(supportedBySubTypes);
89 public byte toByte() {
90 return (byte) command;
94 public List<SubType> supportedBySubTypes() {
95 return supportedBySubTypes;
99 public SubType subType;
101 public Commands command;
103 public RFXComThermostat3Message() {
104 super(PacketType.THERMOSTAT3);
107 public RFXComThermostat3Message(byte[] data) throws RFXComException {
112 public String toString() {
115 str += super.toString();
116 str += ", Sub type = " + subType;
117 str += ", Device Id = " + getDeviceId();
118 str += ", Command = " + command;
119 str += ", Signal level = " + signalLevel;
125 public String getDeviceId() {
126 return String.valueOf(unitId);
130 public void encodeMessage(byte[] data) throws RFXComException {
131 super.encodeMessage(data);
133 subType = fromByte(SubType.class, super.subType);
134 unitId = (data[4] & 0xFF) << 16 | (data[5] & 0xFF) << 8 | (data[6] & 0xFF);
135 command = fromByte(Commands.class, data[7], subType);
136 signalLevel = (byte) ((data[8] & 0xF0) >> 4);
140 public byte[] decodeMessage() {
141 byte[] data = new byte[9];
144 data[1] = RFXComBaseMessage.PacketType.THERMOSTAT3.toByte();
145 data[2] = subType.toByte();
147 data[4] = (byte) ((unitId >> 16) & 0xFF);
148 data[5] = (byte) ((unitId >> 8) & 0xFF);
149 data[6] = (byte) (unitId & 0xFF);
150 data[7] = command.toByte();
151 data[8] = (byte) ((signalLevel & 0x0F) << 4);
157 public State convertToState(String channelId, RFXComDeviceConfiguration config, DeviceState deviceState)
158 throws RFXComUnsupportedChannelException, RFXComInvalidStateException {
160 case CHANNEL_COMMAND:
164 return OnOffType.OFF;
173 return UnDefType.UNDEF;
176 case CHANNEL_CONTROL:
182 return UpDownType.UP;
184 return OnOffType.OFF;
187 return UpDownType.DOWN;
193 throw new RFXComUnsupportedChannelException("Can't convert " + command + " for " + channelId);
195 case CHANNEL_COMMAND_SECOND:
198 return OnOffType.OFF;
204 case CHANNEL_COMMAND_STRING:
205 return command == null ? UnDefType.UNDEF : StringType.valueOf(command.toString());
208 return super.convertToState(channelId, config, deviceState);
213 public void convertFromState(String channelId, Type type) throws RFXComUnsupportedChannelException {
215 case CHANNEL_COMMAND:
216 if (type instanceof OnOffType) {
217 command = (type == OnOffType.ON ? Commands.ON : Commands.OFF);
219 throw new RFXComUnsupportedChannelException("Channel " + channelId + " does not accept " + type);
223 case CHANNEL_COMMAND_SECOND:
224 if (type instanceof OnOffType) {
225 command = (type == OnOffType.ON ? Commands.SECOND_ON : Commands.SECOND_OFF);
227 throw new RFXComUnsupportedChannelException("Channel " + channelId + " does not accept " + type);
231 case CHANNEL_CONTROL:
232 if (type instanceof UpDownType) {
233 command = (type == UpDownType.UP ? Commands.UP : Commands.DOWN);
234 } else if (type == StopMoveType.STOP) {
235 command = Commands.STOP;
236 } else if (type instanceof PercentType) {
237 command = ((PercentType) type).as(UpDownType.class) == UpDownType.UP ? Commands.UP : Commands.DOWN;
239 throw new RFXComUnsupportedChannelException("Channel " + channelId + " does not accept " + type);
243 case CHANNEL_COMMAND_STRING:
244 command = Commands.valueOf(type.toString().toUpperCase());
248 throw new RFXComUnsupportedChannelException("Channel " + channelId + " is not relevant here");
253 public SubType convertSubType(String subType) throws RFXComUnsupportedValueException {
254 return ByteEnumUtil.convertSubType(SubType.class, subType);
258 public void setSubType(SubType subType) {
259 this.subType = subType;
263 public void setDeviceId(String deviceId) {
264 this.unitId = Integer.parseInt(deviceId);