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