]> git.basschouten.com Git - openhab-addons.git/blob
c7c043860f7154e1f288053e76294fbce5b9d2ca
[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.core.items.Item;
22 import org.openhab.core.items.ItemNotFoundException;
23 import org.openhab.core.thing.Channel;
24 import org.openhab.core.thing.ChannelUID;
25 import org.openhab.core.thing.type.ChannelType;
26 import org.openhab.core.types.Command;
27 import org.openhab.io.neeo.internal.NeeoUtil;
28 import org.openhab.io.neeo.internal.ServiceContext;
29 import org.openhab.io.neeo.internal.models.ItemSubType;
30 import org.openhab.io.neeo.internal.models.NeeoCapabilityType;
31 import org.openhab.io.neeo.internal.models.NeeoDeviceChannel;
32 import org.openhab.io.neeo.internal.models.NeeoDeviceChannelDirectory;
33 import org.openhab.io.neeo.internal.models.NeeoDeviceChannelDirectoryListItem;
34 import org.openhab.io.neeo.internal.models.NeeoDeviceChannelKind;
35 import org.openhab.io.neeo.internal.models.NeeoDeviceChannelRange;
36 import org.openhab.io.neeo.internal.models.NeeoDeviceChannelText;
37
38 import com.google.gson.JsonDeserializationContext;
39 import com.google.gson.JsonDeserializer;
40 import com.google.gson.JsonElement;
41 import com.google.gson.JsonObject;
42 import com.google.gson.JsonParseException;
43 import com.google.gson.JsonSerializationContext;
44 import com.google.gson.JsonSerializer;
45
46 /**
47  * Implementation of {@link JsonSerializer} and {@link JsonDeserializer} to serialize/deserial
48  * {@link NeeoDeviceChannel}
49  *
50  * @author Tim Roberts - Initial Contribution
51  */
52 @NonNullByDefault
53 public class NeeoDeviceChannelSerializer
54         implements JsonSerializer<NeeoDeviceChannel>, JsonDeserializer<NeeoDeviceChannel> {
55
56     /** The service context */
57     @Nullable
58     private final ServiceContext context;
59
60     /**
61      * Creates the serializer with no context
62      */
63     public NeeoDeviceChannelSerializer() {
64         this(null);
65     }
66
67     /**
68      * Creates the serializer using the given context. A null context will suppress certain values on the returned
69      * object
70      *
71      * @param context the possibly null context
72      */
73     public NeeoDeviceChannelSerializer(@Nullable ServiceContext context) {
74         this.context = context;
75     }
76
77     @Override
78     public JsonElement serialize(NeeoDeviceChannel chnl, Type type, JsonSerializationContext jsonContext) {
79         final JsonObject jo = new JsonObject();
80
81         jo.add("kind", jsonContext.serialize(chnl.getKind()));
82         jo.addProperty("itemName", chnl.getItemName());
83         jo.addProperty("label", chnl.getLabel());
84         jo.addProperty("value", chnl.getValue());
85         jo.addProperty("channelNbr", chnl.getChannelNbr());
86         jo.add("type", jsonContext.serialize(chnl.getType()));
87         jo.add("subType", jsonContext.serialize(chnl.getSubType()));
88         jo.add("range", jsonContext.serialize(chnl.getRange()));
89
90         final ServiceContext localContext = context;
91         if (localContext != null) {
92             final List<String> commandTypes = new ArrayList<>();
93             boolean isReadOnly = false;
94             String itemLabel = chnl.getLabel();
95             String itemType = null;
96
97             try {
98                 final Item item = localContext.getItemRegistry().getItem(chnl.getItemName());
99                 itemType = item.getType();
100
101                 String label = item.getLabel();
102                 if (label != null && !label.isEmpty()) {
103                     itemLabel = label;
104                 }
105
106                 for (Class<? extends Command> cmd : item.getAcceptedCommandTypes()) {
107                     if (!cmd.getSimpleName().equalsIgnoreCase("refreshtype")) {
108                         commandTypes.add(cmd.getSimpleName().toLowerCase());
109                     }
110                 }
111
112                 for (ChannelUID channelUid : localContext.getItemChannelLinkRegistry()
113                         .getBoundChannels(chnl.getItemName())) {
114                     if (channelUid != null) {
115                         jo.addProperty("groupId", channelUid.getGroupId());
116                         final Channel channel = localContext.getThingRegistry().getChannel(channelUid);
117                         if (channel != null) {
118                             final ChannelType channelType = localContext.getChannelTypeRegistry()
119                                     .getChannelType(channel.getChannelTypeUID());
120                             if (channelType != null && channelType.getState() != null) {
121                                 isReadOnly = channelType.getState().isReadOnly();
122                             }
123                         }
124                     }
125                 }
126             } catch (ItemNotFoundException e) {
127                 itemType = "N/A";
128             }
129
130             if (!itemLabel.isEmpty()) {
131                 switch (chnl.getSubType()) {
132                     case HUE:
133                         itemType += " (Hue)";
134                         break;
135
136                     case SATURATION:
137                         itemType += " (Sat)";
138                         break;
139
140                     case BRIGHTNESS:
141                         itemType += " (Bri)";
142                         break;
143
144                     default:
145                         break;
146                 }
147             }
148
149             jo.addProperty("itemType", itemType);
150             jo.addProperty("itemLabel", itemLabel);
151             jo.add("acceptedCommandTypes", jsonContext.serialize(commandTypes));
152             jo.addProperty("isReadOnly", isReadOnly);
153
154         }
155
156         if (chnl instanceof NeeoDeviceChannelText) {
157             jo.addProperty("labelVisible", ((NeeoDeviceChannelText) chnl).isLabelVisible());
158         } else if (chnl instanceof NeeoDeviceChannelDirectory) {
159             jo.add("listItems", jsonContext.serialize(((NeeoDeviceChannelDirectory) chnl).getListItems()));
160         }
161
162         return jo;
163     }
164
165     @Override
166     public @Nullable NeeoDeviceChannel deserialize(JsonElement elm, Type type, JsonDeserializationContext context)
167             throws JsonParseException {
168         if (!(elm instanceof JsonObject)) {
169             throw new JsonParseException("Element not an instance of JsonObject: " + elm);
170         }
171
172         final JsonObject jo = (JsonObject) elm;
173         final String itemName = NeeoUtil.getString(jo, "itemName");
174
175         if (itemName == null || itemName.isEmpty()) {
176             throw new JsonParseException("Element requires an itemName attribute: " + elm);
177         }
178
179         final ItemSubType itemSubType = jo.has("subType") ? context.deserialize(jo.get("subType"), ItemSubType.class)
180                 : ItemSubType.NONE;
181
182         final String label = NeeoUtil.getString(jo, "label");
183         final String value = NeeoUtil.getString(jo, "value");
184         final Integer channelNbr = NeeoUtil.getInt(jo, "channelNbr");
185
186         if (channelNbr == null) {
187             throw new JsonParseException("Channel Number is not a valid integer");
188         }
189         final NeeoCapabilityType capType = context.deserialize(jo.get("type"), NeeoCapabilityType.class);
190
191         final NeeoDeviceChannelRange range = jo.has("range")
192                 ? context.deserialize(jo.get("range"), NeeoDeviceChannelRange.class)
193                 : null;
194
195         final NeeoDeviceChannelKind kind = jo.has("kind")
196                 ? context.deserialize(jo.get("kind"), NeeoDeviceChannelKind.class)
197                 : NeeoDeviceChannelKind.ITEM;
198
199         try {
200             if (capType == NeeoCapabilityType.TEXTLABEL) {
201                 final boolean labelVisible = jo.has("labelVisible") ? jo.get("labelVisible").getAsBoolean() : true;
202
203                 return new NeeoDeviceChannelText(kind, itemName, channelNbr, capType, itemSubType,
204                         label == null || label.isEmpty() ? NeeoUtil.NOTAVAILABLE : label, value, range, labelVisible);
205             } else if (capType == NeeoCapabilityType.DIRECTORY) {
206                 final NeeoDeviceChannelDirectoryListItem[] listItems = jo.has("listItems")
207                         ? context.deserialize(jo.get("listItems"), NeeoDeviceChannelDirectoryListItem[].class)
208                         : new NeeoDeviceChannelDirectoryListItem[0];
209
210                 return new NeeoDeviceChannelDirectory(kind, itemName, channelNbr, capType, itemSubType,
211                         label == null || label.isEmpty() ? NeeoUtil.NOTAVAILABLE : label, value, range, listItems);
212             } else {
213                 return new NeeoDeviceChannel(kind, itemName, channelNbr, capType, itemSubType,
214                         label == null || label.isEmpty() ? NeeoUtil.NOTAVAILABLE : label, value, range);
215             }
216         } catch (NullPointerException | IllegalArgumentException e) {
217             throw new JsonParseException(e);
218         }
219     }
220 }