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