]> git.basschouten.com Git - openhab-addons.git/blob
36b6a605e7f5ac1a19109fa81e2d7e4a6572effd
[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.shelly.internal.util;
14
15 import static org.openhab.binding.shelly.internal.ShellyBindingConstants.*;
16
17 import java.io.UnsupportedEncodingException;
18 import java.math.BigDecimal;
19 import java.math.RoundingMode;
20 import java.net.URLEncoder;
21 import java.nio.charset.StandardCharsets;
22 import java.time.DateTimeException;
23 import java.time.Instant;
24 import java.time.LocalDateTime;
25 import java.time.ZoneId;
26 import java.time.ZonedDateTime;
27
28 import javax.measure.Unit;
29
30 import org.eclipse.jdt.annotation.NonNullByDefault;
31 import org.eclipse.jdt.annotation.Nullable;
32 import org.openhab.binding.shelly.internal.api.ShellyApiException;
33 import org.openhab.binding.shelly.internal.api.ShellyDeviceProfile;
34 import org.openhab.core.library.types.DateTimeType;
35 import org.openhab.core.library.types.DecimalType;
36 import org.openhab.core.library.types.OnOffType;
37 import org.openhab.core.library.types.PercentType;
38 import org.openhab.core.library.types.QuantityType;
39 import org.openhab.core.library.types.StringType;
40 import org.openhab.core.types.Command;
41 import org.openhab.core.types.State;
42 import org.openhab.core.types.UnDefType;
43
44 import com.google.gson.Gson;
45 import com.google.gson.JsonSyntaxException;
46 import com.google.gson.internal.Primitives;
47
48 /**
49  * {@link ShellyUtils} provides general utility functions
50  *
51  * @author Markus Michels - Initial contribution
52  */
53 @NonNullByDefault
54 public class ShellyUtils {
55     private final static String PRE = "Unable to create object of type ";
56
57     public static <T> T fromJson(Gson gson, @Nullable String json, Class<T> classOfT) throws ShellyApiException {
58         @Nullable
59         T o = fromJson(gson, json, classOfT, true);
60         if (o == null) {
61             throw new ShellyApiException("Unable to create JSON object");
62         }
63         return o;
64     }
65
66     public static @Nullable <T> T fromJson(Gson gson, @Nullable String json, Class<T> classOfT, boolean exceptionOnNull)
67             throws ShellyApiException {
68         String className = substringAfter(classOfT.getName(), "$");
69
70         if (json == null) {
71             if (exceptionOnNull) {
72                 throw new IllegalArgumentException(PRE + className + ": json is null!");
73             } else {
74                 return null;
75             }
76         }
77
78         if (classOfT.isInstance(json)) {
79             return Primitives.wrap(classOfT).cast(json);
80         } else if (json.isEmpty()) { // update GSON might return null
81             throw new ShellyApiException(PRE + className + "from empty JSON");
82         } else {
83             try {
84                 @Nullable
85                 T obj = gson.fromJson(json, classOfT);
86                 if ((obj == null) && exceptionOnNull) { // new in OH3: fromJson may return null
87                     throw new ShellyApiException(PRE + className + "from JSON: " + json);
88                 }
89                 return obj;
90             } catch (JsonSyntaxException e) {
91                 throw new ShellyApiException(PRE + className + "from JSON (syntax/format error): " + json, e);
92             } catch (RuntimeException e) {
93                 throw new ShellyApiException(PRE + className + "from JSON: " + json, e);
94             }
95         }
96     }
97
98     public static String mkChannelId(String group, String channel) {
99         return group + "#" + channel;
100     }
101
102     public static String getString(@Nullable String value) {
103         return value != null ? value : "";
104     }
105
106     public static String substringBefore(@Nullable String string, String pattern) {
107         if (string != null) {
108             int pos = string.indexOf(pattern);
109             if (pos > 0) {
110                 return string.substring(0, pos);
111             }
112         }
113         return "";
114     }
115
116     public static String substringBeforeLast(@Nullable String string, String pattern) {
117         if (string != null) {
118             int pos = string.lastIndexOf(pattern);
119             if (pos > 0) {
120                 return string.substring(0, pos);
121             }
122         }
123         return "";
124     }
125
126     public static String substringAfter(@Nullable String string, String pattern) {
127         if (string != null) {
128             int pos = string.indexOf(pattern);
129             if (pos != -1) {
130                 return string.substring(pos + pattern.length());
131             }
132         }
133         return "";
134     }
135
136     public static String substringAfterLast(@Nullable String string, String pattern) {
137         if (string == null) {
138             return "";
139         }
140         int pos = string.lastIndexOf(pattern);
141         if (pos != -1) {
142             return string.substring(pos + pattern.length());
143         }
144         return string;
145     }
146
147     public static String substringBetween(@Nullable String string, String begin, String end) {
148         if (string != null) {
149             int s = string.indexOf(begin);
150             if (s != -1) {
151                 // The end tag might be included before the start tag, e.g.
152                 // when using "http://" and ":" to get the IP from http://192.168.1.1:8081/xxx
153                 // therefore make it 2 steps
154                 String result = string.substring(s + begin.length());
155                 return substringBefore(result, end);
156             }
157         }
158         return "";
159     }
160
161     public static String getMessage(Exception e) {
162         String message = e.getMessage();
163         return message != null ? message : "";
164     }
165
166     public static Integer getInteger(@Nullable Integer value) {
167         return (value != null ? (Integer) value : 0);
168     }
169
170     public static Long getLong(@Nullable Long value) {
171         return (value != null ? (Long) value : 0);
172     }
173
174     public static Double getDouble(@Nullable Double value) {
175         return (value != null ? (Double) value : 0);
176     }
177
178     public static Boolean getBool(@Nullable Boolean value) {
179         return (value != null ? (Boolean) value : false);
180     }
181
182     // as State
183
184     public static StringType getStringType(@Nullable String value) {
185         return new StringType(value != null ? value : "");
186     }
187
188     public static DecimalType getDecimal(@Nullable Double value) {
189         return new DecimalType((value != null ? value : 0));
190     }
191
192     public static DecimalType getDecimal(@Nullable Integer value) {
193         return new DecimalType((value != null ? value : 0));
194     }
195
196     public static DecimalType getDecimal(@Nullable Long value) {
197         return new DecimalType((value != null ? value : 0));
198     }
199
200     public static Double getNumber(Command command) throws IllegalArgumentException {
201         if (command instanceof DecimalType) {
202             return ((DecimalType) command).doubleValue();
203         }
204         if (command instanceof QuantityType) {
205             return ((QuantityType<?>) command).doubleValue();
206         }
207         throw new IllegalArgumentException("Unable to convert number");
208     }
209
210     public static OnOffType getOnOff(@Nullable Boolean value) {
211         return (value != null ? value ? OnOffType.ON : OnOffType.OFF : OnOffType.OFF);
212     }
213
214     public static OnOffType getOnOff(int value) {
215         return value == 0 ? OnOffType.OFF : OnOffType.ON;
216     }
217
218     public static State toQuantityType(@Nullable Double value, int digits, Unit<?> unit) {
219         if (value == null) {
220             return UnDefType.NULL;
221         }
222         BigDecimal bd = new BigDecimal(value.doubleValue());
223         return toQuantityType(bd.setScale(digits, RoundingMode.HALF_UP), unit);
224     }
225
226     public static State toQuantityType(@Nullable Number value, Unit<?> unit) {
227         return value == null ? UnDefType.NULL : new QuantityType<>(value, unit);
228     }
229
230     public static State toQuantityType(@Nullable PercentType value, Unit<?> unit) {
231         return value == null ? UnDefType.NULL : toQuantityType(value.toBigDecimal(), unit);
232     }
233
234     public static void validateRange(String name, Integer value, int min, int max) {
235         if ((value < min) || (value > max)) {
236             throw new IllegalArgumentException("Value " + name + " is out of range (" + min + "-" + max + ")");
237         }
238     }
239
240     public static String urlEncode(String input) {
241         try {
242             return URLEncoder.encode(input, StandardCharsets.UTF_8.toString());
243         } catch (UnsupportedEncodingException e) {
244             return input;
245         }
246     }
247
248     public static Long now() {
249         return System.currentTimeMillis() / 1000L;
250     }
251
252     public static DateTimeType getTimestamp() {
253         return new DateTimeType(ZonedDateTime.ofInstant(Instant.ofEpochSecond(now()), ZoneId.systemDefault()));
254     }
255
256     public static DateTimeType getTimestamp(String zone, long timestamp) {
257         try {
258             if (timestamp == 0) {
259                 return getTimestamp();
260             }
261             ZoneId zoneId = !zone.isEmpty() ? ZoneId.of(zone) : ZoneId.systemDefault();
262             ZonedDateTime zdt = LocalDateTime.now().atZone(zoneId);
263             int delta = zdt.getOffset().getTotalSeconds();
264             return new DateTimeType(ZonedDateTime.ofInstant(Instant.ofEpochSecond(timestamp - delta), zoneId));
265         } catch (DateTimeException e) {
266             // Unable to convert device's timezone, use system one
267             return getTimestamp();
268         }
269     }
270
271     public static Integer getLightIdFromGroup(String groupName) {
272         if (groupName.startsWith(CHANNEL_GROUP_LIGHT_CHANNEL)) {
273             return Integer.parseInt(substringAfter(groupName, CHANNEL_GROUP_LIGHT_CHANNEL)) - 1;
274         }
275         return 0; // only 1 light, e.g. bulb or rgbw2 in color mode
276     }
277
278     public static String buildControlGroupName(ShellyDeviceProfile profile, Integer channelId) {
279         return profile.isBulb || profile.isDuo || profile.inColor ? CHANNEL_GROUP_LIGHT_CONTROL
280                 : CHANNEL_GROUP_LIGHT_CHANNEL + channelId.toString();
281     }
282
283     public static String buildWhiteGroupName(ShellyDeviceProfile profile, Integer channelId) {
284         return profile.isBulb || profile.isDuo ? CHANNEL_GROUP_WHITE_CONTROL
285                 : CHANNEL_GROUP_LIGHT_CHANNEL + channelId.toString();
286     }
287
288     public static DecimalType mapSignalStrength(int dbm) {
289         int strength = -1;
290         if (dbm > -60) {
291             strength = 4;
292         } else if (dbm > -70) {
293             strength = 3;
294         } else if (dbm > -80) {
295             strength = 2;
296         } else if (dbm > -90) {
297             strength = 1;
298         } else {
299             strength = 0;
300         }
301         return new DecimalType(strength);
302     }
303 }