]> git.basschouten.com Git - openhab-addons.git/blob
5809b62140e4295f5e6963519b8a77a5ccff5df1
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2020 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.io.neeo.internal.serialization;
14
15 import java.lang.reflect.Type;
16 import java.util.ArrayList;
17 import java.util.List;
18 import java.util.Objects;
19
20 import org.apache.commons.lang.StringUtils;
21 import org.eclipse.jdt.annotation.NonNullByDefault;
22 import org.eclipse.jdt.annotation.Nullable;
23 import org.openhab.io.neeo.internal.NeeoConstants;
24 import org.openhab.io.neeo.internal.NeeoUtil;
25 import org.openhab.io.neeo.internal.models.ButtonInfo;
26 import org.openhab.io.neeo.internal.models.NeeoButtonGroup;
27 import org.openhab.io.neeo.internal.models.NeeoCapabilityType;
28 import org.openhab.io.neeo.internal.models.NeeoDevice;
29 import org.openhab.io.neeo.internal.models.NeeoDeviceChannel;
30 import org.openhab.io.neeo.internal.models.NeeoDeviceChannelKind;
31 import org.openhab.io.neeo.internal.models.NeeoDeviceChannelRange;
32 import org.openhab.io.neeo.internal.models.NeeoDeviceChannelText;
33 import org.openhab.io.neeo.internal.models.NeeoDeviceTiming;
34 import org.slf4j.Logger;
35 import org.slf4j.LoggerFactory;
36
37 import com.google.gson.JsonArray;
38 import com.google.gson.JsonElement;
39 import com.google.gson.JsonObject;
40 import com.google.gson.JsonPrimitive;
41 import com.google.gson.JsonSerializationContext;
42 import com.google.gson.JsonSerializer;
43
44 /**
45  * Implementation of {@link JsonSerializer} that will serialize a {@link NeeoDevice} for communications going to the
46  * NEEO Brain
47  *
48  * @author Tim Roberts - Initial Contribution
49  */
50 @NonNullByDefault
51 public class NeeoBrainDeviceSerializer implements JsonSerializer<NeeoDevice> {
52
53     /** The logger */
54     private final Logger logger = LoggerFactory.getLogger(NeeoBrainDeviceSerializer.class);
55
56     @Override
57     public JsonElement serialize(NeeoDevice device, @Nullable Type deviceType,
58             @Nullable JsonSerializationContext jsonContext) {
59         Objects.requireNonNull(device, "device cannot be null");
60         Objects.requireNonNull(deviceType, "deviceType cannot be null");
61         Objects.requireNonNull(jsonContext, "jsonContext cannot be null");
62
63         final JsonObject jsonObject = new JsonObject();
64
65         final String adapterName = device.getUid().getNeeoUID();
66         // jsonObject.addProperty("apiversion", "1.0"); // haven't decided if needed
67         jsonObject.addProperty("adapterName", adapterName);
68         jsonObject.addProperty("driverVersion", device.getDriverVersion());
69
70         jsonObject.addProperty("type", device.getType().toString());
71         jsonObject.addProperty("manufacturer", device.getManufacturer());
72         jsonObject.addProperty("name", device.getName());
73         jsonObject.addProperty("tokens", "");
74
75         final NeeoDeviceTiming timing = device.getDeviceTiming();
76         if (timing != null) {
77             final JsonObject timingObj = new JsonObject();
78             timingObj.addProperty("standbyCommandDelay", timing.getStandbyCommandDelay());
79             timingObj.addProperty("sourceSwitchDelay", timing.getSourceSwitchDelay());
80             timingObj.addProperty("shutdownDelay", timing.getShutdownDelay());
81             jsonObject.add("timing", timingObj);
82         }
83
84         /**
85          * Setup only really good for SDK discovery (which we don't do)
86          * 'setup': { 'discovery': true,'registration': false,'introheader': 'header text','introtext': 'some hints'}
87          */
88         jsonObject.add("setup", new JsonObject());
89
90         jsonObject.add("deviceCapabilities", jsonContext.serialize(device.getDeviceCapabilities()));
91
92         final JsonObject deviceObj = new JsonObject();
93         final String deviceName = device.getName();
94         deviceObj.addProperty("name", deviceName);
95         deviceObj.add("tokens", new JsonArray());
96         jsonObject.add("device", deviceObj);
97
98         final String specificName = device.getSpecificName();
99         if (specificName != null && StringUtils.isNotEmpty(specificName)) {
100             deviceObj.addProperty("specificname", specificName);
101             jsonObject.addProperty("specificname", specificName);
102         } else if (StringUtils.isNotEmpty(deviceName)) {
103             deviceObj.addProperty("specificname", deviceName);
104             jsonObject.addProperty("specificname", deviceName);
105         }
106
107         final String iconName = device.getIconName();
108         if (iconName != null && StringUtils.isNotEmpty(iconName)) {
109             deviceObj.addProperty("icon", iconName);
110             jsonObject.addProperty("icon", iconName);
111         }
112
113         final List<JsonObject> capabilities = new ArrayList<>();
114         for (NeeoDeviceChannel channel : device.getExposedChannels()) {
115             final NeeoCapabilityType capabilityType = channel.getType();
116
117             final String compPath = NeeoConstants.CAPABILITY_PATH_PREFIX + "/" + adapterName + "/"
118                     + channel.getItemName() + "/" + channel.getSubType() + "/" + channel.getChannelNbr();
119
120             final String uniqueItemName = channel.getUniqueItemName();
121             final String sensorItemName = uniqueItemName
122                     + (StringUtils.endsWithIgnoreCase(uniqueItemName, NeeoConstants.NEEO_SENSOR_SUFFIX) ? ""
123                             : NeeoConstants.NEEO_SENSOR_SUFFIX);
124
125             if (capabilityType == NeeoCapabilityType.BUTTON) {
126                 final String name = StringUtils.isEmpty(channel.getLabel()) ? uniqueItemName : channel.getLabel();
127
128                 if (channel.getKind() == NeeoDeviceChannelKind.TRIGGER) {
129                     final String path = compPath + "/button/trigger";
130                     capabilities.add(createBase(name, channel.getLabel(), capabilityType.toString(), path));
131                 } else {
132                     final String value = channel.getValue();
133                     final String path = compPath + "/button/" + (value == null || StringUtils.isEmpty(value) ? "on"
134                             : NeeoUtil.encodeURIComponent(value.trim()));
135                     capabilities.add(createBase(name, channel.getLabel(), capabilityType.toString(), path));
136                 }
137             } else if (capabilityType == NeeoCapabilityType.SENSOR_POWER) {
138                 final JsonObject sensorTypeObj = new JsonObject();
139                 sensorTypeObj.addProperty("type", NeeoCapabilityType.SENSOR_POWER.toString());
140
141                 // power should NOT use the sensor suffix
142                 capabilities.add(createBase(uniqueItemName, channel.getLabel(), NeeoCapabilityType.SENSOR.toString(),
143                         compPath + "/switch/power", sensorTypeObj));
144             } else if (capabilityType == NeeoCapabilityType.SENSOR) {
145                 final JsonObject sensor = new JsonObject();
146                 sensor.addProperty("type", NeeoCapabilityType.SENSOR_RANGE.toString());
147
148                 final NeeoDeviceChannelRange channelRange = channel.getRange();
149                 final int[] range = new int[] { channelRange.getMinValue(), channelRange.getMaxValue() };
150                 sensor.add("range", jsonContext.serialize(range));
151                 sensor.addProperty("unit", channelRange.getUnit());
152
153                 capabilities.add(createBase(sensorItemName, channel.getLabel(), capabilityType.toString(),
154                         compPath + "/sensor/sensor", sensor));
155             } else if (capabilityType == NeeoCapabilityType.SLIDER) {
156                 final JsonObject sliderSensor = new JsonObject();
157                 sliderSensor.addProperty("type", NeeoCapabilityType.SENSOR_RANGE.toString());
158                 sliderSensor.addProperty("sensor", sensorItemName);
159
160                 final NeeoDeviceChannelRange channelRange = channel.getRange();
161                 final int[] range = new int[] { channelRange.getMinValue(), channelRange.getMaxValue() };
162                 sliderSensor.add("range", jsonContext.serialize(range));
163                 sliderSensor.addProperty("unit", channelRange.getUnit());
164                 capabilities.add(createBase(uniqueItemName, channel.getLabel(), capabilityType.toString(),
165                         compPath + "/slider/actor", "slider", sliderSensor));
166
167                 final JsonObject sensorTypeObj = new JsonObject();
168                 sensorTypeObj.addProperty("type", NeeoCapabilityType.SENSOR_RANGE.toString());
169                 sensorTypeObj.add("range", jsonContext.serialize(range));
170                 sensorTypeObj.addProperty("unit", channelRange.getUnit());
171
172                 capabilities.add(createBase(sensorItemName, channel.getLabel(), NeeoCapabilityType.SENSOR.toString(),
173                         compPath + "/slider/sensor", sensorTypeObj));
174             } else if (capabilityType == NeeoCapabilityType.SWITCH) {
175                 final String label = channel.getLabel();
176
177                 final NeeoButtonGroup buttons = NeeoButtonGroup.parse(label);
178                 if (buttons == null) {
179                     capabilities.add(createBase(uniqueItemName, channel.getLabel(), capabilityType.toString(),
180                             compPath + "/switch/actor", new JsonPrimitive(sensorItemName)));
181
182                     final JsonObject sensorTypeObj = new JsonObject();
183                     sensorTypeObj.addProperty("type", NeeoCapabilityType.SENSOR_BINARY.toString());
184
185                     capabilities.add(createBase(sensorItemName, channel.getLabel(),
186                             NeeoCapabilityType.SENSOR.toString(), compPath + "/switch/sensor", sensorTypeObj));
187                 } else {
188                     for (final ButtonInfo bi : buttons.getButtonInfos()) {
189                         capabilities.add(createBase(bi.getLabel(), bi.getLabel(), NeeoCapabilityType.BUTTON.toString(),
190                                 compPath + "/button/" + bi.getSuffix()));
191
192                     }
193                 }
194             } else if (capabilityType == NeeoCapabilityType.IMAGEURL) {
195                 final String value = channel.getValue();
196                 final String size = (value == null || StringUtils.isEmpty(value) ? "large" : value.trim())
197                         .toLowerCase();
198
199                 final JsonObject jo = createBase(uniqueItemName, channel.getLabel(), capabilityType.toString(),
200                         compPath + "/image/actor", "sensor", new JsonPrimitive(sensorItemName));
201                 jo.addProperty("size", size);
202                 capabilities.add(jo);
203
204                 final JsonObject sensorTypeObj = new JsonObject();
205                 sensorTypeObj.addProperty("type", NeeoCapabilityType.IMAGEURL.toString());
206
207                 capabilities.add(createBase(sensorItemName, channel.getLabel(), NeeoCapabilityType.SENSOR.toString(),
208                         compPath + "/image/sensor", sensorTypeObj));
209             } else if (capabilityType == NeeoCapabilityType.TEXTLABEL) {
210                 final JsonObject capObj = createBase(uniqueItemName, channel.getLabel(), capabilityType.toString(),
211                         compPath + "/textlabel/actor", new JsonPrimitive(sensorItemName));
212
213                 capObj.addProperty("isLabelVisible",
214                         channel instanceof NeeoDeviceChannelText ? ((NeeoDeviceChannelText) channel).isLabelVisible()
215                                 : true);
216
217                 capabilities.add(capObj);
218
219                 final JsonObject sensorTypeObj = new JsonObject();
220                 sensorTypeObj.addProperty("type", NeeoCapabilityType.SENSOR_CUSTOM.toString());
221
222                 capabilities.add(createBase(sensorItemName, channel.getLabel(), NeeoCapabilityType.SENSOR.toString(),
223                         compPath + "/textlabel/sensor", sensorTypeObj));
224             } else if (capabilityType == NeeoCapabilityType.DIRECTORY) {
225                 final JsonObject capObj = createBase(uniqueItemName, channel.getLabel(), capabilityType.toString(),
226                         compPath + "/directory/actor");
227
228                 capabilities.add(capObj);
229             } else {
230                 logger.debug("Unknown capability type: {} for channel {}", capabilityType, channel);
231                 continue;
232             }
233
234         }
235         jsonObject.add("capabilities", jsonContext.serialize(capabilities));
236
237         return jsonObject;
238     }
239
240     /**
241      * Helper method to create a base element with the given name/label/type/path
242      *
243      * @param name the element name
244      * @param label the element label
245      * @param type the element type
246      * @param path the element path
247      * @return the json object representing the base element
248      */
249     private JsonObject createBase(String name, String label, String type, String path) {
250         return createBase(name, label, type, path, null, null);
251     }
252
253     /**
254      * Helper method to create a base element with the given name/label/type/path/sensor
255      *
256      * @param name the element name
257      * @param label the element label
258      * @param type the element type
259      * @param path the element path
260      * @param sensor the element sensor
261      * @return the json object representing the base element
262      */
263     private JsonObject createBase(String name, String label, String type, String path, JsonElement sensor) {
264         return createBase(name, label, type, path, "sensor", sensor);
265     }
266
267     /**
268      * Helper method to create a base element with the given name/label/type/path/sensorname/sensor
269      *
270      * @param name the element name
271      * @param label the element label
272      * @param type the element type
273      * @param path the element path
274      * @param sensorName the element sensor name
275      * @param sensor the element sensor
276      * @return the json object representing the base element
277      */
278     private JsonObject createBase(String name, String label, String type, String path, @Nullable String sensorName,
279             @Nullable JsonElement sensor) {
280         final JsonObject compObj = new JsonObject();
281         compObj.addProperty("name", NeeoUtil.encodeURIComponent(name));
282         compObj.addProperty("label", label);
283         compObj.addProperty("type", type);
284
285         compObj.addProperty("path", NeeoUtil.encodeURIComponent(path));
286         if (sensor != null && StringUtils.isNotEmpty(sensorName)) {
287             if (sensor instanceof JsonPrimitive) {
288                 compObj.addProperty(sensorName, sensor.getAsString());
289             } else {
290                 compObj.add(sensorName, sensor);
291             }
292         }
293         return compObj;
294     }
295 }