]> git.basschouten.com Git - openhab-addons.git/blob
35aef7ba01b6516ba1efae007fd6fec18860ee86
[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 ndct ? ndct.isLabelVisible() : true);
207
208                 capabilities.add(capObj);
209
210                 final JsonObject sensorTypeObj = new JsonObject();
211                 sensorTypeObj.addProperty("type", NeeoCapabilityType.SENSOR_CUSTOM.toString());
212
213                 capabilities.add(createBase(sensorItemName, channel.getLabel(), NeeoCapabilityType.SENSOR.toString(),
214                         compPath + "/textlabel/sensor", sensorTypeObj));
215             } else if (capabilityType == NeeoCapabilityType.DIRECTORY) {
216                 final JsonObject capObj = createBase(uniqueItemName, channel.getLabel(), capabilityType.toString(),
217                         compPath + "/directory/actor");
218
219                 capabilities.add(capObj);
220             } else {
221                 logger.debug("Unknown capability type: {} for channel {}", capabilityType, channel);
222                 continue;
223             }
224
225         }
226         jsonObject.add("capabilities", jsonContext.serialize(capabilities));
227
228         return jsonObject;
229     }
230
231     /**
232      * Helper method to create a base element with the given name/label/type/path
233      *
234      * @param name the element name
235      * @param label the element label
236      * @param type the element type
237      * @param path the element path
238      * @return the json object representing the base element
239      */
240     private JsonObject createBase(String name, String label, String type, String path) {
241         return createBase(name, label, type, path, null, null);
242     }
243
244     /**
245      * Helper method to create a base element with the given name/label/type/path/sensor
246      *
247      * @param name the element name
248      * @param label the element label
249      * @param type the element type
250      * @param path the element path
251      * @param sensor the element sensor
252      * @return the json object representing the base element
253      */
254     private JsonObject createBase(String name, String label, String type, String path, JsonElement sensor) {
255         return createBase(name, label, type, path, "sensor", sensor);
256     }
257
258     /**
259      * Helper method to create a base element with the given name/label/type/path/sensorname/sensor
260      *
261      * @param name the element name
262      * @param label the element label
263      * @param type the element type
264      * @param path the element path
265      * @param sensorName the element sensor name
266      * @param sensor the element sensor
267      * @return the json object representing the base element
268      */
269     private JsonObject createBase(String name, String label, String type, String path, @Nullable String sensorName,
270             @Nullable JsonElement sensor) {
271         final JsonObject compObj = new JsonObject();
272         compObj.addProperty("name", NeeoUtil.encodeURIComponent(name));
273         compObj.addProperty("label", label);
274         compObj.addProperty("type", type);
275
276         compObj.addProperty("path", NeeoUtil.encodeURIComponent(path));
277         if (sensor != null && sensorName != null && !sensorName.isEmpty()) {
278             if (sensor instanceof JsonPrimitive) {
279                 compObj.addProperty(sensorName, sensor.getAsString());
280             } else {
281                 compObj.add(sensorName, sensor);
282             }
283         }
284         return compObj;
285     }
286 }