2 * Copyright (c) 2010-2021 Contributors to the openHAB project
4 * See the NOTICE file(s) distributed with this work for additional
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
11 * SPDX-License-Identifier: EPL-2.0
13 package org.openhab.binding.shelly.internal.util;
15 import static org.openhab.binding.shelly.internal.ShellyBindingConstants.*;
17 import java.io.UnsupportedEncodingException;
18 import java.math.BigDecimal;
19 import java.net.URLEncoder;
20 import java.nio.charset.StandardCharsets;
21 import java.time.DateTimeException;
22 import java.time.Instant;
23 import java.time.LocalDateTime;
24 import java.time.ZoneId;
25 import java.time.ZonedDateTime;
27 import javax.measure.Unit;
29 import org.eclipse.jdt.annotation.NonNullByDefault;
30 import org.eclipse.jdt.annotation.Nullable;
31 import org.openhab.binding.shelly.internal.api.ShellyApiException;
32 import org.openhab.binding.shelly.internal.api.ShellyDeviceProfile;
33 import org.openhab.core.library.types.DateTimeType;
34 import org.openhab.core.library.types.DecimalType;
35 import org.openhab.core.library.types.OnOffType;
36 import org.openhab.core.library.types.PercentType;
37 import org.openhab.core.library.types.QuantityType;
38 import org.openhab.core.library.types.StringType;
39 import org.openhab.core.types.Command;
40 import org.openhab.core.types.State;
41 import org.openhab.core.types.UnDefType;
44 * {@link ShellyUtils} provides general utility functions
46 * @author Markus Michels - Initial contribution
49 public class ShellyUtils {
50 public static String mkChannelId(String group, String channel) {
51 return group + "#" + channel;
54 public static String getString(@Nullable String value) {
55 return value != null ? value : "";
58 public static String substringBefore(@Nullable String string, String pattern) {
60 int pos = string.indexOf(pattern);
62 return string.substring(0, pos);
68 public static String substringBeforeLast(@Nullable String string, String pattern) {
70 int pos = string.lastIndexOf(pattern);
72 return string.substring(0, pos);
78 public static String substringAfter(@Nullable String string, String pattern) {
80 int pos = string.indexOf(pattern);
82 return string.substring(pos + pattern.length());
88 public static String substringAfterLast(@Nullable String string, String pattern) {
90 int pos = string.lastIndexOf(pattern);
92 return string.substring(pos + pattern.length());
98 public static String substringBetween(@Nullable String string, String begin, String end) {
100 int s = string.indexOf(begin);
102 // The end tag might be included before the start tag, e.g.
103 // when using "http://" and ":" to get the IP from http://192.168.1.1:8081/xxx
104 // therefore make it 2 steps
105 String result = string.substring(s + begin.length());
106 return substringBefore(result, end);
112 public static String getMessage(Exception e) {
113 String message = e.getMessage();
114 return message != null ? message : "";
117 public static Integer getInteger(@Nullable Integer value) {
118 return (value != null ? (Integer) value : 0);
121 public static Long getLong(@Nullable Long value) {
122 return (value != null ? (Long) value : 0);
125 public static Double getDouble(@Nullable Double value) {
126 return (value != null ? (Double) value : 0);
129 public static Boolean getBool(@Nullable Boolean value) {
130 return (value != null ? (Boolean) value : false);
135 public static StringType getStringType(@Nullable String value) {
136 return new StringType(value != null ? value : "");
139 public static DecimalType getDecimal(@Nullable Double value) {
140 return new DecimalType((value != null ? value : 0));
143 public static DecimalType getDecimal(@Nullable Integer value) {
144 return new DecimalType((value != null ? value : 0));
147 public static DecimalType getDecimal(@Nullable Long value) {
148 return new DecimalType((value != null ? value : 0));
151 public static Double getNumber(Command command) throws IllegalArgumentException {
152 if (command instanceof DecimalType) {
153 return ((DecimalType) command).doubleValue();
155 if (command instanceof QuantityType) {
156 return ((QuantityType<?>) command).doubleValue();
158 throw new IllegalArgumentException("Unable to convert number");
161 public static OnOffType getOnOff(@Nullable Boolean value) {
162 return (value != null ? value ? OnOffType.ON : OnOffType.OFF : OnOffType.OFF);
165 public static OnOffType getOnOff(int value) {
166 return value == 0 ? OnOffType.OFF : OnOffType.ON;
169 public static State toQuantityType(@Nullable Double value, int digits, Unit<?> unit) {
171 return UnDefType.NULL;
173 BigDecimal bd = new BigDecimal(value.doubleValue());
174 return toQuantityType(bd.setScale(digits, BigDecimal.ROUND_HALF_UP), unit);
177 public static State toQuantityType(@Nullable Number value, Unit<?> unit) {
178 return value == null ? UnDefType.NULL : new QuantityType<>(value, unit);
181 public static State toQuantityType(@Nullable PercentType value, Unit<?> unit) {
182 return value == null ? UnDefType.NULL : toQuantityType(value.toBigDecimal(), unit);
185 public static void validateRange(String name, Integer value, int min, int max) {
186 if ((value < min) || (value > max)) {
187 throw new IllegalArgumentException("Value " + name + " is out of range (" + min + "-" + max + ")");
191 public static String urlEncode(String input) throws ShellyApiException {
193 return URLEncoder.encode(input, StandardCharsets.UTF_8.toString());
194 } catch (UnsupportedEncodingException e) {
195 throw new ShellyApiException(
196 "Unsupported encoding format: " + StandardCharsets.UTF_8.toString() + ", input=" + input, e);
200 public static Long now() {
201 return System.currentTimeMillis() / 1000L;
204 public static DateTimeType getTimestamp() {
205 return new DateTimeType(ZonedDateTime.ofInstant(Instant.ofEpochSecond(now()), ZoneId.systemDefault()));
208 public static DateTimeType getTimestamp(String zone, long timestamp) {
210 if (timestamp == 0) {
211 return getTimestamp();
213 ZoneId zoneId = !zone.isEmpty() ? ZoneId.of(zone) : ZoneId.systemDefault();
214 ZonedDateTime zdt = LocalDateTime.now().atZone(zoneId);
215 int delta = zdt.getOffset().getTotalSeconds();
216 return new DateTimeType(ZonedDateTime.ofInstant(Instant.ofEpochSecond(timestamp - delta), zoneId));
217 } catch (DateTimeException e) {
218 // Unable to convert device's timezone, use system one
219 return getTimestamp();
223 public static Integer getLightIdFromGroup(String groupName) {
224 if (groupName.startsWith(CHANNEL_GROUP_LIGHT_CHANNEL)) {
225 return Integer.parseInt(substringAfter(groupName, CHANNEL_GROUP_LIGHT_CHANNEL)) - 1;
227 return 0; // only 1 light, e.g. bulb or rgbw2 in color mode
230 public static String buildControlGroupName(ShellyDeviceProfile profile, Integer channelId) {
231 return profile.isBulb || profile.isDuo || profile.inColor ? CHANNEL_GROUP_LIGHT_CONTROL
232 : CHANNEL_GROUP_LIGHT_CHANNEL + channelId.toString();
235 public static String buildWhiteGroupName(ShellyDeviceProfile profile, Integer channelId) {
236 return profile.isBulb || profile.isDuo && !profile.inColor ? CHANNEL_GROUP_WHITE_CONTROL
237 : CHANNEL_GROUP_LIGHT_CHANNEL + channelId.toString();
240 public static DecimalType mapSignalStrength(int dbm) {
244 } else if (dbm > -70) {
246 } else if (dbm > -80) {
248 } else if (dbm > -90) {
253 return new DecimalType(strength);