2 * Copyright (c) 2010-2024 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;
18 import org.openhab.binding.rfxcom.internal.config.RFXComDeviceConfiguration;
19 import org.openhab.binding.rfxcom.internal.exceptions.RFXComException;
20 import org.openhab.binding.rfxcom.internal.exceptions.RFXComInvalidStateException;
21 import org.openhab.binding.rfxcom.internal.exceptions.RFXComUnsupportedChannelException;
22 import org.openhab.binding.rfxcom.internal.exceptions.RFXComUnsupportedValueException;
23 import org.openhab.binding.rfxcom.internal.handler.DeviceState;
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.State;
28 import org.openhab.core.types.Type;
31 * RFXCOM data class for Security1 message.
32 * (i.e. X10 Security, Visonic PowerCode, Meiantech, etc.)
34 * @author David Kalff - Initial contribution
35 * @author Pauli Anttila
37 public class RFXComSecurity1Message extends RFXComBatteryDeviceMessage<RFXComSecurity1Message.SubType> {
39 public enum SubType implements ByteEnumWrapper {
41 X10_SECURITY_MOTION(1),
42 X10_SECURITY_REMOTE(2),
44 VISONIC_POWERCODE_SENSOR_PRIMARY_CONTACT(4),
45 VISONIC_POWERCODE_MOTION(5),
46 VISONIC_CODESECURE(6),
47 VISONIC_POWERCODE_SENSOR_AUX_CONTACT(7),
52 private final int subType;
54 SubType(int subType) {
55 this.subType = subType;
59 public byte toByte() {
60 return (byte) subType;
64 public enum Status implements ByteEnumWrapper {
88 NORMAL_DELAYED_TAMPER(129),
90 ALARM_DELAYED_TAMPER(131),
92 NO_MOTION_TAMPER(133);
94 private final int status;
101 public byte toByte() {
102 return (byte) status;
106 /* Added item for ContactTypes */
107 public enum Contact implements ByteEnumWrapper {
113 NORMAL_DELAYED_TAMPER(129),
115 ALARM_DELAYED_TAMPER(131),
119 private final int contact;
121 Contact(int contact) {
122 this.contact = contact;
126 public byte toByte() {
127 return (byte) contact;
130 public static Contact fromByte(int input) {
131 for (Contact status : Contact.values()) {
132 if (status.contact == input) {
137 return Contact.UNKNOWN;
141 /* Added item for MotionTypes */
142 public enum Motion implements ByteEnumWrapper {
146 NO_MOTION_TAMPER(133),
150 private final int motion;
153 this.motion = motion;
157 public byte toByte() {
158 return (byte) motion;
161 public static Motion fromByte(int input) {
162 for (Motion motion : Motion.values()) {
163 if (motion.motion == input) {
168 return Motion.UNKNOWN;
172 public SubType subType;
174 public Status status;
175 public Contact contact;
176 public Motion motion;
178 public RFXComSecurity1Message() {
179 super(PacketType.SECURITY1);
182 public RFXComSecurity1Message(byte[] data) throws RFXComException {
187 public String toString() {
190 str += super.toString();
191 str += ", Sub type = " + subType;
192 str += ", Device Id = " + getDeviceId();
193 str += ", Status = " + status;
194 str += ", Battery level = " + batteryLevel;
195 str += ", Signal level = " + signalLevel;
201 public void encodeMessage(byte[] data) throws RFXComException {
202 super.encodeMessage(data);
204 subType = fromByte(SubType.class, super.subType);
205 sensorId = (data[4] & 0xFF) << 16 | (data[5] & 0xFF) << 8 | (data[6] & 0xFF);
207 status = fromByte(Status.class, data[7]);
208 batteryLevel = (byte) ((data[8] & 0xF0) >> 4);
209 signalLevel = (byte) (data[8] & 0x0F);
211 contact = Contact.fromByte(data[7]);
212 motion = Motion.fromByte(data[7]);
216 public byte[] decodeMessage() {
217 byte[] data = new byte[9];
220 data[1] = RFXComBaseMessage.PacketType.SECURITY1.toByte();
221 data[2] = subType.toByte();
223 data[4] = (byte) ((sensorId >> 16) & 0xFF);
224 data[5] = (byte) ((sensorId >> 8) & 0xFF);
225 data[6] = (byte) (sensorId & 0xFF);
226 data[7] = status.toByte();
227 data[8] = (byte) (((batteryLevel & 0x0F) << 4) | (signalLevel & 0x0F));
233 public String getDeviceId() {
234 return String.valueOf(sensorId);
238 public State convertToState(String channelId, RFXComDeviceConfiguration config, DeviceState deviceState)
239 throws RFXComUnsupportedChannelException, RFXComInvalidStateException {
246 return OnOffType.OFF;
248 throw new RFXComUnsupportedChannelException("Can't convert " + status + " for " + channelId);
251 case CHANNEL_CONTACT:
254 return OpenClosedType.CLOSED;
256 return OpenClosedType.CLOSED;
258 return OpenClosedType.OPEN;
260 return OpenClosedType.OPEN;
262 throw new RFXComUnsupportedChannelException("Can't convert " + status + " for " + channelId);
266 return new StringType(status.toString());
269 return super.convertToState(channelId, config, deviceState);
274 public void setSubType(SubType subType) {
275 this.subType = subType;
279 public void setDeviceId(String deviceId) {
280 sensorId = Integer.parseInt(deviceId);
284 public void convertFromState(String channelId, Type type) throws RFXComUnsupportedChannelException {
286 case CHANNEL_COMMAND:
287 if ((type instanceof OnOffType) && (subType == SubType.X10_SECURITY_REMOTE)) {
288 status = (type == OnOffType.ON ? Status.ARM_AWAY_DELAYED : Status.DISARM);
291 throw new RFXComUnsupportedChannelException("Channel " + channelId + " does not accept " + type);
296 if (type instanceof StringType) {
297 status = Status.valueOf(type.toString());
300 throw new RFXComUnsupportedChannelException("Channel " + channelId + " does not accept " + type);
305 throw new RFXComUnsupportedChannelException("Channel " + channelId + " is not relevant here");
310 public SubType convertSubType(String subType) throws RFXComUnsupportedValueException {
311 return ByteEnumUtil.convertSubType(SubType.class, subType);