]> git.basschouten.com Git - openhab-addons.git/blob
8668c0ba6d80118356ba1a485b6a7ed0c062fd08
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2023 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.enocean.internal.eep.D2_06;
14
15 import static org.openhab.binding.enocean.internal.EnOceanBindingConstants.*;
16
17 import java.util.Arrays;
18 import java.util.Optional;
19 import java.util.function.Function;
20
21 import org.eclipse.jdt.annotation.NonNullByDefault;
22 import org.eclipse.jdt.annotation.Nullable;
23 import org.openhab.binding.enocean.internal.eep.Base._VLDMessage;
24 import org.openhab.binding.enocean.internal.messages.ERP1Message;
25 import org.openhab.core.config.core.Configuration;
26 import org.openhab.core.library.types.DecimalType;
27 import org.openhab.core.library.types.OnOffType;
28 import org.openhab.core.library.types.QuantityType;
29 import org.openhab.core.library.types.StringType;
30 import org.openhab.core.library.unit.SIUnits;
31 import org.openhab.core.library.unit.Units;
32 import org.openhab.core.thing.CommonTriggerEvents;
33 import org.openhab.core.types.State;
34 import org.openhab.core.types.UnDefType;
35
36 /**
37  * Implementation of the D2_06_01 EEP as used by window handles manufactured by Soda GmbH. All channels except the
38  * battery channels may be not supported by the physical device (depending on the actual model). If a channel is not
39  * supported by a device it will transmit a 'not supported' message which is ignored by this implementation.
40  * Consequently channels that are not supported by the physical device will never send updates to linked items.
41  * 
42  * @author Thomas Lauterbach - Initial contribution
43  */
44 @NonNullByDefault
45 public class D2_06_01 extends _VLDMessage {
46
47     private enum MessageType {
48         SENSORVALUES(0x00),
49         CONFIGURATIONREPORT(0x10),
50         LOGDATA01(0x20),
51         LOGDATA02(0x21),
52         LOGDATA03(0x22),
53         LOGDATA04(0x23),
54         CONTROLANDSETTINGS(0x80);
55
56         private int intValue;
57
58         private MessageType(int intValue) {
59             this.intValue = intValue;
60         }
61
62         private int getIntValue() {
63             return this.intValue;
64         }
65     }
66
67     private enum SashState {
68         // WINDOWSTATEUNDEFINED(0x00, "UNDEFINED"),
69         NOTTILTED(0x01, "NOT TILTED"),
70         TILTED(0x02, "TILTED");
71
72         private int intValue;
73         private String textValue;
74
75         private SashState(int intValue, String textValue) {
76             this.intValue = intValue;
77             this.textValue = textValue;
78         }
79
80         private String getTextValue() {
81             return this.textValue;
82         }
83
84         private static Optional<SashState> valueOf(int intValue) {
85             return Arrays.stream(values()).filter(sashState -> sashState.intValue == intValue).findFirst();
86         }
87     }
88
89     private enum HandleState {
90         // HANDLEPOSITIONUNDEFINED(0x00, "UNDEFINED"),
91         HANDLEUP(0x01, "UP"),
92         HANDLEDOWN(0x02, "DOWN"),
93         HANDLELEFT(0x03, "LEFT"),
94         HANDLERIGHT(0x04, "RIGHT");
95
96         private int intValue;
97         private String textValue;
98
99         private HandleState(int intValue, String textValue) {
100             this.intValue = intValue;
101             this.textValue = textValue;
102         }
103
104         private String getTextValue() {
105             return this.textValue;
106         }
107
108         private static Optional<HandleState> valueOf(int intValue) {
109             return Arrays.stream(values()).filter(handleState -> handleState.intValue == intValue).findFirst();
110         }
111     }
112
113     private enum MotionState {
114         MOTIONNOTTRIGGERED(0x00, "OFF"),
115         MOTIONTRIGGERED(0x01, "ON");
116
117         private int intValue;
118         private String textValue;
119
120         private MotionState(int intValue, String textValue) {
121             this.intValue = intValue;
122             this.textValue = textValue;
123         }
124
125         private String getTextValue() {
126             return this.textValue;
127         }
128
129         private static Optional<MotionState> valueOf(int intValue) {
130             return Arrays.stream(values()).filter(motionState -> motionState.intValue == intValue).findFirst();
131         }
132     }
133
134     public D2_06_01() {
135         super();
136     }
137
138     public D2_06_01(ERP1Message packet) {
139         super(packet);
140     }
141
142     protected State getWindowSashState() {
143         Optional<SashState> sashState = SashState.valueOf(bytes[2] & 0x0F);
144         if (sashState.isPresent()) {
145             return new StringType(sashState.get().getTextValue());
146         }
147         return UnDefType.UNDEF;
148     }
149
150     protected State getWindowHandleState() {
151         Optional<HandleState> handleState = HandleState.valueOf(bytes[2] >>> 4);
152         if (handleState.isPresent()) {
153             return new StringType(handleState.get().getTextValue());
154         }
155         return UnDefType.UNDEF;
156     }
157
158     protected State getMotionState() {
159         Optional<MotionState> motionState = MotionState.valueOf(bytes[4] >>> 4);
160         if (motionState.isPresent()) {
161             return OnOffType.from(motionState.get().getTextValue());
162         }
163         return UnDefType.UNDEF;
164     }
165
166     protected State getTemperature() {
167         double unscaledTemp = (double) (bytes[5] & 0xFF);
168         if (unscaledTemp <= 250) {
169             double scaledTemp = unscaledTemp * 0.32 - 20;
170             return new QuantityType<>(scaledTemp, SIUnits.CELSIUS);
171         }
172         return UnDefType.UNDEF;
173     }
174
175     protected State getHumidity() {
176         int unscaledHumidity = bytes[6] & 0xFF;
177         if (unscaledHumidity <= 200) {
178             double scaledHumidity = unscaledHumidity * 0.5;
179             return new DecimalType(scaledHumidity);
180         }
181         return UnDefType.UNDEF;
182     }
183
184     protected State getIllumination() {
185         int illumination = ((bytes[7] & 0xFF) << 8) | (bytes[8] & 0xFF);
186         if (illumination <= 60000) {
187             return new QuantityType<>(illumination, Units.LUX);
188         }
189         return UnDefType.UNDEF;
190     }
191
192     protected State getBatteryLevel() {
193         int unscaledBatteryLevel = ((bytes[9] & 0xFF) >> 3);
194         if (unscaledBatteryLevel <= 20) {
195             return new DecimalType(unscaledBatteryLevel * 5);
196         }
197         return UnDefType.UNDEF;
198     }
199
200     @Override
201     protected @Nullable String convertToEventImpl(String channelId, String channelTypeId, String lastEvent,
202             Configuration config) {
203         // Sensor values
204         if (bytes[0] == MessageType.SENSORVALUES.getIntValue()) {
205             switch (channelId) {
206                 case CHANNEL_WINDOWBREACHEVENT:
207                     if ((bytes[1] >>> 4) == 0x01) {
208                         return "ALARM";
209                     }
210                     break;
211                 case CHANNEL_PROTECTIONPLUSEVENT:
212                     if ((bytes[1] & 0x0F) == 0x01) {
213                         return "ALARM";
214                     }
215                     break;
216                 case CHANNEL_PUSHBUTTON:
217                     int buttonEvent = bytes[3] >>> 4;
218                     switch (buttonEvent) {
219                         case 0x01:
220                             return CommonTriggerEvents.PRESSED;
221                         case 0x02:
222                             return CommonTriggerEvents.RELEASED;
223                     }
224                     break;
225                 case CHANNEL_PUSHBUTTON2:
226                     int buttonEvent2 = bytes[3] & 0x0F;
227                     switch (buttonEvent2) {
228                         case 0x01:
229                             return CommonTriggerEvents.PRESSED;
230                         case 0x02:
231                             return CommonTriggerEvents.RELEASED;
232                     }
233                     break;
234                 case CHANNEL_VACATIONMODETOGGLEEVENT:
235                     int vacationModeToggleEvent = bytes[4] & 0x0F;
236                     switch (vacationModeToggleEvent) {
237                         case 0x01:
238                             return "ACTIVATED";
239                         case 0x02:
240                             return "DEACTIVATED";
241                     }
242                     break;
243             }
244         }
245         return null;
246     }
247
248     @Override
249     public State convertToStateImpl(String channelId, String channelTypeId,
250             Function<String, @Nullable State> getCurrentStateFunc, Configuration config) {
251         // Sensor values
252         if (bytes[0] == MessageType.SENSORVALUES.getIntValue()) {
253             switch (channelId) {
254                 case CHANNEL_WINDOWSASHSTATE:
255                     return getWindowSashState();
256                 case CHANNEL_WINDOWHANDLESTATE:
257                     return getWindowHandleState();
258                 case CHANNEL_MOTIONDETECTION:
259                     return getMotionState();
260                 case CHANNEL_INDOORAIRTEMPERATURE:
261                     return getTemperature();
262                 case CHANNEL_HUMIDITY:
263                     return getHumidity();
264                 case CHANNEL_ILLUMINATION:
265                     return getIllumination();
266                 case CHANNEL_BATTERY_LEVEL:
267                     return getBatteryLevel();
268             }
269         }
270         return UnDefType.UNDEF;
271     }
272 }