Commit 51b0d50542ff0da65c7abd722e3c0f6332c8a5ee

Authored by nickAS21
Committed by GitHub
1 parent cb945010

Lwm2m discovery (#4438)

* Lwm2m: fix bug delete zero updateAttribute

* Lwm2m: front add select binding

* Lwm2m: discovery only for test

* Lwm2m: remove type_cast_enabled from the main branch.

* Lwm2m: remove type_cast_enabled from the main branch.

* Lwm2m: remove type_cast_enabled from the main branch.

* Lwm2m: remove double code.
Showing 15 changed files with 420 additions and 208 deletions
... ... @@ -35,7 +35,6 @@ import org.thingsboard.server.transport.lwm2m.secure.LwM2mCredentialsSecurityInf
35 35 import org.thingsboard.server.transport.lwm2m.secure.ReadResultSecurityStore;
36 36 import org.thingsboard.server.transport.lwm2m.server.LwM2mSessionMsgListener;
37 37 import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportContextServer;
38   -import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler;
39 38 import org.thingsboard.server.transport.lwm2m.utils.TypeServer;
40 39
41 40 import java.io.IOException;
... ... @@ -165,13 +164,13 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore {
165 164 lwM2MBootstrapConfig.bootstrapServer = new LwM2MServerBootstrap(lwM2MBootstrapConfig.bootstrapServer, profileServerBootstrap);
166 165 lwM2MBootstrapConfig.lwm2mServer = new LwM2MServerBootstrap(lwM2MBootstrapConfig.lwm2mServer, profileLwm2mServer);
167 166 String logMsg = String.format("%s: getParametersBootstrap: %s Access connect client with bootstrap server.", LOG_LW2M_INFO, store.getEndPoint());
168   - context.sendParametersOnThingsboard(context.getTelemetryMsgObject(logMsg), LwM2mTransportHandler.DEVICE_TELEMETRY_TOPIC, sessionInfo);
  167 + context.sendParametersOnThingsboardTelemetry(context.getKvLogyToThingsboard(logMsg), sessionInfo);
169 168 return lwM2MBootstrapConfig;
170 169 } else {
171 170 log.error(" [{}] Different values SecurityMode between of client and profile.", store.getEndPoint());
172 171 log.error("{} getParametersBootstrap: [{}] Different values SecurityMode between of client and profile.", LOG_LW2M_ERROR, store.getEndPoint());
173 172 String logMsg = String.format("%s: getParametersBootstrap: %s Different values SecurityMode between of client and profile.", LOG_LW2M_ERROR, store.getEndPoint());
174   - context.sendParametersOnThingsboard(context.getTelemetryMsgObject(logMsg), LwM2mTransportHandler.DEVICE_TELEMETRY_TOPIC, sessionInfo);
  173 + context.sendParametersOnThingsboardTelemetry(context.getKvLogyToThingsboard(logMsg), sessionInfo);
175 174 return null;
176 175 }
177 176 }
... ...
... ... @@ -26,7 +26,7 @@ import org.eclipse.leshan.server.registration.RegistrationUpdate;
26 26
27 27 import java.util.Collection;
28 28
29   -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.convertToIdVerFromObjectId;
  29 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.convertPathFromObjectIdToIdVer;
