]> git.basschouten.com Git - openhab-addons.git/blob
daf1f3aeea01504107902416e1f4eddb8dfe2c3c
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2020 Contributors to the openHAB project
3  *
4  * See the NOTICE file(s) distributed with this work for additional
5  * information.
6  *
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
10  *
11  * SPDX-License-Identifier: EPL-2.0
12  */
13 package org.openhab.binding.rfxcom.internal.messages;
14
15 import static org.openhab.binding.rfxcom.internal.RFXComBindingConstants.*;
16 import static org.openhab.binding.rfxcom.internal.messages.ByteEnumUtil.fromByte;
17
18 import org.openhab.binding.rfxcom.internal.exceptions.RFXComException;
19 import org.openhab.binding.rfxcom.internal.exceptions.RFXComUnsupportedChannelException;
20 import org.openhab.binding.rfxcom.internal.exceptions.RFXComUnsupportedValueException;
21 import org.openhab.binding.rfxcom.internal.handler.DeviceState;
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.State;
26 import org.openhab.core.types.Type;
27
28 /**
29  * RFXCOM data class for Security1 message.
30  * (i.e. X10 Security, Visonic PowerCode, Meiantech, etc.)
31  *
32  * @author David Kalff - Initial contribution
33  * @author Pauli Anttila
34  */
35 public class RFXComSecurity1Message extends RFXComBatteryDeviceMessage<RFXComSecurity1Message.SubType> {
36
37     public enum SubType implements ByteEnumWrapper {
38         X10_SECURITY(0),
39         X10_SECURITY_MOTION(1),
40         X10_SECURITY_REMOTE(2),
41         KD101(3),
42         VISONIC_POWERCODE_SENSOR_PRIMARY_CONTACT(4),
43         VISONIC_POWERCODE_MOTION(5),
44         VISONIC_CODESECURE(6),
45         VISONIC_POWERCODE_SENSOR_AUX_CONTACT(7),
46         MEIANTECH(8),
47         SA30(9), // Also SA33
48         RM174RF(10);
49
50         private final int subType;
51
52         SubType(int subType) {
53             this.subType = subType;
54         }
55
56         @Override
57         public byte toByte() {
58             return (byte) subType;
59         }
60     }
61
62     public enum Status implements ByteEnumWrapper {
63         NORMAL(0),
64         NORMAL_DELAYED(1),
65         ALARM(2),
66         ALARM_DELAYED(3),
67         MOTION(4),
68         NO_MOTION(5),
69         PANIC(6),
70         END_PANIC(7),
71         IR(8),
72         ARM_AWAY(9),
73         ARM_AWAY_DELAYED(10),
74         ARM_HOME(11),
75         ARM_HOME_DELAYED(12),
76         DISARM(13),
77         LIGHT_1_OFF(16),
78         LIGHT_1_ON(17),
79         LIGHT_2_OFF(18),
80         LIGHT_2_ON(19),
81         DARK_DETECTED(20),
82         LIGHT_DETECTED(21),
83         BATLOW(22),
84         PAIR_KD101(23),
85         NORMAL_TAMPER(128),
86         NORMAL_DELAYED_TAMPER(129),
87         ALARM_TAMPER(130),
88         ALARM_DELAYED_TAMPER(131),
89         MOTION_TAMPER(132),
90         NO_MOTION_TAMPER(133);
91
92         private final int status;
93
94         Status(int status) {
95             this.status = status;
96         }
97
98         @Override
99         public byte toByte() {
100             return (byte) status;
101         }
102     }
103
104     /* Added item for ContactTypes */
105     public enum Contact implements ByteEnumWrapper {
106         NORMAL(0),
107         NORMAL_DELAYED(1),
108         ALARM(2),
109         ALARM_DELAYED(3),
110         NORMAL_TAMPER(128),
111         NORMAL_DELAYED_TAMPER(129),
112         ALARM_TAMPER(130),
113         ALARM_DELAYED_TAMPER(131),
114
115         UNKNOWN(255);
116
117         private final int contact;
118
119         Contact(int contact) {
120             this.contact = contact;
121         }
122
123         @Override
124         public byte toByte() {
125             return (byte) contact;
126         }
127
128         public static Contact fromByte(int input) {
129             for (Contact status : Contact.values()) {
130                 if (status.contact == input) {
131                     return status;
132                 }
133             }
134
135             return Contact.UNKNOWN;
136         }
137     }
138
139     /* Added item for MotionTypes */
140     public enum Motion implements ByteEnumWrapper {
141         MOTION(4),
142         NO_MOTION(5),
143         MOTION_TAMPER(132),
144         NO_MOTION_TAMPER(133),
145
146         UNKNOWN(255);
147
148         private final int motion;
149
150         Motion(int motion) {
151             this.motion = motion;
152         }
153
154         @Override
155         public byte toByte() {
156             return (byte) motion;
157         }
158
159         public static Motion fromByte(int input) {
160             for (Motion motion : Motion.values()) {
161                 if (motion.motion == input) {
162                     return motion;
163                 }
164             }
165
166             return Motion.UNKNOWN;
167         }
168     }
169
170     public SubType subType;
171     public int sensorId;
172     public Status status;
173     public Contact contact;
174     public Motion motion;
175
176     public RFXComSecurity1Message() {
177         super(PacketType.SECURITY1);
178     }
179
180     public RFXComSecurity1Message(byte[] data) throws RFXComException {
181         encodeMessage(data);
182     }
183
184     @Override
185     public String toString() {
186         String str = "";
187
188         str += super.toString();
189         str += ", Sub type = " + subType;
190         str += ", Device Id = " + getDeviceId();
191         str += ", Status = " + status;
192         str += ", Battery level = " + batteryLevel;
193         str += ", Signal level = " + signalLevel;
194
195         return str;
196     }
197
198     @Override
199     public void encodeMessage(byte[] data) throws RFXComException {
200         super.encodeMessage(data);
201
202         subType = fromByte(SubType.class, super.subType);
203         sensorId = (data[4] & 0xFF) << 16 | (data[5] & 0xFF) << 8 | (data[6] & 0xFF);
204
205         status = fromByte(Status.class, data[7]);
206         batteryLevel = (byte) ((data[8] & 0xF0) >> 4);
207         signalLevel = (byte) (data[8] & 0x0F);
208
209         contact = Contact.fromByte(data[7]);
210         motion = Motion.fromByte(data[7]);
211     }
212
213     @Override
214     public byte[] decodeMessage() {
215         byte[] data = new byte[9];
216
217         data[0] = 0x08;
218         data[1] = RFXComBaseMessage.PacketType.SECURITY1.toByte();
219         data[2] = subType.toByte();
220         data[3] = seqNbr;
221         data[4] = (byte) ((sensorId >> 16) & 0xFF);
222         data[5] = (byte) ((sensorId >> 8) & 0xFF);
223         data[6] = (byte) (sensorId & 0xFF);
224         data[7] = status.toByte();
225         data[8] = (byte) (((batteryLevel & 0x0F) << 4) | (signalLevel & 0x0F));
226
227         return data;
228     }
229
230     @Override
231     public String getDeviceId() {
232         return String.valueOf(sensorId);
233     }
234
235     @Override
236     public State convertToState(String channelId, DeviceState deviceState) throws RFXComUnsupportedChannelException {
237         switch (channelId) {
238             case CHANNEL_MOTION:
239                 switch (status) {
240                     case MOTION:
241                         return OnOffType.ON;
242                     case NO_MOTION:
243                         return OnOffType.OFF;
244                     default:
245                         throw new RFXComUnsupportedChannelException("Can't convert " + status + " for " + channelId);
246                 }
247
248             case CHANNEL_CONTACT:
249                 switch (status) {
250                     case NORMAL:
251                         return OpenClosedType.CLOSED;
252                     case NORMAL_DELAYED:
253                         return OpenClosedType.CLOSED;
254                     case ALARM:
255                         return OpenClosedType.OPEN;
256                     case ALARM_DELAYED:
257                         return OpenClosedType.OPEN;
258                     default:
259                         throw new RFXComUnsupportedChannelException("Can't convert " + status + " for " + channelId);
260                 }
261
262             case CHANNEL_STATUS:
263                 return new StringType(status.toString());
264
265             default:
266                 return super.convertToState(channelId, deviceState);
267         }
268     }
269
270     @Override
271     public void setSubType(SubType subType) {
272         this.subType = subType;
273     }
274
275     @Override
276     public void setDeviceId(String deviceId) {
277         sensorId = Integer.parseInt(deviceId);
278     }
279
280     @Override
281     public void convertFromState(String channelId, Type type) throws RFXComUnsupportedChannelException {
282         switch (channelId) {
283             case CHANNEL_COMMAND:
284                 if ((type instanceof OnOffType) && (subType == SubType.X10_SECURITY_REMOTE)) {
285                     status = (type == OnOffType.ON ? Status.ARM_AWAY_DELAYED : Status.DISARM);
286
287                 } else {
288                     throw new RFXComUnsupportedChannelException("Channel " + channelId + " does not accept " + type);
289                 }
290                 break;
291
292             case CHANNEL_STATUS:
293                 if (type instanceof StringType) {
294                     status = Status.valueOf(type.toString());
295
296                 } else {
297                     throw new RFXComUnsupportedChannelException("Channel " + channelId + " does not accept " + type);
298                 }
299                 break;
300
301             default:
302                 throw new RFXComUnsupportedChannelException("Channel " + channelId + " is not relevant here");
303         }
304     }
305
306     @Override
307     public SubType convertSubType(String subType) throws RFXComUnsupportedValueException {
308         return ByteEnumUtil.convertSubType(SubType.class, subType);
309     }
310 }