2 * Copyright (c) 2010-2021 Contributors to the openHAB project
4 * See the NOTICE file(s) distributed with this work for additional
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
11 * SPDX-License-Identifier: EPL-2.0
13 package org.openhab.binding.shelly.internal.coap;
15 import java.io.IOException;
16 import java.util.ArrayList;
17 import java.util.List;
19 import com.google.gson.TypeAdapter;
20 import com.google.gson.annotations.SerializedName;
21 import com.google.gson.stream.JsonReader;
22 import com.google.gson.stream.JsonToken;
23 import com.google.gson.stream.JsonWriter;
26 * The {@link ShellyCoapJSonDTO} helps the CoIoT Json into Java objects
28 * @author Markus Michels - Initial contribution
30 public class ShellyCoapJSonDTO {
32 public static final int COIOT_VERSION_1 = 1;
33 public static final int COIOT_VERSION_2 = 2;
35 public static final int COIOT_PORT = 5683;
36 public static final String COAP_MULTICAST_ADDRESS = "224.0.1.187";
38 public static final String COLOIT_URI_BASE = "/cit/";
39 public static final String COLOIT_URI_DEVDESC = COLOIT_URI_BASE + "d";
40 public static final String COLOIT_URI_DEVSTATUS = COLOIT_URI_BASE + "s";
42 public static final int COIOT_OPTION_GLOBAL_DEVID = 3332;
43 public static final int COIOT_OPTION_STATUS_VALIDITY = 3412;
44 public static final int COIOT_OPTION_STATUS_SERIAL = 3420;
46 public static final String COIOT_TAG_BLK = "blk";
47 public static final String COIOT_TAG_SEN = "sen";
48 public static final String COIOT_TAG_ACT = "act";
49 public static final String COIOT_TAG_GENERIC = "G";
51 public static class CoIotDescrBlk {
55 String desc; // Description
57 // Sometimes sen entries are part of the blk array - not conforming the Spec!
59 public String type; // Type
61 public String range; // Range
63 public String links; // Links
66 public static class CoIotDescrSen {
70 String desc = ""; // Description
72 public String type; // Type
74 public String range; // Range
76 public String links; // Links
78 public String unit; // Unit
81 public static class CoIotDescrP {
85 String desc; // Description
87 public String range; // Range
90 public static class CoIotDescrAct {
94 String desc; // Description
96 public String links; // Links
98 public List<CoIotDescrP> pTag; // ?
101 public static class CoIotDevDescription {
102 public List<CoIotDescrBlk> blk;
103 public List<CoIotDescrSen> sen;
104 // public List<CoIotDescrAct> act;
106 public CoIotDevDescription() {
107 blk = new ArrayList<>();
108 sen = new ArrayList<>();
112 public static class CoIotSensor {
113 @SerializedName("index")
114 public String id; // id
115 public double value; // value
116 public String valueStr; // value
117 public List<Object> valueArray;
120 public static class CoIotGenericSensorList {
122 public List<CoIotSensor> generic;
124 public CoIotGenericSensorList() {
125 generic = new ArrayList<>();
129 protected static class CoIotDevDescrTypeAdapter extends TypeAdapter<CoIotDevDescription> {
131 public CoIotDevDescription read(final JsonReader in) throws IOException {
132 CoIotDevDescription descr = new CoIotDevDescription();
137 * { "I": 0, "D": "Relay0"},
138 * { "I": 1, "D": "Sensors"} ],
140 * { "I": 111, "T": "P", "D": "Power","R": "0/3500","L": 0},
141 * { "I": 112,"T": "S","D": "Switch","R": "0/1","L": 0}
145 String name = in.nextName();
146 if (name.equalsIgnoreCase(COIOT_TAG_BLK)) {
148 while (in.hasNext()) {
149 CoIotDescrBlk blk = new CoIotDescrBlk();
151 while (in.hasNext()) {
152 switch (in.nextName().toUpperCase()) {
154 blk.id = in.nextString();
157 blk.desc = in.nextString();
168 name = in.nextName();
171 if (name.equalsIgnoreCase(COIOT_TAG_SEN)) {
173 * parse sensor list, e.g.
175 * { "I":111,"T":"Red","R":"0/255","L":0},
176 * { "I":121,"T":"Green","R":"0/255","L":0},
180 while (in.hasNext()) {
181 CoIotDescrSen sen = new CoIotDescrSen();
183 while (in.hasNext()) {
184 String tag = in.nextName();
185 switch (tag.toUpperCase()) {
187 sen.id = in.nextString();
190 sen.desc = in.nextString();
193 sen.type = in.nextString();
196 JsonToken token = in.peek();
197 if (token == JsonToken.BEGIN_ARRAY) {
198 // must be v2: an array
201 while (in.hasNext()) {
202 String value = in.nextString();
203 sen.range += sen.range.isEmpty() ? value : ";" + value;
207 sen.range = in.nextString();
211 sen.links = String.valueOf(in.nextInt());
213 case "U": // New in CoAPv2: unit"
214 sen.unit = in.nextString();
233 public void write(final JsonWriter out, final CoIotDevDescription descr) throws IOException {
236 out.name(COIOT_TAG_BLK).beginArray();
237 for (int i = 0; i < descr.blk.size(); i++) {
238 CoIotDescrBlk blk = descr.blk.get(i);
246 out.name(COIOT_TAG_SEN).beginArray();
247 for (int i = 0; i < descr.sen.size(); i++) {
248 // Create element, e.g. {“I”:66, “D”:“lux”, “T”:“L”, “R”:“0/100000”, “L”:1},
249 CoIotDescrSen sen = descr.sen.get(i);
254 out.value(sen.range);
255 out.value(sen.links);
256 if (sen.unit != null) {
267 protected static class CoIotSensorTypeAdapter extends TypeAdapter<CoIotGenericSensorList> {
269 public CoIotGenericSensorList read(final JsonReader in) throws IOException {
270 CoIotGenericSensorList list = new CoIotGenericSensorList();
273 String generic = in.nextName();
274 if (generic.equals(COIOT_TAG_GENERIC)) {
276 while (in.hasNext()) {
277 CoIotSensor sensor = new CoIotSensor();
279 in.nextInt(); // alway 0
280 sensor.id = Integer.toString(in.nextInt());
281 JsonToken token = in.peek();
282 if (token == JsonToken.STRING) {
284 sensor.valueStr = in.nextString();
286 } else if (token == JsonToken.NUMBER) {
288 sensor.value = in.nextDouble();
289 sensor.valueStr = "";
290 } else if (token == JsonToken.BEGIN_ARRAY) {
291 sensor.valueArray = new ArrayList<>();
293 while (in.hasNext()) {
294 if (in.peek() == JsonToken.STRING) {
295 sensor.valueArray.add(in.nextString());
304 list.generic.add(sensor);
314 public void write(final JsonWriter out, final CoIotGenericSensorList o) throws IOException {
315 CoIotGenericSensorList sensors = o;
317 if (sensors != null) {
318 out.name(COIOT_TAG_GENERIC).beginArray();
319 for (int i = 0; i < sensors.generic.size(); i++) {
322 out.value(sensors.generic.get(i).id);
323 out.value(sensors.generic.get(i).value);