30 30
31 31 @Slf4j
32 32 public class LwM2mServerListener {
... ... @@ -92,7 +92,7 @@ public class LwM2mServerListener {
92 92 public void onResponse(Observation observation, Registration registration, ObserveResponse response) {
93 93 if (registration != null) {
94 94 try {
95   - service.onObservationResponse(registration, convertToIdVerFromObjectId(observation.getPath().toString(), registration), response);
  95 + service.onObservationResponse(registration, convertPathFromObjectIdToIdVer(observation.getPath().toString(), registration), response);
96 96 } catch (Exception e) {
97 97 log.error("[{}] onResponse", e.toString());
98 98
... ... @@ -107,7 +107,7 @@ public class LwM2mServerListener {
107 107
108 108 @Override
109 109 public void newObservation(Observation observation, Registration registration) {
110   -// log.info("Received newObservation from [{}] endpoint [{}] ", observation.getPath(), registration.getEndpoint());
  110 + log.info("Received newObservation from [{}] endpoint [{}] ", observation.getPath(), registration.getEndpoint());
111 111 }
112 112 };
113 113
... ...
... ... @@ -30,31 +30,33 @@ package org.thingsboard.server.transport.lwm2m.server;
30 30 * limitations under the License.
31 31 */
32 32
33   -import com.google.gson.JsonElement;
34   -import com.google.gson.JsonObject;
35 33 import lombok.Getter;
36 34 import lombok.extern.slf4j.Slf4j;
37 35 import org.eclipse.leshan.core.model.DDFFileParser;
38 36 import org.eclipse.leshan.core.model.DefaultDDFFileValidator;
39 37 import org.eclipse.leshan.core.model.InvalidDDFFileException;
40 38 import org.eclipse.leshan.core.model.ObjectModel;
  39 +import org.eclipse.leshan.core.model.ResourceModel;
  40 +import org.eclipse.leshan.core.node.codec.CodecException;
41 41 import org.springframework.stereotype.Component;
42 42 import org.thingsboard.server.common.transport.TransportContext;
43 43 import org.thingsboard.server.common.transport.TransportResourceCache;
44 44 import org.thingsboard.server.common.transport.TransportService;
45 45 import org.thingsboard.server.common.transport.TransportServiceCallback;
46   -import org.thingsboard.server.common.transport.adaptor.AdaptorException;
47 46 import org.thingsboard.server.common.transport.lwm2m.LwM2MTransportConfigServer;
  47 +import org.thingsboard.server.gen.transport.TransportProtos;
48 48 import org.thingsboard.server.gen.transport.TransportProtos.PostAttributeMsg;
49 49 import org.thingsboard.server.gen.transport.TransportProtos.PostTelemetryMsg;
50 50 import org.thingsboard.server.gen.transport.TransportProtos.SessionInfoProto;
51   -import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceCredentialsResponseMsg;
52 51 import org.thingsboard.server.queue.util.TbLwM2mTransportComponent;
53 52 import org.thingsboard.server.transport.lwm2m.server.adaptors.LwM2MJsonAdaptor;
54 53
55 54 import java.io.ByteArrayInputStream;
56 55 import java.io.IOException;
  56 +import java.util.ArrayList;
  57 +import java.util.List;
57 58
  59 +import static org.thingsboard.server.gen.transport.TransportProtos.KeyValueType.BOOLEAN_V;
58 60 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.LOG_LW2M_TELEMETRY;
59 61
60 62 @Slf4j
... ... @@ -91,7 +93,7 @@ public class LwM2mTransportContextServer extends TransportContext {
91 93 /**
92 94 * send to Thingsboard Attribute || Telemetry
93 95 *
94   - * @param msg - JsonObject: [{name: value}]
  96 + * @param msg - JsonObject: [{name: value}]
95 97 * @return - dummy
96 98 */
97 99 private <T> TransportServiceCallback<Void> getPubAckCallbackSendAttrTelemetry(final T msg) {
... ... @@ -108,33 +110,29 @@ public class LwM2mTransportContextServer extends TransportContext {
108 110 };
109 111 }
110 112
111   - public void sendParametersOnThingsboard(JsonElement msg, String topicName, SessionInfoProto sessionInfo) {
112   - try {
113   - if (topicName.equals(LwM2mTransportHandler.DEVICE_ATTRIBUTES_TOPIC)) {
114   - PostAttributeMsg postAttributeMsg = adaptor.convertToPostAttributes(msg);
115   - TransportServiceCallback call = this.getPubAckCallbackSendAttrTelemetry(postAttributeMsg);
116   - transportService.process(sessionInfo, postAttributeMsg, this.getPubAckCallbackSendAttrTelemetry(call));
117   - } else if (topicName.equals(LwM2mTransportHandler.DEVICE_TELEMETRY_TOPIC)) {
118   - PostTelemetryMsg postTelemetryMsg = adaptor.convertToPostTelemetry(msg);
119   - TransportServiceCallback call = this.getPubAckCallbackSendAttrTelemetry(postTelemetryMsg);
120   - transportService.process(sessionInfo, postTelemetryMsg, this.getPubAckCallbackSendAttrTelemetry(call));
121   - }
122   - } catch (AdaptorException e) {
123   - log.error("[{}] Failed to process publish msg [{}]", topicName, e);
124   - log.info("[{}] Closing current session due to invalid publish", topicName);
125   - }
  113 + public void sendParametersOnThingsboardAttribute(List<TransportProtos.KeyValueProto> result, SessionInfoProto sessionInfo) {
  114 + PostAttributeMsg.Builder request = PostAttributeMsg.newBuilder();
  115 + request.addAllKv(result);
  116 + PostAttributeMsg postAttributeMsg = request.build();
  117 + TransportServiceCallback call = this.getPubAckCallbackSendAttrTelemetry(postAttributeMsg);
  118 + transportService.process(sessionInfo, postAttributeMsg, this.getPubAckCallbackSendAttrTelemetry(call));
126 119 }
127 120
128   - public JsonObject getTelemetryMsgObject(String logMsg) {
129   - JsonObject telemetries = new JsonObject();
130   - telemetries.addProperty(LOG_LW2M_TELEMETRY, logMsg);
131   - return telemetries;
  121 + public void sendParametersOnThingsboardTelemetry(List<TransportProtos.KeyValueProto> result, SessionInfoProto sessionInfo) {
  122 + PostTelemetryMsg.Builder request = PostTelemetryMsg.newBuilder();
  123 + TransportProtos.TsKvListProto.Builder builder = TransportProtos.TsKvListProto.newBuilder();
  124 + builder.setTs(System.currentTimeMillis());
  125 + builder.addAllKv(result);
  126 + request.addTsKvList(builder.build());
  127 + PostTelemetryMsg postTelemetryMsg = request.build();
  128 + TransportServiceCallback call = this.getPubAckCallbackSendAttrTelemetry(postTelemetryMsg);
  129 + transportService.process(sessionInfo, postTelemetryMsg, this.getPubAckCallbackSendAttrTelemetry(call));
132 130 }
133 131
134 132 /**
135 133 * @return - sessionInfo after access connect client
136 134 */
137   - public SessionInfoProto getValidateSessionInfo(ValidateDeviceCredentialsResponseMsg msg, long mostSignificantBits, long leastSignificantBits) {
  135 + public SessionInfoProto getValidateSessionInfo(TransportProtos.ValidateDeviceCredentialsResponseMsg msg, long mostSignificantBits, long leastSignificantBits) {
138 136 return SessionInfoProto.newBuilder()
139 137 .setNodeId(this.getNodeId())
140 138 .setSessionIdMSB(mostSignificantBits)
... ... @@ -159,4 +157,90 @@ public class LwM2mTransportContextServer extends TransportContext {
159 157 return null;
160 158 }
161 159 }
  160 +
  161 + /**
  162 + *
  163 + * @param logMsg - info about Logs
  164 + * @return- KeyValueProto for telemetry (Logs)
  165 + */
  166 + public List <TransportProtos.KeyValueProto> getKvLogyToThingsboard(String logMsg) {
  167 + List <TransportProtos.KeyValueProto> result = new ArrayList<>();
  168 + result.add(TransportProtos.KeyValueProto.newBuilder()
  169 + .setKey(LOG_LW2M_TELEMETRY)
  170 + .setType(TransportProtos.KeyValueType.STRING_V)
  171 + .setStringV(logMsg).build());
  172 + return result;
  173 + }
  174 +
  175 + /**
  176 + * @return - KeyValueProto for attribute/telemetry (change value)
  177 + * @throws CodecException -
  178 + */
  179 +
  180 + public TransportProtos.KeyValueProto getKvAttrTelemetryToThingsboard(ResourceModel.Type resourceType, String resourceName, Object value, boolean isMultiInstances) {
  181 + TransportProtos.KeyValueProto.Builder kvProto = TransportProtos.KeyValueProto.newBuilder().setKey(resourceName);
  182 + if (isMultiInstances) {
  183 + kvProto.setType(TransportProtos.KeyValueType.JSON_V)
  184 + .setJsonV((String) value);
  185 + }
  186 + else {
  187 + switch (resourceType) {
  188 + case BOOLEAN:
  189 + kvProto.setType(BOOLEAN_V).setBoolV((Boolean) value).build();
  190 + break;
  191 + case STRING:
  192 + case TIME:
  193 + case OPAQUE:
  194 + case OBJLNK:
  195 + kvProto.setType(TransportProtos.KeyValueType.STRING_V).setStringV((String) value);
  196 + break;
  197 + case INTEGER:
  198 + kvProto.setType(TransportProtos.KeyValueType.LONG_V).setLongV((Long) value);
  199 + break;
  200 + case FLOAT:
  201 + kvProto.setType(TransportProtos.KeyValueType.DOUBLE_V).setDoubleV((Double) value);
  202 + }
  203 + }
  204 + return kvProto.build();
  205 + }
  206 +
  207 + /**
  208 + *
  209 + * @param currentType -
  210 + * @param resourcePath -
  211 + * @return
  212 + */
  213 + public ResourceModel.Type getResourceModelTypeEqualsKvProtoValueType(ResourceModel.Type currentType, String resourcePath) {
  214 + switch (currentType) {
  215 + case BOOLEAN:
  216 + return ResourceModel.Type.BOOLEAN;
  217 + case STRING:
  218 + case TIME:
  219 + case OPAQUE:
  220 + case OBJLNK:
  221 + return ResourceModel.Type.STRING;
  222 + case INTEGER:
  223 + return ResourceModel.Type.INTEGER;
  224 + case FLOAT:
  225 + return ResourceModel.Type.FLOAT;
  226 + default:
  227 + }
  228 + throw new CodecException("Invalid ResourceModel_Type for resource %s, got %s", resourcePath, currentType);
  229 + }
  230 +
  231 + public Object getValueFromKvProto (TransportProtos.KeyValueProto kv) {
  232 + switch (kv.getType()) {
  233 + case BOOLEAN_V:
  234 + return kv.getBoolV();
  235 + case LONG_V:
  236 + return kv.getLongV();
  237 + case DOUBLE_V:
  238 + return kv.getDoubleV();
  239 + case STRING_V:
  240 + return kv.getStringV();
  241 + case JSON_V:
  242 + return kv.getJsonV();
  243 + }
  244 + return null;
  245 + }
162 246 }
... ...
... ... @@ -75,6 +75,8 @@ public class LwM2mTransportHandler {
75 75 public static final String KEY_NAME = "keyName";
76 76 public static final String OBSERVE = "observe";
77 77 public static final String ATTRIBUTE_LWM2M = "attributeLwm2m";
  78 + public static final String RESOURCE_VALUE = "resValue";
  79 + public static final String RESOURCE_TYPE = "resType";
78 80
79 81 private static final String REQUEST = "/request";
80 82 private static final String RESPONSE = "/response";
... ... @@ -333,28 +335,30 @@ public class LwM2mTransportHandler {
333 335 };
334 336 }
335 337
336   - public static String convertToObjectIdFromIdVer(String key) {
  338 + public static String convertPathFromIdVerToObjectId(String pathIdVer) {
337 339 try {
338   - String[] keyArray = key.split(LWM2M_SEPARATOR_PATH);
  340 + String[] keyArray = pathIdVer.split(LWM2M_SEPARATOR_PATH);
339 341 if (keyArray.length > 1 && keyArray[1].split(LWM2M_SEPARATOR_KEY).length == 2) {
340 342 keyArray[1] = keyArray[1].split(LWM2M_SEPARATOR_KEY)[0];
341 343 return StringUtils.join(keyArray, LWM2M_SEPARATOR_PATH);
342   - } else {
343   - return key;
  344 + }
  345 + else {
  346 + return pathIdVer;
344 347 }
345 348 } catch (Exception e) {
346 349 return null;
347 350 }
348 351 }
349 352
350   - public static String convertToIdVerFromObjectId(String path, Registration registration) {
  353 + public static String convertPathFromObjectIdToIdVer(String path, Registration registration) {
351 354 String ver = registration.getSupportedObject().get(new LwM2mPath(path).getObjectId());
352 355 try {
353 356 String[] keyArray = path.split(LWM2M_SEPARATOR_PATH);
354 357 if (keyArray.length > 1) {
355 358 keyArray[1] = keyArray[1] + LWM2M_SEPARATOR_KEY + ver;
356 359 return StringUtils.join(keyArray, LWM2M_SEPARATOR_PATH);
357   - } else {
  360 + }
  361 + else {
358 362 return path;
359 363 }
360 364 } catch (Exception e) {
... ...
... ... @@ -69,8 +69,8 @@ import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandle
69 69 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.PUT_TYPE_OPER_WRITE_ATTRIBUTES;
70 70 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.PUT_TYPE_OPER_WRITE_UPDATE;
71 71 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.RESPONSE_CHANNEL;
72   -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.convertToIdVerFromObjectId;
73   -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.convertToObjectIdFromIdVer;
  72 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.convertPathFromIdVerToObjectId;
  73 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.convertPathFromObjectIdToIdVer;
74 74 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.createWriteAttributeRequest;
75 75
76 76 @Slf4j
... ... @@ -114,7 +114,7 @@ public class LwM2mTransportRequest {
114 114 */
115 115 public void sendAllRequest(Registration registration, String targetIdVer, String typeOper,
116 116 String contentFormatParam, Observation observation, Object params, long timeoutInMs) {
117   - String target = convertToObjectIdFromIdVer(targetIdVer);
  117 + String target = convertPathFromIdVerToObjectId(targetIdVer);
118 118 LwM2mPath resultIds = new LwM2mPath(target);
119 119 if (registration != null && resultIds.getObjectId() >= 0) {
120 120 DownlinkRequest request = null;
... ... @@ -204,7 +204,7 @@ public class LwM2mTransportRequest {
204 204 private void sendRequest(Registration registration, LwM2mClient lwM2MClient, DownlinkRequest request, long timeoutInMs) {
205 205 leshanServer.send(registration, request, timeoutInMs, (ResponseCallback<?>) response -> {
206 206 if (!lwM2MClient.isInit()) {
207   - lwM2MClient.initValue(this.serviceImpl, convertToIdVerFromObjectId(request.getPath().toString(), registration));
  207 + lwM2MClient.initValue(this.serviceImpl, convertPathFromObjectIdToIdVer(request.getPath().toString(), registration));
208 208 }
209 209 if (CoAP.ResponseCode.isSuccess(((Response) response.getCoapResponse()).getCode())) {
210 210 this.handleResponse(registration, request.getPath().toString(), response, request);
... ... @@ -228,7 +228,7 @@ public class LwM2mTransportRequest {
228 228 }
229 229 }, e -> {
230 230 if (!lwM2MClient.isInit()) {
231   - lwM2MClient.initValue(this.serviceImpl, convertToIdVerFromObjectId(request.getPath().toString(), registration));
  231 + lwM2MClient.initValue(this.serviceImpl, convertPathFromObjectIdToIdVer(request.getPath().toString(), registration));
232 232 }
233 233 String msg = String.format("%s: sendRequest: Resource path - %s msg error - %s SendRequest to Client",
234 234 LOG_LW2M_ERROR, request.getPath().toString(), e.toString());
... ... @@ -287,7 +287,7 @@ public class LwM2mTransportRequest {
287 287 * @param response -
288 288 */
289 289 private void sendResponse(Registration registration, String path, LwM2mResponse response, DownlinkRequest request) {
290   - String pathIdVer = convertToIdVerFromObjectId(path, registration);
  290 + String pathIdVer = convertPathFromObjectIdToIdVer(path, registration);
291 291 if (response instanceof ReadResponse) {
292 292 serviceImpl.onObservationResponse(registration, pathIdVer, (ReadResponse) response);
293 293 } else if (response instanceof CancelObservationResponse) {
... ...
... ... @@ -18,6 +18,7 @@ package org.thingsboard.server.transport.lwm2m.server;
18 18 import com.fasterxml.jackson.core.type.TypeReference;
19 19 import com.google.common.collect.Sets;
20 20 import com.google.gson.Gson;
  21 +import com.google.gson.GsonBuilder;
21 22 import com.google.gson.JsonArray;
22 23 import com.google.gson.JsonElement;
23 24 import com.google.gson.JsonObject;
... ... @@ -42,7 +43,6 @@ import org.thingsboard.server.common.data.Device;
42 43 import org.thingsboard.server.common.data.DeviceProfile;
43 44 import org.thingsboard.server.common.transport.TransportService;
44 45 import org.thingsboard.server.common.transport.adaptor.AdaptorException;
45   -import org.thingsboard.server.common.transport.adaptor.JsonConverter;
46 46 import org.thingsboard.server.common.transport.service.DefaultTransportService;
47 47 import org.thingsboard.server.gen.transport.TransportProtos;
48 48 import org.thingsboard.server.gen.transport.TransportProtos.AttributeUpdateNotificationMsg;
... ... @@ -52,12 +52,12 @@ import org.thingsboard.server.queue.util.TbLwM2mTransportComponent;
52 52 import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient;
53 53 import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientContext;
54 54 import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientProfile;
  55 +import org.thingsboard.server.transport.lwm2m.server.client.ResultsAddKeyValueProto;
55 56 import org.thingsboard.server.transport.lwm2m.server.client.ResultsAnalyzerParameters;
56 57 import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl;
57 58
58 59 import javax.annotation.PostConstruct;
59 60 import java.util.ArrayList;
60   -import java.util.Arrays;
61 61 import java.util.Collection;
62 62 import java.util.HashSet;
63 63 import java.util.LinkedHashSet;
... ... @@ -76,24 +76,19 @@ import java.util.stream.Collectors;
76 76
77 77 import static org.eclipse.leshan.core.attributes.Attribute.OBJECT_VERSION;
78 78 import static org.thingsboard.server.common.data.lwm2m.LwM2mConstants.LWM2M_SEPARATOR_PATH;
79   -import static org.thingsboard.server.common.transport.util.JsonUtils.getJsonObject;
80 79 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.CLIENT_NOT_AUTHORIZED;
81 80 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.DEVICE_ATTRIBUTES_REQUEST;
82   -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.DEVICE_ATTRIBUTES_TOPIC;
83   -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.DEVICE_TELEMETRY_TOPIC;
84 81 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.GET_TYPE_OPER_DISCOVER;
85 82 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.GET_TYPE_OPER_OBSERVE;
86 83 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.GET_TYPE_OPER_READ;
87 84 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.LOG_LW2M_ERROR;
88 85 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.LOG_LW2M_INFO;
89   -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.LOG_LW2M_TELEMETRY;
90 86 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.LWM2M_STRATEGY_2;
91 87 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.POST_TYPE_OPER_EXECUTE;
92 88 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.POST_TYPE_OPER_WRITE_REPLACE;
93 89 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.PUT_TYPE_OPER_WRITE_ATTRIBUTES;
94 90 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.SERVICE_CHANNEL;
95   -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.convertToIdVerFromObjectId;
96   -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.convertToObjectIdFromIdVer;
  91 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.convertPathFromIdVerToObjectId;
97 92 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.getAckCallback;
98 93 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.validateObjectVerFromKey;
99 94
... ... @@ -163,6 +158,7 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
163 158 transportService.registerAsyncSession(sessionInfo, new LwM2mSessionMsgListener(this, sessionInfo));
164 159 transportService.process(sessionInfo, DefaultTransportService.getSessionEventMsg(SessionEvent.OPEN), null);
165 160 transportService.process(sessionInfo, TransportProtos.SubscribeToAttributeUpdatesMsg.newBuilder().build(), null);
  161 + transportService.process(sessionInfo, TransportProtos.SubscribeToRPCMsg.newBuilder().build(), null);
166 162 this.initLwM2mFromClientValue(registration, lwM2MClient);
167 163 this.sendLogsToThingsboard(LOG_LW2M_INFO + ": Client create after Registration", registration);
168 164 } else {
... ... @@ -309,33 +305,32 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
309 305 @Override
310 306 public void onAttributeUpdate(AttributeUpdateNotificationMsg msg, TransportProtos.SessionInfoProto sessionInfo) {
311 307 if (msg.getSharedUpdatedCount() > 0) {
312   - JsonElement el = JsonConverter.toJson(msg);
313   - el.getAsJsonObject().entrySet().forEach(de -> {
314   - String pathIdVer = this.getPathAttributeUpdate(sessionInfo, de.getKey());
315   - String value = de.getValue().getAsString();
  308 + msg.getSharedUpdatedList().forEach(tsKvProto -> {
  309 + String pathName = tsKvProto.getKv().getKey();
  310 + String pathIdVer = this.validatePathIntoProfile(sessionInfo, pathName);
  311 + Object valueNew = this.lwM2mTransportContextServer.getValueFromKvProto(tsKvProto.getKv());
316 312 LwM2mClient lwM2MClient = lwM2mClientContext.getLwM2mClient(new UUID(sessionInfo.getSessionIdMSB(), sessionInfo.getSessionIdLSB()));
317   - LwM2mClientProfile clientProfile = lwM2mClientContext.getProfile(new UUID(sessionInfo.getDeviceProfileIdMSB(), sessionInfo.getDeviceProfileIdLSB()));
318   - if (pathIdVer != null && !pathIdVer.isEmpty() && (this.validatePathInAttrProfile(clientProfile, pathIdVer) || this.validatePathInTelemetryProfile(clientProfile, pathIdVer))) {
  313 + if (pathIdVer != null) {
319 314 ResourceModel resourceModel = lwM2MClient.getResourceModel(pathIdVer);
320 315 if (resourceModel != null && resourceModel.operations.isWritable()) {
321   - lwM2mTransportRequest.sendAllRequest(lwM2MClient.getRegistration(), pathIdVer, POST_TYPE_OPER_WRITE_REPLACE,
322   - ContentFormat.TLV.getName(), null, value, this.lwM2mTransportContextServer.getLwM2MTransportConfigServer().getTimeout());
  316 + this.updateResourcesValueToClient(lwM2MClient, this.getResourceValueFormatKv(lwM2MClient, pathIdVer), valueNew, pathIdVer);
323 317 } else {
324   - log.error("Resource path - [{}] value - [{}] is not Writable and cannot be updated", pathIdVer, value);
  318 + log.error("Resource path - [{}] value - [{}] is not Writable and cannot be updated", pathIdVer, valueNew);
325 319 String logMsg = String.format("%s: attributeUpdate: Resource path - %s value - %s is not Writable and cannot be updated",
326   - LOG_LW2M_ERROR, pathIdVer, value);
  320 + LOG_LW2M_ERROR, pathIdVer, valueNew);
327 321 this.sendLogsToThingsboard(logMsg, lwM2MClient.getRegistration());
328 322 }
329 323 } else {
330   - log.error("Attribute name - [{}] value - [{}] is not present as attribute in profile and cannot be updated", de.getKey(), value);
  324 + log.error("Resource name name - [{}] value - [{}] is not present as attribute/telemetry in profile and cannot be updated", pathName, valueNew);
331 325 String logMsg = String.format("%s: attributeUpdate: attribute name - %s value - %s is not present as attribute in profile and cannot be updated",
332   - LOG_LW2M_ERROR, de.getKey(), value);
  326 + LOG_LW2M_ERROR, pathName, valueNew);
333 327 this.sendLogsToThingsboard(logMsg, lwM2MClient.getRegistration());
334 328 }
335 329 });
336 330 } else if (msg.getSharedDeletedCount() > 0) {
337 331 log.info("[{}] delete [{}] onAttributeUpdate", msg.getSharedDeletedList(), sessionInfo);
338 332 }
  333 +
339 334 }
340 335
341 336 /**
... ... @@ -462,32 +457,13 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
462 457 }
463 458
464 459 /**
465   - * @param msg - text msg
  460 + * @param logMsg - text msg
466 461 * @param registration - Id of Registration LwM2M Client
467 462 */
468   - public void sendLogsToThingsboard(String msg, Registration registration) {
469   - if (msg != null) {
470   - JsonObject telemetries = new JsonObject();
471   - telemetries.addProperty(LOG_LW2M_TELEMETRY, msg);
472   - this.updateParametersOnThingsboard(telemetries, DEVICE_TELEMETRY_TOPIC, registration);
473   - }
474   - }
475   -
476   -
477   - /**
478   - * // !!! Ok
479   - * Prepare send to Thigsboard callback - Attribute or Telemetry
480   - *
481   - * @param msg - JsonArray: [{name: value}]
482   - * @param topicName - Api Attribute or Telemetry
483   - * @param registration - Id of Registration LwM2M Client
484   - */
485   - public void updateParametersOnThingsboard(JsonElement msg, String topicName, Registration registration) {
  463 + public void sendLogsToThingsboard(String logMsg, Registration registration) {
486 464 SessionInfoProto sessionInfo = this.getValidateSessionInfo(registration);
487   - if (sessionInfo != null) {
488   - lwM2mTransportContextServer.sendParametersOnThingsboard(msg, topicName, sessionInfo);
489   - } else {
490   - log.error("Client: [{}] updateParametersOnThingsboard [{}] sessionInfo ", registration, null);
  465 + if (logMsg != null && sessionInfo != null) {
  466 + this.lwM2mTransportContextServer.sendParametersOnThingsboardTelemetry(this.lwM2mTransportContextServer.getKvLogyToThingsboard(logMsg), sessionInfo);
491 467 }
492 468 }
493 469
... ... @@ -517,7 +493,7 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
517 493 this.initReadAttrTelemetryObserveToClient(registration, lwM2MClient, GET_TYPE_OPER_READ, clientObjects);
518 494 this.initReadAttrTelemetryObserveToClient(registration, lwM2MClient, GET_TYPE_OPER_OBSERVE, clientObjects);
519 495 this.initReadAttrTelemetryObserveToClient(registration, lwM2MClient, PUT_TYPE_OPER_WRITE_ATTRIBUTES, clientObjects);
520   -// this.initReadAttrTelemetryObserveToClient(registration, lwM2MClient, GET_TYPE_OPER_DISCOVER, clientObjects);
  496 + this.initReadAttrTelemetryObserveToClient(registration, lwM2MClient, GET_TYPE_OPER_DISCOVER, clientObjects);
521 497 }
522 498 }
523 499
... ... @@ -577,17 +553,20 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
577 553 * @param registration - Registration LwM2M Client
578 554 */
579 555 private void updateAttrTelemetry(Registration registration, Set<String> paths) {
580   - JsonObject attributes = new JsonObject();
581   - JsonObject telemetries = new JsonObject();
582 556 try {
583   - this.getParametersFromProfile(attributes, telemetries, registration, paths);
  557 + ResultsAddKeyValueProto results = getParametersFromProfile(registration, paths);
  558 + SessionInfoProto sessionInfo = this.getValidateSessionInfo(registration);
  559 + if (results != null && sessionInfo != null) {
  560 + if (results.getResultAttributes().size() > 0) {
  561 + this.lwM2mTransportContextServer.sendParametersOnThingsboardAttribute(results.getResultAttributes(), sessionInfo);
  562 + }
  563 + if (results.getResultTelemetries().size() > 0) {
  564 + this.lwM2mTransportContextServer.sendParametersOnThingsboardTelemetry(results.getResultTelemetries(), sessionInfo);
  565 + }
  566 + }
584 567 } catch (Exception e) {
585 568 log.error("UpdateAttrTelemetry", e);
586 569 }
587   - if (attributes.getAsJsonObject().entrySet().size() > 0)
588   - this.updateParametersOnThingsboard(attributes, DEVICE_ATTRIBUTES_TOPIC, registration);
589   - if (telemetries.getAsJsonObject().entrySet().size() > 0)
590   - this.updateParametersOnThingsboard(telemetries, DEVICE_TELEMETRY_TOPIC, registration);
591 570 }
592 571
593 572 /**
... ... @@ -700,73 +679,99 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
700 679 }
701 680
702 681 /**
703   - * @param registration -
704   - * @return all instances in client
705   - */
706   - private Set<String> getAllInstancesInClient(Registration registration) {
707   - Set<String> clientInstances = ConcurrentHashMap.newKeySet();
708   - Arrays.stream(registration.getObjectLinks()).forEach(url -> {
709   - LwM2mPath pathIds = new LwM2mPath(url.getUrl());
710   - if (pathIds.isObjectInstance()) {
711   - clientInstances.add(convertToIdVerFromObjectId(url.getUrl(), registration));
712   - }
713   - });
714   - return (clientInstances.size() > 0) ? clientInstances : null;
715   - }
716   -
717   - /**
718   - * @param attributes - new JsonObject
719   - * @param telemetry - new JsonObject
  682 + * // * @param attributes - new JsonObject
  683 + * // * @param telemetry - new JsonObject
  684 + *
720 685 * @param registration - Registration LwM2M Client
721 686 * @param path -
722 687 */
723   - private void getParametersFromProfile(JsonObject attributes, JsonObject telemetry, Registration registration, Set<String> path) {
  688 + private ResultsAddKeyValueProto getParametersFromProfile(Registration registration, Set<String> path) {
724 689 if (path != null && path.size() > 0) {
  690 + ResultsAddKeyValueProto results = new ResultsAddKeyValueProto();
725 691 LwM2mClientProfile lwM2MClientProfile = lwM2mClientContext.getProfile(registration);
726   - lwM2MClientProfile.getPostAttributeProfile().forEach(idVer -> {
727   - if (path.contains(idVer.getAsString())) {
728   - this.addParameters(idVer.getAsString(), attributes, registration);
  692 + List<TransportProtos.KeyValueProto> resultAttributes = new ArrayList<>();
  693 + lwM2MClientProfile.getPostAttributeProfile().forEach(pathIdVer -> {
  694 + if (path.contains(pathIdVer.getAsString())) {
  695 + TransportProtos.KeyValueProto kvAttr = this.getKvToThingsboard(pathIdVer.getAsString(), registration);
  696 + if (kvAttr != null) {
  697 + resultAttributes.add(kvAttr);
  698 + }
729 699 }
730 700 });
731   - lwM2MClientProfile.getPostTelemetryProfile().forEach(idVer -> {
732   - if (path.contains(idVer.getAsString())) {
733   - this.addParameters(idVer.getAsString(), telemetry, registration);
  701 + List<TransportProtos.KeyValueProto> resultTelemetries = new ArrayList<>();
  702 + lwM2MClientProfile.getPostTelemetryProfile().forEach(pathIdVer -> {
  703 + if (path.contains(pathIdVer.getAsString())) {
  704 + TransportProtos.KeyValueProto kvAttr = this.getKvToThingsboard(pathIdVer.getAsString(), registration);
  705 + if (kvAttr != null) {
  706 + resultTelemetries.add(kvAttr);
  707 + }
734 708 }
735 709 });
  710 + if (resultAttributes.size() > 0) {
  711 + results.setResultAttributes(resultAttributes);
  712 + }
  713 + if (resultTelemetries.size() > 0) {
  714 + results.setResultTelemetries(resultTelemetries);
  715 + }
  716 + return results;
736 717 }
  718 + return null;
737 719 }
738 720
739   - /**
740   - * @param parameters - JsonObject attributes/telemetry
741   - * @param registration - Registration LwM2M Client
742   - */
743   - private void addParameters(String path, JsonObject parameters, Registration registration) {
744   - LwM2mClient lwM2MClient = lwM2mClientContext.getLwM2mClientWithReg(registration, null);
  721 +// public TransportProtos.KeyValueProto getKvToThingsboard(String pathIdVer, Registration registration) {
  722 +// ResultsResourceValue resultsResourceValue = getResultsResourceValue(pathIdVer, registration);
  723 +// return resultsResourceValue != null ? this.lwM2mTransportContextServer.getKvAttrTelemetryToThingsboard(resultsResourceValue) : null;
  724 +// }
  725 +
  726 + private TransportProtos.KeyValueProto getKvToThingsboard(String pathIdVer, Registration registration) {
  727 + LwM2mClient lwM2MClient = this.lwM2mClientContext.getLwM2mClientWithReg(null, registration.getId());
745 728 JsonObject names = lwM2mClientContext.getProfiles().get(lwM2MClient.getProfileId()).getPostKeyNameProfile();
746   - if (names != null && names.has(path)) {
747   - String resName = names.get(path).getAsString();
748   - if (resName != null && !resName.isEmpty()) {
  729 + if (names != null && names.has(pathIdVer)) {
  730 + String resourceName = names.get(pathIdVer).getAsString();
  731 + if (resourceName != null && !resourceName.isEmpty()) {
749 732 try {
750   - String resValue = this.getResourceValueToString(lwM2MClient, path);
751   - parameters.addProperty(resName, resValue);
  733 + LwM2mResource resourceValue = lwM2MClient != null ? getResourceValueFromLwM2MClient(lwM2MClient, pathIdVer) : null;
  734 + if (resourceValue != null) {
  735 + ResourceModel.Type currentType = resourceValue.getType();
  736 + ResourceModel.Type expectedType = this.lwM2mTransportContextServer.getResourceModelTypeEqualsKvProtoValueType(currentType, pathIdVer);
  737 + Object valueKvProto = null;
  738 + if (resourceValue.isMultiInstances()) {
  739 + valueKvProto = new JsonObject();
  740 + Object finalvalueKvProto = valueKvProto;
  741 + Gson gson = new GsonBuilder().create();
  742 + resourceValue.getValues().forEach((k, v) -> {
  743 + Object val = this.converter.convertValue(resourceValue.getValue(), currentType, expectedType,
  744 + new LwM2mPath(convertPathFromIdVerToObjectId(pathIdVer)));
  745 + JsonElement element = gson.toJsonTree(val, val.getClass());
  746 + ((JsonObject) finalvalueKvProto).add(String.valueOf(k), element);
  747 + });
  748 + valueKvProto = gson.toJson(valueKvProto);
  749 + } else {
  750 + valueKvProto = this.converter.convertValue(resourceValue.getValue(), currentType, expectedType,
  751 + new LwM2mPath(convertPathFromIdVerToObjectId(pathIdVer)));
  752 + }
  753 + return valueKvProto != null ? this.lwM2mTransportContextServer.getKvAttrTelemetryToThingsboard(currentType, resourceName, valueKvProto, resourceValue.isMultiInstances()) : null;
  754 + }
752 755 } catch (Exception e) {
753 756 log.error("Failed to add parameters.", e);
754 757 }
755 758 }
756 759 } else {
757   - log.error("Failed to add parameters. path: [{}], names: [{}]", path, names);
  760 + log.error("Failed to add parameters. path: [{}], names: [{}]", pathIdVer, names);
758 761 }
  762 + return null;
759 763 }
760 764
761 765 /**
762   - * @param path - path resource
763   - * @return - value of Resource or null
  766 + * @param pathIdVer - path resource
  767 + * @return - value of Resource into format KvProto or null
764 768 */
765   - private String getResourceValueToString(LwM2mClient lwM2MClient, String path) {
766   - LwM2mPath pathIds = new LwM2mPath(convertToObjectIdFromIdVer(path));
767   - LwM2mResource resourceValue = this.returnResourceValueFromLwM2MClient(lwM2MClient, path);
768   - return resourceValue == null ? null :
769   - this.converter.convertValue(resourceValue.isMultiInstances() ? resourceValue.getValues() : resourceValue.getValue(), resourceValue.getType(), ResourceModel.Type.STRING, pathIds).toString();
  769 + private Object getResourceValueFormatKv(LwM2mClient lwM2MClient, String pathIdVer) {
  770 + LwM2mResource resourceValue = this.getResourceValueFromLwM2MClient(lwM2MClient, pathIdVer);
  771 + ResourceModel.Type currentType = resourceValue.getType();
  772 + ResourceModel.Type expectedType = this.lwM2mTransportContextServer.getResourceModelTypeEqualsKvProtoValueType(currentType, pathIdVer);
  773 + return this.converter.convertValue(resourceValue.getValue(), currentType, expectedType,
  774 + new LwM2mPath(convertPathFromIdVerToObjectId(pathIdVer)));
770 775 }
771 776
772 777 /**
... ... @@ -774,9 +779,9 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
774 779 * @param path -
775 780 * @return - return value of Resource by idPath
776 781 */
777   - private LwM2mResource returnResourceValueFromLwM2MClient(LwM2mClient lwM2MClient, String path) {
  782 + private LwM2mResource getResourceValueFromLwM2MClient(LwM2mClient lwM2MClient, String path) {
778 783 LwM2mResource resourceValue = null;
779   - if (new LwM2mPath(convertToObjectIdFromIdVer(path)).isResource()) {
  784 + if (new LwM2mPath(convertPathFromIdVerToObjectId(path)).isResource()) {
780 785 resourceValue = lwM2MClient.getResources().get(path).getLwM2mResource();
781 786 }
782 787 return resourceValue;
... ... @@ -959,7 +964,7 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
959 964 */
960 965 private void readResourceValueObserve(Registration registration, Set<String> targets, String typeOper) {
961 966 targets.forEach(target -> {
962   - LwM2mPath pathIds = new LwM2mPath(convertToObjectIdFromIdVer(target));
  967 + LwM2mPath pathIds = new LwM2mPath(convertPathFromIdVerToObjectId(target));
963 968 if (pathIds.isResource()) {
964 969 if (GET_TYPE_OPER_READ.equals(typeOper)) {
965 970 lwM2mTransportRequest.sendAllRequest(registration, target, typeOper,
... ... @@ -1050,19 +1055,23 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
1050 1055 private void cancelObserveIsValue(Registration registration, Set<String> paramAnallyzer) {
1051 1056 LwM2mClient lwM2MClient = lwM2mClientContext.getLwM2mClientWithReg(registration, null);
1052 1057 paramAnallyzer.forEach(p -> {
1053   - if (this.returnResourceValueFromLwM2MClient(lwM2MClient, p) != null) {
1054   - this.setCancelObservationRecourse(registration, convertToObjectIdFromIdVer(p));
  1058 + if (this.getResourceValueFromLwM2MClient(lwM2MClient, p) != null) {
  1059 + this.setCancelObservationRecourse(registration, convertPathFromIdVerToObjectId(p));
1055 1060 }
1056 1061 }
1057 1062 );
1058 1063 }
1059 1064
1060   - private void putDelayedUpdateResourcesClient(LwM2mClient lwM2MClient, Object valueOld, Object valueNew, String path) {
  1065 + private void updateResourcesValueToClient(LwM2mClient lwM2MClient, Object valueOld, Object valueNew, String path) {
1061 1066 if (valueNew != null && (valueOld == null || !valueNew.toString().equals(valueOld.toString()))) {
1062 1067 lwM2mTransportRequest.sendAllRequest(lwM2MClient.getRegistration(), path, POST_TYPE_OPER_WRITE_REPLACE,
1063 1068 ContentFormat.TLV.getName(), null, valueNew, this.lwM2mTransportContextServer.getLwM2MTransportConfigServer().getTimeout());
1064 1069 } else {
1065   - log.error("05 delayError");
  1070 + log.error("Failed update resource [{}] [{}]", path, valueNew);
  1071 + String logMsg = String.format("%s: Failed update resource path - %s value - %s. Value is not changed or bad",
  1072 + LOG_LW2M_ERROR, path, valueNew);
  1073 + this.sendLogsToThingsboard(logMsg, lwM2MClient.getRegistration());
  1074 + log.info("Failed update resource [{}] [{}]", path, valueNew);
1066 1075 }
1067 1076 }
1068 1077
... ... @@ -1082,9 +1091,9 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
1082 1091 * @param name -
1083 1092 * @return path if path isPresent in postProfile
1084 1093 */
1085   - private String getPathAttributeUpdate(TransportProtos.SessionInfoProto sessionInfo, String name) {
1086   - String profilePath = this.getPathAttributeUpdateProfile(sessionInfo, name);
1087   - return !profilePath.isEmpty() ? profilePath : null;
  1094 + private String validatePathIntoProfile(TransportProtos.SessionInfoProto sessionInfo, String name) {
  1095 + String pathIdVer = this.getPresentPathIntoProfile(sessionInfo, name);
  1096 + return !pathIdVer.isEmpty() ? pathIdVer : null;
1088 1097 }
1089 1098
1090 1099 /**
... ... @@ -1094,7 +1103,7 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
1094 1103 * @param name -
1095 1104 * @return -
1096 1105 */
1097   - private String getPathAttributeUpdateProfile(TransportProtos.SessionInfoProto sessionInfo, String name) {
  1106 + private String getPresentPathIntoProfile(TransportProtos.SessionInfoProto sessionInfo, String name) {
1098 1107 LwM2mClientProfile profile = lwM2mClientContext.getProfile(new UUID(sessionInfo.getDeviceProfileIdMSB(), sessionInfo.getDeviceProfileIdLSB()));
1099 1108 LwM2mClient lwM2mClient = lwM2mClientContext.getLwM2MClient(sessionInfo);
1100 1109 return profile.getPostKeyNameProfile().getAsJsonObject().entrySet().stream()
... ... @@ -1105,41 +1114,50 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
1105 1114 /**
1106 1115 * Update resource value on client: if there is a difference in values between the current resource values and the shared attribute values
1107 1116 * #1 Get path resource by result attributesResponse
1108   - * #1.1 If two names have equal path => last time attribute
1109   - * #2.1 if there is a difference in values between the current resource values and the shared attribute values
1110   - * => send to client Request Update of value (new value from shared attribute)
1111   - * and LwM2MClient.delayedRequests.add(path)
1112   - * #2.1 if there is not a difference in values between the current resource values and the shared attribute values
1113 1117 *
1114 1118 * @param attributesResponse -
1115 1119 * @param sessionInfo -
1116 1120 */
1117 1121 public void onGetAttributesResponse(TransportProtos.GetAttributeResponseMsg attributesResponse, TransportProtos.SessionInfoProto sessionInfo) {
1118 1122 try {
1119   - LwM2mClient lwM2MClient = lwM2mClientContext.getLwM2MClient(sessionInfo);
1120   - attributesResponse.getSharedAttributeListList().forEach(attr -> {
1121   - String path = this.getPathAttributeUpdate(sessionInfo, attr.getKv().getKey());
1122   - if (path != null) {
1123   - // #1.1
1124   - if (lwM2MClient.getDelayedRequests().containsKey(path) && attr.getTs() > lwM2MClient.getDelayedRequests().get(path).getTs()) {
1125   - lwM2MClient.getDelayedRequests().put(path, attr);
1126   - } else {
1127   - lwM2MClient.getDelayedRequests().put(path, attr);
1128   - }
1129   - }
1130   - });
1131   - // #2.1
1132   - lwM2MClient.getDelayedRequests().forEach((k, v) -> {
1133   - ArrayList<TransportProtos.KeyValueProto> listV = new ArrayList<>();
1134   - listV.add(v.getKv());
1135   - this.putDelayedUpdateResourcesClient(lwM2MClient, this.getResourceValueToString(lwM2MClient, k), getJsonObject(listV).get(v.getKv().getKey()), k);
1136   - });
  1123 + List<TransportProtos.TsKvProto> tsKvProtos = attributesResponse.getSharedAttributeListList();
  1124 + this.updateAttriuteFromThingsboard(tsKvProtos, sessionInfo);
1137 1125 } catch (Exception e) {
1138 1126 log.error(String.valueOf(e));
1139 1127 }
1140 1128 }
1141 1129
1142 1130 /**
  1131 + * #1.1 If two names have equal path => last time attribute
  1132 + * #2.1 if there is a difference in values between the current resource values and the shared attribute values
  1133 + * => send to client Request Update of value (new value from shared attribute)
  1134 + * and LwM2MClient.delayedRequests.add(path)
  1135 + * #2.1 if there is not a difference in values between the current resource values and the shared attribute values
  1136 + *
  1137 + * @param tsKvProtos
  1138 + * @param sessionInfo
  1139 + */
  1140 + public void updateAttriuteFromThingsboard(List<TransportProtos.TsKvProto> tsKvProtos, TransportProtos.SessionInfoProto sessionInfo) {
  1141 + LwM2mClient lwM2MClient = lwM2mClientContext.getLwM2MClient(sessionInfo);
  1142 + tsKvProtos.forEach(tsKvProto -> {
  1143 + String pathIdVer = this.validatePathIntoProfile(sessionInfo, tsKvProto.getKv().getKey());
  1144 + if (pathIdVer != null) {
  1145 + // #1.1
  1146 + if (lwM2MClient.getDelayedRequests().containsKey(pathIdVer) && tsKvProto.getTs() > lwM2MClient.getDelayedRequests().get(pathIdVer).getTs()) {
  1147 + lwM2MClient.getDelayedRequests().put(pathIdVer, tsKvProto);
  1148 + } else if (!lwM2MClient.getDelayedRequests().containsKey(pathIdVer)) {
  1149 + lwM2MClient.getDelayedRequests().put(pathIdVer, tsKvProto);
  1150 + }
  1151 + }
  1152 + });
  1153 + // #2.1
  1154 + lwM2MClient.getDelayedRequests().forEach((pathIdVer, tsKvProto) -> {
  1155 + this.updateResourcesValueToClient(lwM2MClient, this.getResourceValueFormatKv(lwM2MClient, pathIdVer),
  1156 + this.lwM2mTransportContextServer.getValueFromKvProto(tsKvProto.getKv()), pathIdVer);
  1157 + });
  1158 + }
  1159 +
  1160 + /**
1143 1161 * @param lwM2MClient -
1144 1162 * @return SessionInfoProto -
1145 1163 */
... ... @@ -1257,7 +1275,7 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
1257 1275
1258 1276 private boolean validateResourceInModel(LwM2mClient lwM2mClient, String pathIdVer, boolean isWritableNotOptional) {
1259 1277 ResourceModel resourceModel = lwM2mClient.getResourceModel(pathIdVer);
1260   - Integer objectId = new LwM2mPath(convertToObjectIdFromIdVer(pathIdVer)).getObjectId();
  1278 + Integer objectId = new LwM2mPath(convertPathFromIdVerToObjectId(pathIdVer)).getObjectId();
1261 1279 String objectVer = validateObjectVerFromKey(pathIdVer);
1262 1280 return resourceModel != null && (isWritableNotOptional ?
1263 1281 objectId != null && objectVer != null && objectVer.equals(lwM2mClient.getRegistration().getSupportedVersion(objectId)) && resourceModel.operations.isWritable() :
... ...
... ... @@ -39,7 +39,7 @@ import java.util.concurrent.CopyOnWriteArrayList;
39 39 import java.util.stream.Collectors;
40 40
41 41 import static org.thingsboard.server.common.data.lwm2m.LwM2mConstants.LWM2M_SEPARATOR_PATH;
42   -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.convertToObjectIdFromIdVer;
  42 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.convertPathFromIdVerToObjectId;
43 43
44 44 @Slf4j
45 45 @Data
... ... @@ -83,7 +83,7 @@ public class LwM2mClient implements Cloneable {
83 83 this.resources.get(pathRez).setLwM2mResource(rez);
84 84 return true;
85 85 } else {
86   - LwM2mPath pathIds = new LwM2mPath(convertToObjectIdFromIdVer(pathRez));
  86 + LwM2mPath pathIds = new LwM2mPath(convertPathFromIdVerToObjectId(pathRez));
87 87 ResourceModel resourceModel = modelProvider.getObjectModel(registration).getResourceModel(pathIds.getObjectId(), pathIds.getResourceId());
88 88 if (resourceModel != null) {
89 89 this.resources.put(pathRez, new ResourceValue(rez, resourceModel));
... ... @@ -110,7 +110,7 @@ public class LwM2mClient implements Cloneable {
110 110 public void deleteResources(String pathIdVer, LwM2mModelProvider modelProvider) {
111 111 Set<String> key = getKeysEqualsIdVer(pathIdVer);
112 112 key.forEach(pathRez -> {
113   - LwM2mPath pathIds = new LwM2mPath(convertToObjectIdFromIdVer(pathRez));
  113 + LwM2mPath pathIds = new LwM2mPath(convertPathFromIdVerToObjectId(pathRez));
114 114 ResourceModel resourceModel = modelProvider.getObjectModel(registration).getResourceModel(pathIds.getObjectId(), pathIds.getResourceId());
115 115 if (resourceModel != null) {
116 116 this.resources.get(pathRez).setResourceModel(resourceModel);
... ... @@ -132,7 +132,7 @@ public class LwM2mClient implements Cloneable {
132 132 }
133 133
134 134 private void saveResourceModel(String pathRez, LwM2mModelProvider modelProvider) {
135   - LwM2mPath pathIds = new LwM2mPath(convertToObjectIdFromIdVer(pathRez));
  135 + LwM2mPath pathIds = new LwM2mPath(convertPathFromIdVerToObjectId(pathRez));
136 136 ResourceModel resourceModel = modelProvider.getObjectModel(registration).getResourceModel(pathIds.getObjectId(), pathIds.getResourceId());
137 137 this.resources.get(pathRez).setResourceModel(resourceModel);
138 138 }
... ...
... ... @@ -35,7 +35,7 @@ import java.util.UUID;
35 35 import java.util.concurrent.ConcurrentHashMap;
36 36
37 37 import static org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode.NO_SEC;
38   -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.convertToIdVerFromObjectId;
  38 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.convertPathFromObjectIdToIdVer;
39 39
40 40 @Service
41 41 @TbLwM2mTransportComponent
... ... @@ -185,7 +185,7 @@ public class LwM2mClientContextImpl implements LwM2mClientContext {
185 185 Arrays.stream(registration.getObjectLinks()).forEach(url -> {
186 186 LwM2mPath pathIds = new LwM2mPath(url.getUrl());
187 187 if (!pathIds.isRoot()) {
188   - clientObjects.add(convertToIdVerFromObjectId(url.getUrl(), registration));
  188 + clientObjects.add(convertPathFromObjectIdToIdVer(url.getUrl(), registration));
189 189 }
190 190 });
191 191 return (clientObjects.size() > 0) ? clientObjects : null;
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.transport.lwm2m.server.client;
  17 +
  18 +import lombok.Data;
  19 +import org.thingsboard.server.gen.transport.TransportProtos;
  20 +
  21 +import java.util.ArrayList;
  22 +import java.util.List;
  23 +
  24 +@Data
  25 +public class ResultsAddKeyValueProto {
  26 + List<TransportProtos.KeyValueProto> resultAttributes;
  27 + List<TransportProtos.KeyValueProto> resultTelemetries;
  28 +
  29 + public ResultsAddKeyValueProto() {
  30 + this.resultAttributes = new ArrayList<>();
  31 + this.resultTelemetries = new ArrayList<>();
  32 + }
  33 +
  34 +}
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.transport.lwm2m.server.client;
  17 +
  18 +import lombok.Data;
  19 +import org.thingsboard.server.common.data.kv.DataType;
  20 +
  21 +@Data
  22 +public class ResultsResourceValue {
  23 + DataType dataType;
  24 + Object value;
  25 + String resourceName;
  26 +
  27 + public ResultsResourceValue (DataType dataType, Object value, String resourceName) {
  28 + this.dataType = dataType;
  29 + this.value = value;
  30 + this.resourceName = resourceName;
  31 + }
  32 +}
... ...
... ... @@ -18,14 +18,12 @@ package org.thingsboard.server.transport.lwm2m.utils;
18 18 import lombok.extern.slf4j.Slf4j;
19 19 import org.eclipse.leshan.core.model.ResourceModel.Type;
20 20 import org.eclipse.leshan.core.node.LwM2mPath;
  21 +import org.eclipse.leshan.core.node.ObjectLink;
21 22 import org.eclipse.leshan.core.node.codec.CodecException;
22 23 import org.eclipse.leshan.core.node.codec.LwM2mValueConverter;
23 24 import org.eclipse.leshan.core.util.Hex;
24 25 import org.eclipse.leshan.core.util.StringUtils;
25 26
26   -import javax.xml.datatype.DatatypeConfigurationException;
27   -import javax.xml.datatype.DatatypeFactory;
28   -import javax.xml.datatype.XMLGregorianCalendar;
29 27 import java.math.BigInteger;
30 28 import java.text.DateFormat;
31 29 import java.text.SimpleDateFormat;
... ... @@ -111,15 +109,16 @@ public class LwM2mValueConverterImpl implements LwM2mValueConverter {
111 109 case INTEGER:
112 110 log.debug("Trying to convert long value {} to date", value);
113 111 /** let's assume we received the millisecond since 1970/1/1 */
114   - return new Date((Long) value);
  112 + return new Date(((Number) value).longValue() * 1000L);
115 113 case STRING:
116 114 log.debug("Trying to convert string value {} to date", value);
117 115 /** let's assume we received an ISO 8601 format date */
118 116 try {
119   - DatatypeFactory datatypeFactory = DatatypeFactory.newInstance();
120   - XMLGregorianCalendar cal = datatypeFactory.newXMLGregorianCalendar((String) value);
121   - return cal.toGregorianCalendar().getTime();
122   - } catch (DatatypeConfigurationException | IllegalArgumentException e) {
  117 + return new Date(Long.decode(value.toString()));
  118 +// DatatypeFactory datatypeFactory = DatatypeFactory.newInstance();
  119 +// XMLGregorianCalendar cal = datatypeFactory.newXMLGregorianCalendar((String) value);
  120 +// return cal.toGregorianCalendar().getTime();
  121 + } catch (IllegalArgumentException e) {
123 122 log.debug("Unable to convert string to date", e);
124 123 throw new CodecException("Unable to convert string (%s) to date for resource %s", value,
125 124 resourcePath);
... ... @@ -147,6 +146,8 @@ public class LwM2mValueConverterImpl implements LwM2mValueConverter {
147 146 return formatter.format(new Date(timeValue));
148 147 case OPAQUE:
149 148 return Hex.encodeHexString((byte[])value);
  149 + case OBJLNK:
  150 + return ObjectLink.decodeFromString((String) value);
150 151 default:
151 152 break;
152 153 }
... ... @@ -164,10 +165,14 @@ public class LwM2mValueConverterImpl implements LwM2mValueConverter {
164 165 }
165 166 }
166 167 break;
  168 + case OBJLNK:
  169 + if (currentType == Type.STRING) {
  170 + return ObjectLink.fromPath(value.toString());
  171 + }
167 172 default:
168 173 }
169 174
170 175 throw new CodecException("Invalid value type for resource %s, expected %s, got %s", resourcePath, expectedType,
171 176 currentType);
172 177 }
173   -}
  178 + }
... ...
... ... @@ -119,6 +119,18 @@ redis:
119 119
120 120 # LWM2M server parameters
121 121 transport:
  122 + sessions:
  123 + inactivity_timeout: "${TB_TRANSPORT_SESSIONS_INACTIVITY_TIMEOUT:300000}"
  124 + report_timeout: "${TB_TRANSPORT_SESSIONS_REPORT_TIMEOUT:30000}"
  125 + json:
  126 + # Cast String data types to Numeric if possible when processing Telemetry/Attributes JSON
  127 + type_cast_enabled: "${JSON_TYPE_CAST_ENABLED:false}"
  128 + # Maximum allowed string value length when processing Telemetry/Attributes JSON (0 value disables string value length check)
  129 + max_string_value_length: "${JSON_MAX_STRING_VALUE_LENGTH:0}"
  130 + client_side_rpc:
  131 + timeout: "${CLIENT_SIDE_RPC_TIMEOUT:60000}"
  132 + # Enable/disable http/mqtt/coap transport protocols (has higher priority than certain protocol's 'enabled' property)
  133 + api_enabled: "${TB_TRANSPORT_API_ENABLED:true}"
122 134 # Local LwM2M transport parameters
123 135 lwm2m:
124 136 # Enable/disable lvm2m transport protocol.
... ... @@ -180,15 +192,6 @@ transport:
180 192 # Use redis for Security and Registration stores
181 193 redis.enabled: "${LWM2M_REDIS_ENABLED:false}"
182 194
183   - sessions:
184   - inactivity_timeout: "${TB_TRANSPORT_SESSIONS_INACTIVITY_TIMEOUT:300000}"
185   - report_timeout: "${TB_TRANSPORT_SESSIONS_REPORT_TIMEOUT:30000}"
186   - json:
187   - # Cast String data types to Numeric if possible when processing Telemetry/Attributes JSON
188   - type_cast_enabled: "${JSON_TYPE_CAST_ENABLED:true}"
189   - # Maximum allowed string value length when processing Telemetry/Attributes JSON (0 value disables string value length check)
190   - max_string_value_length: "${JSON_MAX_STRING_VALUE_LENGTH:0}"
191   -
192 195 queue:
193 196 type: "${TB_QUEUE_TYPE:kafka}" # kafka (Apache Kafka) or aws-sqs (AWS SQS) or pubsub (PubSub) or service-bus (Azure Service Bus) or rabbitmq (RabbitMQ)
194 197 kafka:
... ...
... ... @@ -82,8 +82,6 @@
82 82 <strong>{{ 'device-profile.lwm2m.required' | translate }}</strong>
83 83 </mat-error>
84 84 </mat-form-field>
85   - </div>
86   - <div fxLayout="row" fxLayoutGap="8px">
87 85 <mat-form-field fxFlex>
88 86 <mat-label>{{ 'device-profile.lwm2m.default-min-period' | translate }}</mat-label>
89 87 <input matInput type="number" formControlName="defaultMinPeriod" required>
... ... @@ -93,13 +91,16 @@
93 91 <strong>{{ 'device-profile.lwm2m.required' | translate }}</strong>
94 92 </mat-error>
95 93 </mat-form-field>
96   - <mat-form-field fxFlex>
  94 + </div>
  95 + <div fxLayout="row" fxLayoutGap="8px">
  96 + <mat-form-field class="mat-block" fxFlex="100">
97 97 <mat-label>{{ 'device-profile.lwm2m.binding' | translate }}</mat-label>
98   - <input matInput type="text" formControlName="binding" required>
99   - <mat-error *ngIf="lwm2mDeviceProfileFormGroup.get('binding').hasError('required')">
100   - {{ 'device-profile.lwm2m.binding' | translate }}
101   - <strong>{{ 'device-profile.lwm2m.required' | translate }}</strong>
102   - </mat-error>
  98 + <mat-select formControlName="binding">
  99 + <mat-option *ngFor="let bindingMode of bindingModeTypes"
  100 + [value]="bindingMode">
  101 + {{ bindingModeTypeNamesMap.get(bindingModeType[bindingMode]) }}
  102 + </mat-option>
  103 + </mat-select>
103 104 </mat-form-field>
104 105 </div>
105 106 <div>
... ...
... ... @@ -22,7 +22,8 @@ import { AppState } from '@app/core/core.state';
22 22 import { coerceBooleanProperty } from '@angular/cdk/coercion';
23 23 import {
24 24 ATTRIBUTE,
25   - DEFAULT_BINDING,
  25 + BINDING_MODE,
  26 + BINDING_MODE_NAMES,
26 27 getDefaultProfileConfig,
27 28 INSTANCES,
28 29 KEY_NAME,
... ... @@ -55,6 +56,9 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro
55 56 private requiredValue: boolean;
56 57 private disabled = false;
57 58
  59 + bindingModeType = BINDING_MODE;
  60 + bindingModeTypes = Object.keys(BINDING_MODE);
  61 + bindingModeTypeNamesMap = BINDING_MODE_NAMES;
58 62 lwm2mDeviceProfileFormGroup: FormGroup;
59 63 lwm2mDeviceConfigFormGroup: FormGroup;
60 64 bootstrapServers: string;
... ... @@ -86,7 +90,7 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro
86 90 lifetime: [null, Validators.required],
87 91 defaultMinPeriod: [null, Validators.required],
88 92 notifIfDisabled: [true, []],
89   - binding: [DEFAULT_BINDING, Validators.required],
  93 + binding:[],
90 94 bootstrapServer: [null, Validators.required],
91 95 lwm2mServer: [null, Validators.required],
92 96 });
... ...
... ... @@ -44,6 +44,35 @@ export const KEY_REGEXP_NUMBER = /^(\-?|\+?)\d*$/;
44 44 export const INSTANCES_ID_VALUE_MIN = 0;
45 45 export const INSTANCES_ID_VALUE_MAX = 65535;
46 46
  47 +
  48 +export enum BINDING_MODE {
  49 + U = 'U',
  50 + UQ = 'UQ',
  51 + T = 'T',
  52 + TQ = 'TQ',
  53 + S = 'S',
  54 + SQ = 'SQ',
  55 + US = 'US',
  56 + TS = 'TS',
  57 + UQS = 'UQS',
  58 + TQS = 'TQS'
  59 +}
  60 +
  61 +export const BINDING_MODE_NAMES = new Map<BINDING_MODE, string>(
  62 + [
  63 + [BINDING_MODE.U, 'U: UDP connection in standard mode'],
  64 + [BINDING_MODE.UQ, 'UQ: UDP connection in queue mode'],
  65 + [BINDING_MODE.US, 'US: both UDP and SMS connections active, both in standard mode'],
  66 + [BINDING_MODE.UQS, 'UQS: both UDP and SMS connections active; UDP in queue mode, SMS in standard mode'],
  67 + [BINDING_MODE.T,'T: TCP connection in standard mode'],
  68 + [BINDING_MODE.TQ, 'TQ: TCP connection in queue mode'],
  69 + [BINDING_MODE.TS, 'TS: both TCP and SMS connections active, both in standard mode'],
  70 + [BINDING_MODE.TQS, 'TQS: both TCP and SMS connections active; TCP in queue mode, SMS in standard mode'],
  71 + [BINDING_MODE.S, 'S: SMS connection in standard mode'],
  72 + [BINDING_MODE.SQ, 'SQ: SMS connection in queue mode']
  73 + ]
  74 +);
  75 +
47 76 export enum ATTRIBUTE_LWM2M_ENUM {
48 77 dim = 'dim',
49 78 ver = 'ver',
... ... @@ -62,8 +91,7 @@ export const ATTRIBUTE_LWM2M_LABEL = new Map<ATTRIBUTE_LWM2M_ENUM, string>(
62 91 [ATTRIBUTE_LWM2M_ENUM.pmax, 'pmax='],
63 92 [ATTRIBUTE_LWM2M_ENUM.gt, '>'],
64 93 [ATTRIBUTE_LWM2M_ENUM.lt, '<'],
65   - [ATTRIBUTE_LWM2M_ENUM.st, 'st='],
66   -
  94 + [ATTRIBUTE_LWM2M_ENUM.st, 'st=']
67 95 ]
68 96 );
69 97
... ...