]> git.basschouten.com Git - openhab-addons.git/blob
d6d363d0184b5a1305bd9056654582f003e83910
[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.smartthings.internal.converter;
14
15 import java.util.Map;
16
17 import org.eclipse.jdt.annotation.NonNullByDefault;
18 import org.eclipse.jdt.annotation.Nullable;
19 import org.openhab.binding.smartthings.internal.dto.SmartthingsStateData;
20 import org.openhab.binding.smartthings.internal.handler.SmartthingsThingConfig;
21 import org.openhab.core.library.types.DateTimeType;
22 import org.openhab.core.library.types.DecimalType;
23 import org.openhab.core.library.types.HSBType;
24 import org.openhab.core.library.types.IncreaseDecreaseType;
25 import org.openhab.core.library.types.NextPreviousType;
26 import org.openhab.core.library.types.OnOffType;
27 import org.openhab.core.library.types.OpenClosedType;
28 import org.openhab.core.library.types.PercentType;
29 import org.openhab.core.library.types.PlayPauseType;
30 import org.openhab.core.library.types.PointType;
31 import org.openhab.core.library.types.RewindFastforwardType;
32 import org.openhab.core.library.types.StopMoveType;
33 import org.openhab.core.library.types.StringListType;
34 import org.openhab.core.library.types.StringType;
35 import org.openhab.core.library.types.UpDownType;
36 import org.openhab.core.thing.ChannelUID;
37 import org.openhab.core.thing.Thing;
38 import org.openhab.core.types.Command;
39 import org.openhab.core.types.RefreshType;
40 import org.openhab.core.types.State;
41 import org.openhab.core.types.UnDefType;
42 import org.slf4j.Logger;
43 import org.slf4j.LoggerFactory;
44
45 /**
46  * Base converter class.
47  * The converter classes are responsible for converting "state" messages from the smartthings hub into openHAB States.
48  * And, converting handler.handleCommand() into messages to be sent to smartthings
49  *
50  * @author Bob Raker - Initial contribution
51  */
52 @NonNullByDefault
53 public abstract class SmartthingsConverter {
54
55     private final Logger logger = LoggerFactory.getLogger(SmartthingsConverter.class);
56
57     protected String smartthingsName;
58     protected String thingTypeId;
59
60     SmartthingsConverter(Thing thing) {
61         smartthingsName = thing.getConfiguration().as(SmartthingsThingConfig.class).smartthingsName;
62         thingTypeId = thing.getThingTypeUID().getId();
63     }
64
65     public abstract String convertToSmartthings(ChannelUID channelUid, Command command);
66
67     public abstract State convertToOpenHab(@Nullable String acceptedChannelType,
68             SmartthingsStateData dataFromSmartthings);
69
70     /**
71      * Provide a default converter in the base call so it can be used in sub-classes if needed
72      *
73      * @param command
74      * @return The json string to send to Smartthings
75      */
76     protected String defaultConvertToSmartthings(ChannelUID channelUid, Command command) {
77         String value;
78
79         if (command instanceof DateTimeType dateTimeCommand) {
80             value = dateTimeCommand.format("%m/%d/%Y %H.%M.%S");
81         } else if (command instanceof HSBType hsbCommand) {
82             value = String.format("[%d, %d, %d ]", hsbCommand.getHue().intValue(),
83                     hsbCommand.getSaturation().intValue(), hsbCommand.getBrightness().intValue());
84         } else if (command instanceof DecimalType) {
85             value = command.toString();
86         } else if (command instanceof IncreaseDecreaseType) { // Need to surround with double quotes
87             value = surroundWithQuotes(command.toString().toLowerCase());
88         } else if (command instanceof NextPreviousType) { // Need to surround with double quotes
89             value = surroundWithQuotes(command.toString().toLowerCase());
90         } else if (command instanceof OnOffType) { // Need to surround with double quotes
91             value = surroundWithQuotes(command.toString().toLowerCase());
92         } else if (command instanceof OpenClosedType) { // Need to surround with double quotes
93             value = surroundWithQuotes(command.toString().toLowerCase());
94         } else if (command instanceof PercentType) {
95             value = command.toString();
96         } else if (command instanceof PointType) { // There is not a comparable type in Smartthings, log and send value
97             logger.warn(
98                     "Warning - PointType Command is not supported by Smartthings. Please configure to use a different command type. CapabilityKey: {}, displayName: {}, capabilityAttribute {}",
99                     thingTypeId, smartthingsName, channelUid.getId());
100             value = command.toFullString();
101         } else if (command instanceof RefreshType) { // Need to surround with double quotes
102             value = surroundWithQuotes(command.toString().toLowerCase());
103         } else if (command instanceof RewindFastforwardType) { // Need to surround with double quotes
104             value = surroundWithQuotes(command.toString().toLowerCase());
105         } else if (command instanceof StopMoveType) { // Need to surround with double quotes
106             value = surroundWithQuotes(command.toString().toLowerCase());
107         } else if (command instanceof PlayPauseType) { // Need to surround with double quotes
108             value = surroundWithQuotes(command.toString().toLowerCase());
109         } else if (command instanceof StringListType) {
110             value = surroundWithQuotes(command.toString());
111         } else if (command instanceof StringType) {
112             value = surroundWithQuotes(command.toString());
113         } else if (command instanceof UpDownType) { // Need to surround with double quotes
114             value = surroundWithQuotes(command.toString().toLowerCase());
115         } else {
116             logger.warn(
117                     "Warning - The Smartthings converter does not know how to handle the {} command. The Smartthingsonverter class should be updated.  CapabilityKey: {}, displayName: {}, capabilityAttribute {}",
118                     command.getClass().getName(), thingTypeId, smartthingsName, channelUid.getId());
119             value = command.toString().toLowerCase();
120         }
121
122         return String.format(
123                 "{\"capabilityKey\": \"%s\", \"deviceDisplayName\": \"%s\", \"capabilityAttribute\": \"%s\", \"value\": %s}",
124                 thingTypeId, smartthingsName, channelUid.getId(), value);
125     }
126
127     protected String surroundWithQuotes(String param) {
128         return (new StringBuilder()).append('"').append(param).append('"').toString();
129     }
130
131     protected State defaultConvertToOpenHab(@Nullable String acceptedChannelType,
132             SmartthingsStateData dataFromSmartthings) {
133         // If there is no stateMap the just return null State
134         if (acceptedChannelType == null) {
135             return UnDefType.NULL;
136         }
137
138         String deviceType = dataFromSmartthings.capabilityAttribute;
139         Object deviceValue = dataFromSmartthings.value;
140
141         // deviceValue can be null, handle that up front
142         if (deviceValue == null) {
143             return UnDefType.NULL;
144         }
145
146         switch (acceptedChannelType) {
147             case "Color":
148                 logger.warn(
149                         "Conversion of Color is not supported by the default Smartthings to opemHAB converter. The ThingType should specify an appropriate converter. Device name: {}, Attribute: {}.",
150                         dataFromSmartthings.deviceDisplayName, deviceType);
151                 return UnDefType.UNDEF;
152             case "Contact":
153                 return "open".equals(deviceValue) ? OpenClosedType.OPEN : OpenClosedType.CLOSED;
154             case "DateTime":
155                 return UnDefType.UNDEF;
156             case "Dimmer":
157                 // The value coming in should be a number
158                 if (deviceValue instanceof String stringCommand) {
159                     return new PercentType(stringCommand);
160                 } else {
161                     logger.warn("Failed to convert {} with a value of {} from class {} to an appropriate type.",
162                             deviceType, deviceValue, deviceValue.getClass().getName());
163                     return UnDefType.UNDEF;
164                 }
165             case "Number":
166                 if (deviceValue instanceof String stringCommand2) {
167                     return new DecimalType(Double.parseDouble(stringCommand2));
168                 } else if (deviceValue instanceof Double) {
169                     return new DecimalType((Double) deviceValue);
170                 } else if (deviceValue instanceof Long) {
171                     return new DecimalType((Long) deviceValue);
172                 } else {
173                     logger.warn("Failed to convert Number {} with a value of {} from class {} to an appropriate type.",
174                             deviceType, deviceValue, deviceValue.getClass().getName());
175                     return UnDefType.UNDEF;
176                 }
177             case "Player":
178                 logger.warn("Conversion of Player is not currently supported. Need to provide support for message {}.",
179                         deviceValue);
180                 return UnDefType.UNDEF;
181             case "Rollershutter":
182                 return "open".equals(deviceValue) ? UpDownType.DOWN : UpDownType.UP;
183             case "String":
184                 return new StringType((String) deviceValue);
185             case "Switch":
186                 return "on".equals(deviceValue) ? OnOffType.ON : OnOffType.OFF;
187
188             // Vector3 can't be triggered now but keep it to handle acceleration device
189             case "Vector3":
190                 // This is a weird result from Smartthings. If the messages is from a "state" request the result will
191                 // look like: "value":{"z":22,"y":-36,"x":-987}
192                 // But if the result is from sensor change via a subscription to a threeAxis device the results will
193                 // be a String of the format "value":"-873,-70,484"
194                 // which GSON returns as a LinkedTreeMap
195                 if (deviceValue instanceof String stringCommand3) {
196                     return new StringType(stringCommand3);
197                 } else if (deviceValue instanceof Map<?, ?>) {
198                     Map<String, String> map = (Map<String, String>) deviceValue;
199                     String s = String.format("%.0f,%.0f,%.0f", map.get("x"), map.get("y"), map.get("z"));
200                     return new StringType(s);
201                 } else {
202                     logger.warn(
203                             "Unable to convert {} which should be in Smartthings Vector3 format to a string. The returned datatype from Smartthings is {}.",
204                             deviceType, deviceValue.getClass().getName());
205                     return UnDefType.UNDEF;
206                 }
207             default:
208                 logger.warn("No type defined to convert {} with a value of {} from class {} to an appropriate type.",
209                         deviceType, deviceValue, deviceValue.getClass().getName());
210                 return UnDefType.UNDEF;
211         }
212     }
213 }