]> git.basschouten.com Git - openhab-addons.git/blob
301574fe4f77720be1c9051e290d9487cd29bfa1
[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 import static org.openhab.binding.rfxcom.internal.messages.RFXComFanMessage.Commands.*;
18 import static org.openhab.binding.rfxcom.internal.messages.RFXComFanMessage.SubType.*;
19
20 import java.util.Arrays;
21 import java.util.List;
22
23 import org.eclipse.jdt.annotation.Nullable;
24 import org.openhab.binding.rfxcom.internal.exceptions.RFXComException;
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.DecimalType;
29 import org.openhab.core.library.types.OnOffType;
30 import org.openhab.core.library.types.StringType;
31 import org.openhab.core.library.types.UpDownType;
32 import org.openhab.core.types.State;
33 import org.openhab.core.types.Type;
34 import org.openhab.core.types.UnDefType;
35
36 /**
37  * RFXCOM data class for fan message.
38  *
39  * @author Martin van Wingerden - initial contribution
40  */
41 public class RFXComFanMessage extends RFXComDeviceMessageImpl<RFXComFanMessage.SubType> {
42
43     public enum SubType implements ByteEnumWrapper {
44         SF01(0),
45         CVE_RFT(1),
46         LUCCI_AIR_FAN(2),
47         SEAV_TXS4(3),
48         WESTINGHOUSE_7226640(4),
49         LUCCI_AIR_DC(5),
50         CASAFAN(6),
51         FT1211R(7),
52         FALMEC(8),
53         LUCCI_AIR_DC_II(9);
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 ByteEnumWrapperWithSupportedSubTypes<SubType> {
68         HI(1, WESTINGHOUSE_7226640, CASAFAN, LUCCI_AIR_FAN),
69         MED(2, WESTINGHOUSE_7226640, CASAFAN, LUCCI_AIR_FAN),
70         LOW(3, WESTINGHOUSE_7226640, CASAFAN, LUCCI_AIR_FAN),
71         OFF(4, WESTINGHOUSE_7226640, CASAFAN, LUCCI_AIR_FAN),
72         LIGHT(5, WESTINGHOUSE_7226640, CASAFAN, LUCCI_AIR_FAN),
73
74         FALMEC_POWER_OFF(1, 0, FALMEC),
75         FALMEC_SPEED_1(2, 1, FALMEC),
76         FALMEC_SPEED_2(3, 2, FALMEC),
77         FALMEC_SPEED_3(4, 3, FALMEC),
78         FALMEC_SPEED_4(5, 4, FALMEC),
79         FALMEC_TIMER_1(6, FALMEC),
80         FALMEC_TIMER_2(7, FALMEC),
81         FALMEC_TIMER_3(8, FALMEC),
82         FALMEC_TIMER_4(9, FALMEC),
83         FALMEC_LIGHT_ON(10, FALMEC),
84         FALMEC_LIGHT_OFF(11, FALMEC),
85
86         FT1211R_POWER(1, 0, FT1211R),
87         FT1211R_LIGHT(2, FT1211R),
88         FT1211R_SPEED_1(3, 1, FT1211R),
89         FT1211R_SPEED_2(4, 2, FT1211R),
90         FT1211R_SPEED_3(5, 3, FT1211R),
91         FT1211R_SPEED_4(6, 4, FT1211R),
92         FT1211R_SPEED_5(7, 5, FT1211R),
93         FT1211R_FORWARD_REVERSE(8, FT1211R),
94         FT1211R_TIMER_1H(9, FT1211R),
95         FT1211R_TIMER_4H(10, FT1211R),
96         FT1211R_TIMER_8H(11, FT1211R),
97
98         LUCCI_AIR_DC_POWER(1, LUCCI_AIR_DC),
99         LUCCI_AIR_DC_UP(2, LUCCI_AIR_DC),
100         LUCCI_AIR_DC_DOWN(3, LUCCI_AIR_DC),
101         LUCCI_AIR_DC_LIGHT(4, LUCCI_AIR_DC),
102         LUCCI_AIR_DC_REVERSE(5, LUCCI_AIR_DC),
103         LUCCI_AIR_DC_NATURAL_FLOW(6, LUCCI_AIR_DC),
104         LUCCI_AIR_DC_PAIR(7, LUCCI_AIR_DC),
105
106         LUCCI_AIR_DC_II_POWER_OFF(1, 0, LUCCI_AIR_DC_II),
107         LUCCI_AIR_DC_II_SPEED_1(2, 1, LUCCI_AIR_DC_II),
108         LUCCI_AIR_DC_II_SPEED_2(3, 2, LUCCI_AIR_DC_II),
109         LUCCI_AIR_DC_II_SPEED_3(4, 3, LUCCI_AIR_DC_II),
110         LUCCI_AIR_DC_II_SPEED_4(5, 4, LUCCI_AIR_DC_II),
111         LUCCI_AIR_DC_II_SPEED_5(6, 5, LUCCI_AIR_DC_II),
112         LUCCI_AIR_DC_II_SPEED_6(7, 6, LUCCI_AIR_DC_II),
113         LUCCI_AIR_DC_II_LIGHT(8, LUCCI_AIR_DC_II),
114         LUCCI_AIR_DC_II_REVERSE(9, LUCCI_AIR_DC_II);
115
116         private final int command;
117         private final Integer speed;
118         private final List<SubType> supportedBySubTypes;
119
120         Commands(int command, SubType... supportedSubType) {
121             this(command, null, supportedSubType);
122         }
123
124         Commands(int command, Integer speed, SubType... supportedSubType) {
125             this.command = command;
126             this.speed = speed;
127             this.supportedBySubTypes = Arrays.asList(supportedSubType);
128         }
129
130         @Nullable
131         public static Commands bySpeed(SubType subType, int speed) {
132             for (Commands value : values()) {
133                 if (value.supportedBySubTypes.contains(subType) && value.speed == speed) {
134                     return value;
135                 }
136             }
137             return null;
138         }
139
140         @Override
141         public byte toByte() {
142             return (byte) command;
143         }
144
145         public Integer getSpeed() {
146             return speed;
147         }
148
149         @Override
150         public List<SubType> supportedBySubTypes() {
151             return supportedBySubTypes;
152         }
153     }
154
155     private static final List<SubType> GENERIC_SUB_TYPES = Arrays.asList(WESTINGHOUSE_7226640, CASAFAN, LUCCI_AIR_FAN);
156
157     private static final List<Commands> LIGHT_ON_COMMANDS = Arrays.asList(LIGHT, LUCCI_AIR_DC_LIGHT,
158             LUCCI_AIR_DC_II_LIGHT, FALMEC_LIGHT_ON);
159     private static final List<Commands> ON_COMMANDS = Arrays.asList(Commands.HI, MED, LOW, FALMEC_SPEED_1,
160             FALMEC_SPEED_2, FALMEC_SPEED_3, FALMEC_SPEED_4, LUCCI_AIR_DC_II_SPEED_1, LUCCI_AIR_DC_II_SPEED_2,
161             LUCCI_AIR_DC_II_SPEED_3, LUCCI_AIR_DC_II_SPEED_4, LUCCI_AIR_DC_II_SPEED_5, LUCCI_AIR_DC_II_SPEED_6);
162     private static final List<Commands> OFF_COMMANDS = Arrays.asList(OFF, FALMEC_POWER_OFF, LUCCI_AIR_DC_II_POWER_OFF);
163
164     private SubType subType;
165     private int sensorId;
166     private Commands command;
167
168     public RFXComFanMessage() {
169         super(PacketType.FAN);
170     }
171
172     public RFXComFanMessage(byte[] data) throws RFXComException {
173         encodeMessage(data);
174     }
175
176     @Override
177     public PacketType getPacketType() {
178         switch (subType) {
179             case LUCCI_AIR_FAN:
180             case CASAFAN:
181             case WESTINGHOUSE_7226640:
182                 return PacketType.FAN;
183             case SF01:
184                 return PacketType.FAN_SF01;
185             case CVE_RFT:
186                 return PacketType.FAN_ITHO;
187             case SEAV_TXS4:
188                 return PacketType.FAN_SEAV;
189             case LUCCI_AIR_DC:
190                 return PacketType.FAN_LUCCI_DC;
191             case FT1211R:
192                 return PacketType.FAN_FT1211R;
193             case FALMEC:
194                 return PacketType.FAN_FALMEC;
195             case LUCCI_AIR_DC_II:
196                 return PacketType.FAN_LUCCI_DC_II;
197         }
198         return super.getPacketType();
199     }
200
201     @Override
202     public void encodeMessage(byte[] data) throws RFXComException {
203         super.encodeMessage(data);
204
205         subType = fromByte(SubType.class, super.subType);
206         sensorId = (data[4] & 0xFF) << 16 | (data[5] & 0xFF) << 8 | (data[6] & 0xFF);
207         command = fromByte(Commands.class, data[7], subType);
208
209         signalLevel = (byte) (data[8] & 0x0F);
210     }
211
212     @Override
213     public byte[] decodeMessage() {
214         byte[] data = new byte[9];
215
216         data[0] = 0x08;
217         data[1] = PacketType.FAN.toByte();
218         data[2] = subType.toByte();
219         data[3] = seqNbr;
220
221         data[4] = (byte) ((sensorId >> 16) & 0xFF);
222         data[5] = (byte) ((sensorId >> 8) & 0xFF);
223         data[6] = (byte) (sensorId & 0xFF);
224
225         data[7] = command.toByte();
226
227         data[8] = (byte) (signalLevel & 0x0F);
228
229         return data;
230     }
231
232     @Override
233     public String getDeviceId() {
234         return String.valueOf(sensorId);
235     }
236
237     @Override
238     public void setSubType(SubType subType) {
239         this.subType = subType;
240     }
241
242     @Override
243     public void setDeviceId(String deviceId) {
244         sensorId = Integer.parseInt(deviceId);
245     }
246
247     @Override
248     public SubType convertSubType(String subType) throws RFXComUnsupportedValueException {
249         return ByteEnumUtil.convertSubType(SubType.class, subType);
250     }
251
252     @Override
253     public State convertToState(String channelId, DeviceState deviceState) throws RFXComUnsupportedChannelException {
254         switch (channelId) {
255             case CHANNEL_FAN_LIGHT:
256                 return handleLightChannel();
257
258             case CHANNEL_FAN_SPEED:
259                 return handleFanSpeedChannel();
260
261             case CHANNEL_COMMAND:
262                 return handleCommandChannel();
263
264             case CHANNEL_COMMAND_STRING:
265                 return handleCommandStringChannel();
266
267             default:
268                 return super.convertToState(channelId, deviceState);
269         }
270     }
271
272     private State handleCommandStringChannel() {
273         if (command == null) {
274             return UnDefType.UNDEF;
275         }
276         return StringType.valueOf(command.toString().replace(subType.name() + "_", ""));
277     }
278
279     private State handleLightChannel() {
280         if (LIGHT_ON_COMMANDS.contains(command)) {
281             return OnOffType.ON;
282         } else if (command == Commands.FALMEC_LIGHT_OFF) {
283             return OnOffType.OFF;
284         } else {
285             return UnDefType.UNDEF;
286         }
287     }
288
289     private State handleFanSpeedChannel() {
290         switch (command) {
291             case HI:
292             case MED:
293             case LOW:
294             case OFF:
295                 return StringType.valueOf(command.toString());
296
297             case FALMEC_POWER_OFF:
298             case FALMEC_SPEED_1:
299             case FALMEC_SPEED_2:
300             case FALMEC_SPEED_3:
301             case FALMEC_SPEED_4:
302             case FT1211R_POWER:
303             case FT1211R_SPEED_1:
304             case FT1211R_SPEED_2:
305             case FT1211R_SPEED_3:
306             case FT1211R_SPEED_4:
307             case FT1211R_SPEED_5:
308             case LUCCI_AIR_DC_II_POWER_OFF:
309             case LUCCI_AIR_DC_II_SPEED_1:
310             case LUCCI_AIR_DC_II_SPEED_2:
311             case LUCCI_AIR_DC_II_SPEED_3:
312             case LUCCI_AIR_DC_II_SPEED_4:
313             case LUCCI_AIR_DC_II_SPEED_5:
314             case LUCCI_AIR_DC_II_SPEED_6:
315                 return new DecimalType(command.getSpeed());
316
317             case LUCCI_AIR_DC_DOWN:
318                 return UpDownType.DOWN;
319
320             case LUCCI_AIR_DC_UP:
321                 return UpDownType.UP;
322
323             default:
324                 return null;
325         }
326     }
327
328     private State handleCommandChannel() {
329         if (ON_COMMANDS.contains(command)) {
330             return OnOffType.ON;
331         } else if (OFF_COMMANDS.contains(command)) {
332             return OnOffType.OFF;
333         } else {
334             return null;
335         }
336     }
337
338     @Override
339     public void convertFromState(String channelId, Type type) throws RFXComUnsupportedChannelException {
340         switch (channelId) {
341             case CHANNEL_COMMAND:
342                 command = handleCommand(channelId, type);
343                 break;
344
345             case CHANNEL_FAN_SPEED:
346                 command = handleFanSpeedCommand(channelId, type);
347                 break;
348
349             case CHANNEL_FAN_LIGHT:
350                 command = handleFanLightCommand(channelId, type);
351                 break;
352
353             case CHANNEL_COMMAND_STRING:
354                 command = handleCommandString(channelId, type);
355                 break;
356
357             default:
358                 throw new RFXComUnsupportedChannelException("Channel " + channelId + " is not relevant here");
359         }
360     }
361
362     private Commands handleCommandString(String channelId, Type type) throws RFXComUnsupportedChannelException {
363         if (type instanceof StringType) {
364             String stringCommand = type.toString();
365             switch (stringCommand) {
366                 case "POWER":
367                 case "POWER_OFF":
368                 case "UP":
369                 case "DOWN":
370                 case "LIGHT":
371                 case "REVERSE":
372                 case "NATURAL_FLOW":
373                 case "PAIR":
374                 case "SPEED_1":
375                 case "SPEED_2":
376                 case "SPEED_3":
377                 case "SPEED_4":
378                 case "SPEED_5":
379                 case "SPEED_6":
380                     return Commands.valueOf(subType.name() + "_" + stringCommand);
381             }
382         }
383         throw new RFXComUnsupportedChannelException("Channel " + channelId + " does not accept " + type);
384     }
385
386     private Commands handleCommand(String channelId, Type type) throws RFXComUnsupportedChannelException {
387         if (type instanceof OnOffType) {
388             if (GENERIC_SUB_TYPES.contains(subType)) {
389                 return (type == OnOffType.ON ? Commands.MED : Commands.OFF);
390             } else if (subType == FALMEC) {
391                 return (type == OnOffType.ON ? Commands.FALMEC_SPEED_2 : Commands.FALMEC_POWER_OFF);
392             } else if (subType == LUCCI_AIR_DC_II) {
393                 return (type == OnOffType.ON ? LUCCI_AIR_DC_II_SPEED_3 : LUCCI_AIR_DC_II_POWER_OFF);
394             }
395         }
396         throw new RFXComUnsupportedChannelException("Channel " + channelId + " does not accept " + type);
397     }
398
399     private Commands handleFanSpeedCommand(String channelId, Type type) throws RFXComUnsupportedChannelException {
400         if (type instanceof StringType) {
401             String stringCommand = type.toString();
402             switch (stringCommand) {
403                 case "HI":
404                 case "MED":
405                 case "LOW":
406                 case "OFF":
407                     return Commands.valueOf(stringCommand);
408             }
409         } else if (type instanceof DecimalType) {
410             Commands speedCommand = Commands.bySpeed(subType, ((DecimalType) type).intValue());
411             if (speedCommand != null) {
412                 return speedCommand;
413             }
414         } else if (type instanceof UpDownType && subType == LUCCI_AIR_DC) {
415             if (UpDownType.UP == type) {
416                 return Commands.LUCCI_AIR_DC_UP;
417             } else {
418                 return Commands.LUCCI_AIR_DC_DOWN;
419             }
420         }
421         throw new RFXComUnsupportedChannelException("Channel " + channelId + " does not accept " + type);
422     }
423
424     private Commands handleFanLightCommand(String channelId, Type type) throws RFXComUnsupportedChannelException {
425         if (type == OnOffType.ON) {
426             switch (subType) {
427                 case LUCCI_AIR_FAN:
428                 case CASAFAN:
429                 case WESTINGHOUSE_7226640:
430                 case LUCCI_AIR_DC:
431                     return LIGHT;
432
433                 case FALMEC:
434                     return FALMEC_LIGHT_ON;
435
436                 case LUCCI_AIR_DC_II:
437                     return LUCCI_AIR_DC_II_LIGHT;
438             }
439         } else if (type == OnOffType.OFF && subType == FALMEC) {
440             return Commands.FALMEC_LIGHT_OFF;
441         }
442         throw new RFXComUnsupportedChannelException("Channel " + channelId + " does not accept " + type);
443     }
444 }