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