]> git.basschouten.com Git - openhab-addons.git/blob
2c84bcbf71b6a6f8df34643e67b108245ad744b1
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2021 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.RFXComBaseMessage.PacketType.LIGHTING2;
18 import static org.openhab.binding.rfxcom.internal.messages.RFXComLighting2Message.Commands.*;
19
20 import java.math.BigDecimal;
21 import java.math.RoundingMode;
22
23 import org.openhab.binding.rfxcom.internal.exceptions.RFXComException;
24 import org.openhab.binding.rfxcom.internal.exceptions.RFXComUnsupportedChannelException;
25 import org.openhab.binding.rfxcom.internal.exceptions.RFXComUnsupportedValueException;
26 import org.openhab.binding.rfxcom.internal.handler.DeviceState;
27 import org.openhab.core.library.types.IncreaseDecreaseType;
28 import org.openhab.core.library.types.OnOffType;
29 import org.openhab.core.library.types.OpenClosedType;
30 import org.openhab.core.library.types.PercentType;
31 import org.openhab.core.types.State;
32 import org.openhab.core.types.Type;
33
34 /**
35  * RFXCOM data class for lighting2 message.
36  *
37  * @author Pauli Anttila - Initial contribution
38  */
39 public class RFXComLighting2Message extends RFXComDeviceMessageImpl<RFXComLighting2Message.SubType> {
40     public enum SubType implements ByteEnumWrapper {
41         AC(0),
42         HOME_EASY_EU(1),
43         ANSLUT(2),
44         KAMBROOK(3);
45
46         private final int subType;
47
48         SubType(int subType) {
49             this.subType = subType;
50         }
51
52         @Override
53         public byte toByte() {
54             return (byte) subType;
55         }
56     }
57
58     public enum Commands implements ByteEnumWrapper {
59         OFF(0),
60         ON(1),
61         SET_LEVEL(2),
62         GROUP_OFF(3),
63         GROUP_ON(4),
64         SET_GROUP_LEVEL(5);
65
66         private final int command;
67
68         Commands(int command) {
69             this.command = command;
70         }
71
72         @Override
73         public byte toByte() {
74             return (byte) command;
75         }
76     }
77
78     public SubType subType;
79     public int sensorId;
80     public byte unitCode;
81     public Commands command;
82     public byte dimmingLevel;
83     public boolean group;
84
85     public RFXComLighting2Message() {
86         super(PacketType.LIGHTING2);
87     }
88
89     public RFXComLighting2Message(byte[] data) throws RFXComException {
90         encodeMessage(data);
91     }
92
93     @Override
94     public String toString() {
95         String str = "";
96
97         str += super.toString();
98         str += ", Sub type = " + subType;
99         str += ", Device Id = " + getDeviceId();
100         str += ", Command = " + command;
101         str += ", Dim level = " + dimmingLevel;
102         str += ", Signal level = " + signalLevel;
103
104         return str;
105     }
106
107     @Override
108     public void encodeMessage(byte[] data) throws RFXComException {
109         super.encodeMessage(data);
110
111         subType = fromByte(SubType.class, super.subType);
112         sensorId = (data[4] & 0xFF) << 24 | (data[5] & 0xFF) << 16 | (data[6] & 0xFF) << 8 | (data[7] & 0xFF);
113         command = fromByte(Commands.class, data[9]);
114
115         if ((command == Commands.GROUP_ON) || (command == Commands.GROUP_OFF)) {
116             unitCode = 0;
117         } else {
118             unitCode = data[8];
119         }
120
121         dimmingLevel = data[10];
122         signalLevel = (byte) ((data[11] & 0xF0) >> 4);
123     }
124
125     @Override
126     public byte[] decodeMessage() {
127         byte[] data = new byte[12];
128
129         data[0] = 0x0B;
130         data[1] = LIGHTING2.toByte();
131         data[2] = subType.toByte();
132         data[3] = seqNbr;
133         data[4] = (byte) ((sensorId >> 24) & 0xFF);
134         data[5] = (byte) ((sensorId >> 16) & 0xFF);
135         data[6] = (byte) ((sensorId >> 8) & 0xFF);
136         data[7] = (byte) (sensorId & 0xFF);
137
138         data[8] = unitCode;
139         data[9] = command.toByte();
140         data[10] = dimmingLevel;
141         data[11] = (byte) ((signalLevel & 0x0F) << 4);
142
143         return data;
144     }
145
146     @Override
147     public String getDeviceId() {
148         return sensorId + ID_DELIMITER + unitCode;
149     }
150
151     /**
152      * Convert a 0-15 scale value to a percent type.
153      *
154      * @param pt percent type to convert
155      * @return converted value 0-15
156      */
157     public static int getDimLevelFromPercentType(PercentType pt) {
158         return pt.toBigDecimal().multiply(BigDecimal.valueOf(15))
159                 .divide(PercentType.HUNDRED.toBigDecimal(), 0, RoundingMode.UP).intValue();
160     }
161
162     /**
163      * Convert a 0-15 scale value to a percent type.
164      *
165      * @param value percent type to convert
166      * @return converted value 0-15
167      */
168     public static PercentType getPercentTypeFromDimLevel(int value) {
169         value = Math.min(value, 15);
170
171         return new PercentType(BigDecimal.valueOf(value).multiply(BigDecimal.valueOf(100))
172                 .divide(BigDecimal.valueOf(15), 0, RoundingMode.UP).intValue());
173     }
174
175     @Override
176     public State convertToState(String channelId, DeviceState deviceState) throws RFXComUnsupportedChannelException {
177         switch (channelId) {
178             case CHANNEL_DIMMING_LEVEL:
179                 return RFXComLighting2Message.getPercentTypeFromDimLevel(dimmingLevel);
180
181             case CHANNEL_COMMAND:
182                 switch (command) {
183                     case OFF:
184                     case GROUP_OFF:
185                         return OnOffType.OFF;
186
187                     case ON:
188                     case GROUP_ON:
189                         return OnOffType.ON;
190
191                     case SET_GROUP_LEVEL:
192                     case SET_LEVEL:
193                     default:
194                         throw new RFXComUnsupportedChannelException("Can't convert " + command + " for " + channelId);
195                 }
196
197             case CHANNEL_CONTACT:
198                 switch (command) {
199                     case OFF:
200                     case GROUP_OFF:
201                         return OpenClosedType.CLOSED;
202
203                     case ON:
204                     case GROUP_ON:
205                         return OpenClosedType.OPEN;
206
207                     case SET_GROUP_LEVEL:
208                     case SET_LEVEL:
209                     default:
210                         throw new RFXComUnsupportedChannelException("Can't convert " + command + " for " + channelId);
211                 }
212
213             default:
214                 return super.convertToState(channelId, deviceState);
215         }
216     }
217
218     @Override
219     public void setSubType(SubType subType) {
220         this.subType = subType;
221     }
222
223     @Override
224     public void setDeviceId(String deviceId) throws RFXComException {
225         String[] ids = deviceId.split("\\" + ID_DELIMITER);
226         if (ids.length != 2) {
227             throw new RFXComException("Invalid device id '" + deviceId + "'");
228         }
229
230         sensorId = Integer.parseInt(ids[0]);
231
232         // Get unitcode, 0 means group
233         unitCode = Byte.parseByte(ids[1]);
234         if (unitCode == 0) {
235             unitCode = 1;
236             group = true;
237         }
238     }
239
240     @Override
241     public void convertFromState(String channelId, Type type) throws RFXComUnsupportedChannelException {
242         switch (channelId) {
243             case CHANNEL_COMMAND:
244                 if (type instanceof OnOffType) {
245                     if (group) {
246                         command = (type == OnOffType.ON ? GROUP_ON : GROUP_OFF);
247
248                     } else {
249                         command = (type == OnOffType.ON ? Commands.ON : Commands.OFF);
250                     }
251
252                     dimmingLevel = 0;
253                 } else {
254                     throw new RFXComUnsupportedChannelException("Channel " + channelId + " does not accept " + type);
255                 }
256                 break;
257
258             case CHANNEL_DIMMING_LEVEL:
259                 if (type instanceof OnOffType) {
260                     command = (type == OnOffType.ON ? Commands.ON : Commands.OFF);
261                     dimmingLevel = 0;
262
263                 } else if (type instanceof PercentType) {
264                     command = Commands.SET_LEVEL;
265                     dimmingLevel = (byte) getDimLevelFromPercentType((PercentType) type);
266
267                     if (dimmingLevel == 0) {
268                         command = Commands.OFF;
269                     }
270                 } else if (type instanceof IncreaseDecreaseType) {
271                     command = Commands.SET_LEVEL;
272                     // Evert: I do not know how to get previous object state...
273                     dimmingLevel = 5;
274
275                 } else {
276                     throw new RFXComUnsupportedChannelException("Channel " + channelId + " does not accept " + type);
277                 }
278                 break;
279
280             default:
281                 throw new RFXComUnsupportedChannelException("Channel " + channelId + " is not relevant here");
282         }
283     }
284
285     @Override
286     public SubType convertSubType(String subType) throws RFXComUnsupportedValueException {
287         return ByteEnumUtil.convertSubType(SubType.class, subType);
288     }
289 }