]> git.basschouten.com Git - openhab-addons.git/blob
83949cf0db953e3162df9617a2f696127804e4c2
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2024 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
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;
31
32 /**
33  * RFXCOM data class for lighting1 message. See X10, ARC, etc..
34  *
35  * @author Evert van Es, Cycling Engineer - Initial contribution
36  * @author Pauli Anttila
37  */
38 public class RFXComLighting1Message extends RFXComDeviceMessageImpl<RFXComLighting1Message.SubType> {
39
40     public enum SubType implements ByteEnumWrapper {
41         X10(0),
42         ARC(1),
43         AB400D(2),
44         WAVEMAN(3),
45         EMW200(4),
46         IMPULS(5),
47         RISINGSUN(6),
48         PHILIPS(7),
49         ENERGENIE(8),
50         ENERGENIE_5(9),
51         COCO(10),
52         HQ_COCO20(11),
53         OASE_INSCENIO_FM_N(12);
54
55         private final int subType;
56
57         SubType(int subType) {
58             this.subType = subType;
59         }
60
61         @Override
62         public byte toByte() {
63             return (byte) subType;
64         }
65     }
66
67     public enum Commands implements ByteEnumWrapper {
68         OFF(0),
69         ON(1),
70         DIM(2),
71         BRIGHT(3),
72         GROUP_OFF(5),
73         GROUP_ON(6),
74         CHIME(7);
75
76         private final int command;
77
78         Commands(int command) {
79             this.command = command;
80         }
81
82         @Override
83         public byte toByte() {
84             return (byte) command;
85         }
86     }
87
88     public SubType subType;
89     public char houseCode;
90     public byte unitCode;
91     public Commands command;
92     public boolean group;
93
94     private static byte[] lastUnit = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
95
96     public RFXComLighting1Message() {
97         super(PacketType.LIGHTING1);
98     }
99
100     public RFXComLighting1Message(byte[] data) throws RFXComException {
101         encodeMessage(data);
102     }
103
104     @Override
105     public String toString() {
106         String str = "";
107
108         str += super.toString();
109         str += ", Sub type = " + subType;
110         str += ", Device Id = " + getDeviceId();
111         str += ", Command = " + command;
112         str += ", Signal level = " + signalLevel;
113
114         return str;
115     }
116
117     @Override
118     public void encodeMessage(byte[] data) throws RFXComException {
119         super.encodeMessage(data);
120
121         subType = ByteEnumUtil.fromByte(SubType.class, super.subType);
122         houseCode = (char) data[4];
123         command = ByteEnumUtil.fromByte(Commands.class, data[6]);
124
125         if ((command == Commands.GROUP_ON) || (command == Commands.GROUP_OFF)) {
126             unitCode = 0;
127         } else if ((data[5] == 0) && ((command == Commands.DIM) || (command == Commands.BRIGHT))) {
128             // SS13 switches broadcast DIM/BRIGHT to X0 and the dimmers ignore
129             // the message unless the last X<n> ON they saw was for them. So we
130             // redirect an incoming broadcast DIM/BRIGHT to the correct item
131             // based on the last X<n> we saw or sent.
132             unitCode = lastUnit[houseCode - 'A'];
133         } else {
134             unitCode = data[5];
135             if (command == Commands.ON) {
136                 lastUnit[houseCode - 'A'] = unitCode;
137             }
138         }
139
140         signalLevel = (byte) ((data[7] & 0xF0) >> 4);
141     }
142
143     @Override
144     public byte[] decodeMessage() {
145         // Example data 07 10 01 00 42 01 01 70
146         // 07 10 01 00 42 10 06 70
147
148         byte[] data = new byte[8];
149
150         data[0] = 0x07;
151         data[1] = PacketType.LIGHTING1.toByte();
152         data[2] = subType.toByte();
153         data[3] = seqNbr;
154         data[4] = (byte) houseCode;
155         data[5] = unitCode;
156         data[6] = command.toByte();
157         data[7] = (byte) ((signalLevel & 0x0F) << 4);
158
159         return data;
160     }
161
162     @Override
163     public String getDeviceId() {
164         return houseCode + ID_DELIMITER + unitCode;
165     }
166
167     @Override
168     public Command convertToCommand(String channelId, RFXComDeviceConfiguration config, DeviceState deviceState)
169             throws RFXComUnsupportedChannelException, RFXComInvalidStateException {
170         switch (channelId) {
171             case CHANNEL_COMMAND:
172                 switch (command) {
173                     case OFF:
174                     case GROUP_OFF:
175                         return OnOffType.OFF;
176
177                     case ON:
178                     case GROUP_ON:
179                         return OnOffType.ON;
180
181                     case DIM:
182                         return IncreaseDecreaseType.DECREASE;
183
184                     case BRIGHT:
185                         return IncreaseDecreaseType.INCREASE;
186
187                     case CHIME:
188                         return OnOffType.ON;
189
190                     default:
191                         throw new RFXComUnsupportedChannelException(
192                                 "Channel " + channelId + " does not accept " + command);
193                 }
194
195             default:
196                 return super.convertToCommand(channelId, config, deviceState);
197         }
198     }
199
200     @Override
201     public State convertToState(String channelId, RFXComDeviceConfiguration config, DeviceState deviceState)
202             throws RFXComUnsupportedChannelException {
203         switch (channelId) {
204             case CHANNEL_COMMAND:
205                 switch (command) {
206                     case OFF:
207                     case GROUP_OFF:
208                     case DIM:
209                         return OnOffType.OFF;
210
211                     case ON:
212                     case GROUP_ON:
213                     case BRIGHT:
214                     case CHIME:
215                         return OnOffType.ON;
216
217                     default:
218                         throw new RFXComUnsupportedChannelException(
219                                 "Channel " + channelId + " does not accept " + command);
220                 }
221
222             case CHANNEL_COMMAND_STRING:
223                 return command == null ? UnDefType.UNDEF : StringType.valueOf(command.toString());
224
225             case CHANNEL_CONTACT:
226                 switch (command) {
227                     case OFF:
228                     case GROUP_OFF:
229                     case DIM:
230                         return OpenClosedType.CLOSED;
231
232                     case ON:
233                     case GROUP_ON:
234                     case BRIGHT:
235                     case CHIME:
236                         return OpenClosedType.OPEN;
237
238                     default:
239                         throw new RFXComUnsupportedChannelException(
240                                 "Channel " + channelId + " does not accept " + command);
241                 }
242
243             default:
244                 throw new RFXComUnsupportedChannelException("Channel " + channelId + " is not relevant here");
245         }
246     }
247
248     @Override
249     public void setSubType(SubType subType) {
250         this.subType = subType;
251     }
252
253     @Override
254     public void setDeviceId(String deviceId) throws RFXComException {
255         String[] ids = deviceId.split("\\" + ID_DELIMITER);
256         if (ids.length != 2) {
257             throw new RFXComException("Invalid device id '" + deviceId + "'");
258         }
259
260         houseCode = ids[0].charAt(0);
261
262         // Get unitcode, 0 means group
263         unitCode = Byte.parseByte(ids[1]);
264         if (unitCode == 0) {
265             unitCode = 1;
266             group = true;
267         }
268     }
269
270     @Override
271     public void convertFromState(String channelId, Type type) throws RFXComUnsupportedChannelException {
272         switch (channelId) {
273             case CHANNEL_COMMAND:
274                 if (type instanceof OnOffType) {
275                     if (group) {
276                         command = (type == OnOffType.ON ? Commands.GROUP_ON : Commands.GROUP_OFF);
277
278                     } else {
279                         command = (type == OnOffType.ON ? Commands.ON : Commands.OFF);
280                     }
281                 } else {
282                     throw new RFXComUnsupportedChannelException("Channel " + channelId + " does not accept " + type);
283                 }
284                 break;
285
286             case CHANNEL_COMMAND_STRING:
287                 command = Commands.valueOf(type.toString().toUpperCase());
288                 break;
289
290             default:
291                 throw new RFXComUnsupportedChannelException("Channel " + channelId + " is not relevant here");
292         }
293     }
294
295     @Override
296     public SubType convertSubType(String subType) throws RFXComUnsupportedValueException {
297         return ByteEnumUtil.convertSubType(SubType.class, subType);
298     }
299 }