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,7 +35,6 @@ import org.thingsboard.server.transport.lwm2m.secure.LwM2mCredentialsSecurityInf
35 import org.thingsboard.server.transport.lwm2m.secure.ReadResultSecurityStore; 35 import org.thingsboard.server.transport.lwm2m.secure.ReadResultSecurityStore;
36 import org.thingsboard.server.transport.lwm2m.server.LwM2mSessionMsgListener; 36 import org.thingsboard.server.transport.lwm2m.server.LwM2mSessionMsgListener;
37 import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportContextServer; 37 import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportContextServer;
38 -import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler;  
39 import org.thingsboard.server.transport.lwm2m.utils.TypeServer; 38 import org.thingsboard.server.transport.lwm2m.utils.TypeServer;
40 39
41 import java.io.IOException; 40 import java.io.IOException;
@@ -165,13 +164,13 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore { @@ -165,13 +164,13 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore {
165 lwM2MBootstrapConfig.bootstrapServer = new LwM2MServerBootstrap(lwM2MBootstrapConfig.bootstrapServer, profileServerBootstrap); 164 lwM2MBootstrapConfig.bootstrapServer = new LwM2MServerBootstrap(lwM2MBootstrapConfig.bootstrapServer, profileServerBootstrap);
166 lwM2MBootstrapConfig.lwm2mServer = new LwM2MServerBootstrap(lwM2MBootstrapConfig.lwm2mServer, profileLwm2mServer); 165 lwM2MBootstrapConfig.lwm2mServer = new LwM2MServerBootstrap(lwM2MBootstrapConfig.lwm2mServer, profileLwm2mServer);
167 String logMsg = String.format("%s: getParametersBootstrap: %s Access connect client with bootstrap server.", LOG_LW2M_INFO, store.getEndPoint()); 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 return lwM2MBootstrapConfig; 168 return lwM2MBootstrapConfig;
170 } else { 169 } else {
171 log.error(" [{}] Different values SecurityMode between of client and profile.", store.getEndPoint()); 170 log.error(" [{}] Different values SecurityMode between of client and profile.", store.getEndPoint());
172 log.error("{} getParametersBootstrap: [{}] Different values SecurityMode between of client and profile.", LOG_LW2M_ERROR, store.getEndPoint()); 171 log.error("{} getParametersBootstrap: [{}] Different values SecurityMode between of client and profile.", LOG_LW2M_ERROR, store.getEndPoint());
173 String logMsg = String.format("%s: getParametersBootstrap: %s Different values SecurityMode between of client and profile.", LOG_LW2M_ERROR, store.getEndPoint()); 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 return null; 174 return null;
176 } 175 }
177 } 176 }
@@ -26,7 +26,7 @@ import org.eclipse.leshan.server.registration.RegistrationUpdate; @@ -26,7 +26,7 @@ import org.eclipse.leshan.server.registration.RegistrationUpdate;
26 26
27 import java.util.Collection; 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 @Slf4j 31 @Slf4j
32 public class LwM2mServerListener { 32 public class LwM2mServerListener {
@@ -92,7 +92,7 @@ public class LwM2mServerListener { @@ -92,7 +92,7 @@ public class LwM2mServerListener {
92 public void onResponse(Observation observation, Registration registration, ObserveResponse response) { 92 public void onResponse(Observation observation, Registration registration, ObserveResponse response) {
93 if (registration != null) { 93 if (registration != null) {
94 try { 94 try {
95 - service.onObservationResponse(registration, convertToIdVerFromObjectId(observation.getPath().toString(), registration), response); 95 + service.onObservationResponse(registration, convertPathFromObjectIdToIdVer(observation.getPath().toString(), registration), response);
96 } catch (Exception e) { 96 } catch (Exception e) {
97 log.error("[{}] onResponse", e.toString()); 97 log.error("[{}] onResponse", e.toString());
98 98
@@ -107,7 +107,7 @@ public class LwM2mServerListener { @@ -107,7 +107,7 @@ public class LwM2mServerListener {
107 107
108 @Override 108 @Override
109 public void newObservation(Observation observation, Registration registration) { 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,31 +30,33 @@ package org.thingsboard.server.transport.lwm2m.server;
30 * limitations under the License. 30 * limitations under the License.
31 */ 31 */
32 32
33 -import com.google.gson.JsonElement;  
34 -import com.google.gson.JsonObject;  
35 import lombok.Getter; 33 import lombok.Getter;
36 import lombok.extern.slf4j.Slf4j; 34 import lombok.extern.slf4j.Slf4j;
37 import org.eclipse.leshan.core.model.DDFFileParser; 35 import org.eclipse.leshan.core.model.DDFFileParser;
38 import org.eclipse.leshan.core.model.DefaultDDFFileValidator; 36 import org.eclipse.leshan.core.model.DefaultDDFFileValidator;
39 import org.eclipse.leshan.core.model.InvalidDDFFileException; 37 import org.eclipse.leshan.core.model.InvalidDDFFileException;
40 import org.eclipse.leshan.core.model.ObjectModel; 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 import org.springframework.stereotype.Component; 41 import org.springframework.stereotype.Component;
42 import org.thingsboard.server.common.transport.TransportContext; 42 import org.thingsboard.server.common.transport.TransportContext;
43 import org.thingsboard.server.common.transport.TransportResourceCache; 43 import org.thingsboard.server.common.transport.TransportResourceCache;
44 import org.thingsboard.server.common.transport.TransportService; 44 import org.thingsboard.server.common.transport.TransportService;
45 import org.thingsboard.server.common.transport.TransportServiceCallback; 45 import org.thingsboard.server.common.transport.TransportServiceCallback;
46 -import org.thingsboard.server.common.transport.adaptor.AdaptorException;  
47 import org.thingsboard.server.common.transport.lwm2m.LwM2MTransportConfigServer; 46 import org.thingsboard.server.common.transport.lwm2m.LwM2MTransportConfigServer;
  47 +import org.thingsboard.server.gen.transport.TransportProtos;
48 import org.thingsboard.server.gen.transport.TransportProtos.PostAttributeMsg; 48 import org.thingsboard.server.gen.transport.TransportProtos.PostAttributeMsg;
49 import org.thingsboard.server.gen.transport.TransportProtos.PostTelemetryMsg; 49 import org.thingsboard.server.gen.transport.TransportProtos.PostTelemetryMsg;
50 import org.thingsboard.server.gen.transport.TransportProtos.SessionInfoProto; 50 import org.thingsboard.server.gen.transport.TransportProtos.SessionInfoProto;
51 -import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceCredentialsResponseMsg;  
52 import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; 51 import org.thingsboard.server.queue.util.TbLwM2mTransportComponent;
53 import org.thingsboard.server.transport.lwm2m.server.adaptors.LwM2MJsonAdaptor; 52 import org.thingsboard.server.transport.lwm2m.server.adaptors.LwM2MJsonAdaptor;
54 53
55 import java.io.ByteArrayInputStream; 54 import java.io.ByteArrayInputStream;
56 import java.io.IOException; 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 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.LOG_LW2M_TELEMETRY; 60 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.LOG_LW2M_TELEMETRY;
59 61
60 @Slf4j 62 @Slf4j
@@ -91,7 +93,7 @@ public class LwM2mTransportContextServer extends TransportContext { @@ -91,7 +93,7 @@ public class LwM2mTransportContextServer extends TransportContext {
91 /** 93 /**
92 * send to Thingsboard Attribute || Telemetry 94 * send to Thingsboard Attribute || Telemetry
93 * 95 *
94 - * @param msg - JsonObject: [{name: value}] 96 + * @param msg - JsonObject: [{name: value}]
95 * @return - dummy 97 * @return - dummy
96 */ 98 */
97 private <T> TransportServiceCallback<Void> getPubAckCallbackSendAttrTelemetry(final T msg) { 99 private <T> TransportServiceCallback<Void> getPubAckCallbackSendAttrTelemetry(final T msg) {
@@ -108,33 +110,29 @@ public class LwM2mTransportContextServer extends TransportContext { @@ -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 * @return - sessionInfo after access connect client 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 return SessionInfoProto.newBuilder() 136 return SessionInfoProto.newBuilder()
139 .setNodeId(this.getNodeId()) 137 .setNodeId(this.getNodeId())
140 .setSessionIdMSB(mostSignificantBits) 138 .setSessionIdMSB(mostSignificantBits)
@@ -159,4 +157,90 @@ public class LwM2mTransportContextServer extends TransportContext { @@ -159,4 +157,90 @@ public class LwM2mTransportContextServer extends TransportContext {
159 return null; 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,6 +75,8 @@ public class LwM2mTransportHandler {
75 public static final String KEY_NAME = "keyName"; 75 public static final String KEY_NAME = "keyName";
76 public static final String OBSERVE = "observe"; 76 public static final String OBSERVE = "observe";
77 public static final String ATTRIBUTE_LWM2M = "attributeLwm2m"; 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 private static final String REQUEST = "/request"; 81 private static final String REQUEST = "/request";
80 private static final String RESPONSE = "/response"; 82 private static final String RESPONSE = "/response";
@@ -333,28 +335,30 @@ public class LwM2mTransportHandler { @@ -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 try { 339 try {
338 - String[] keyArray = key.split(LWM2M_SEPARATOR_PATH); 340 + String[] keyArray = pathIdVer.split(LWM2M_SEPARATOR_PATH);
339 if (keyArray.length > 1 && keyArray[1].split(LWM2M_SEPARATOR_KEY).length == 2) { 341 if (keyArray.length > 1 && keyArray[1].split(LWM2M_SEPARATOR_KEY).length == 2) {
340 keyArray[1] = keyArray[1].split(LWM2M_SEPARATOR_KEY)[0]; 342 keyArray[1] = keyArray[1].split(LWM2M_SEPARATOR_KEY)[0];
341 return StringUtils.join(keyArray, LWM2M_SEPARATOR_PATH); 343 return StringUtils.join(keyArray, LWM2M_SEPARATOR_PATH);
342 - } else {  
343 - return key; 344 + }
  345 + else {
  346 + return pathIdVer;
344 } 347 }
345 } catch (Exception e) { 348 } catch (Exception e) {
346 return null; 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 String ver = registration.getSupportedObject().get(new LwM2mPath(path).getObjectId()); 354 String ver = registration.getSupportedObject().get(new LwM2mPath(path).getObjectId());
352 try { 355 try {
353 String[] keyArray = path.split(LWM2M_SEPARATOR_PATH); 356 String[] keyArray = path.split(LWM2M_SEPARATOR_PATH);
354 if (keyArray.length > 1) { 357 if (keyArray.length > 1) {
355 keyArray[1] = keyArray[1] + LWM2M_SEPARATOR_KEY + ver; 358 keyArray[1] = keyArray[1] + LWM2M_SEPARATOR_KEY + ver;
356 return StringUtils.join(keyArray, LWM2M_SEPARATOR_PATH); 359 return StringUtils.join(keyArray, LWM2M_SEPARATOR_PATH);
357 - } else { 360 + }
  361 + else {
358 return path; 362 return path;
359 } 363 }
360 } catch (Exception e) { 364 } catch (Exception e) {
@@ -69,8 +69,8 @@ import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandle @@ -69,8 +69,8 @@ import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandle
69 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.PUT_TYPE_OPER_WRITE_ATTRIBUTES; 69 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.PUT_TYPE_OPER_WRITE_ATTRIBUTES;
70 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.PUT_TYPE_OPER_WRITE_UPDATE; 70 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.PUT_TYPE_OPER_WRITE_UPDATE;
71 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.RESPONSE_CHANNEL; 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 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.createWriteAttributeRequest; 74 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.createWriteAttributeRequest;
75 75
76 @Slf4j 76 @Slf4j
@@ -114,7 +114,7 @@ public class LwM2mTransportRequest { @@ -114,7 +114,7 @@ public class LwM2mTransportRequest {
114 */ 114 */
115 public void sendAllRequest(Registration registration, String targetIdVer, String typeOper, 115 public void sendAllRequest(Registration registration, String targetIdVer, String typeOper,
116 String contentFormatParam, Observation observation, Object params, long timeoutInMs) { 116 String contentFormatParam, Observation observation, Object params, long timeoutInMs) {
117 - String target = convertToObjectIdFromIdVer(targetIdVer); 117 + String target = convertPathFromIdVerToObjectId(targetIdVer);
118 LwM2mPath resultIds = new LwM2mPath(target); 118 LwM2mPath resultIds = new LwM2mPath(target);
119 if (registration != null && resultIds.getObjectId() >= 0) { 119 if (registration != null && resultIds.getObjectId() >= 0) {
120 DownlinkRequest request = null; 120 DownlinkRequest request = null;
@@ -204,7 +204,7 @@ public class LwM2mTransportRequest { @@ -204,7 +204,7 @@ public class LwM2mTransportRequest {
204 private void sendRequest(Registration registration, LwM2mClient lwM2MClient, DownlinkRequest request, long timeoutInMs) { 204 private void sendRequest(Registration registration, LwM2mClient lwM2MClient, DownlinkRequest request, long timeoutInMs) {
205 leshanServer.send(registration, request, timeoutInMs, (ResponseCallback<?>) response -> { 205 leshanServer.send(registration, request, timeoutInMs, (ResponseCallback<?>) response -> {
206 if (!lwM2MClient.isInit()) { 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 if (CoAP.ResponseCode.isSuccess(((Response) response.getCoapResponse()).getCode())) { 209 if (CoAP.ResponseCode.isSuccess(((Response) response.getCoapResponse()).getCode())) {
210 this.handleResponse(registration, request.getPath().toString(), response, request); 210 this.handleResponse(registration, request.getPath().toString(), response, request);
@@ -228,7 +228,7 @@ public class LwM2mTransportRequest { @@ -228,7 +228,7 @@ public class LwM2mTransportRequest {
228 } 228 }
229 }, e -> { 229 }, e -> {
230 if (!lwM2MClient.isInit()) { 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 String msg = String.format("%s: sendRequest: Resource path - %s msg error - %s SendRequest to Client", 233 String msg = String.format("%s: sendRequest: Resource path - %s msg error - %s SendRequest to Client",
234 LOG_LW2M_ERROR, request.getPath().toString(), e.toString()); 234 LOG_LW2M_ERROR, request.getPath().toString(), e.toString());
@@ -287,7 +287,7 @@ public class LwM2mTransportRequest { @@ -287,7 +287,7 @@ public class LwM2mTransportRequest {
287 * @param response - 287 * @param response -
288 */ 288 */
289 private void sendResponse(Registration registration, String path, LwM2mResponse response, DownlinkRequest request) { 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 if (response instanceof ReadResponse) { 291 if (response instanceof ReadResponse) {
292 serviceImpl.onObservationResponse(registration, pathIdVer, (ReadResponse) response); 292 serviceImpl.onObservationResponse(registration, pathIdVer, (ReadResponse) response);
293 } else if (response instanceof CancelObservationResponse) { 293 } else if (response instanceof CancelObservationResponse) {
@@ -18,6 +18,7 @@ package org.thingsboard.server.transport.lwm2m.server; @@ -18,6 +18,7 @@ package org.thingsboard.server.transport.lwm2m.server;
18 import com.fasterxml.jackson.core.type.TypeReference; 18 import com.fasterxml.jackson.core.type.TypeReference;
19 import com.google.common.collect.Sets; 19 import com.google.common.collect.Sets;
20 import com.google.gson.Gson; 20 import com.google.gson.Gson;
  21 +import com.google.gson.GsonBuilder;
21 import com.google.gson.JsonArray; 22 import com.google.gson.JsonArray;
22 import com.google.gson.JsonElement; 23 import com.google.gson.JsonElement;
23 import com.google.gson.JsonObject; 24 import com.google.gson.JsonObject;
@@ -42,7 +43,6 @@ import org.thingsboard.server.common.data.Device; @@ -42,7 +43,6 @@ import org.thingsboard.server.common.data.Device;
42 import org.thingsboard.server.common.data.DeviceProfile; 43 import org.thingsboard.server.common.data.DeviceProfile;
43 import org.thingsboard.server.common.transport.TransportService; 44 import org.thingsboard.server.common.transport.TransportService;
44 import org.thingsboard.server.common.transport.adaptor.AdaptorException; 45 import org.thingsboard.server.common.transport.adaptor.AdaptorException;
45 -import org.thingsboard.server.common.transport.adaptor.JsonConverter;  
46 import org.thingsboard.server.common.transport.service.DefaultTransportService; 46 import org.thingsboard.server.common.transport.service.DefaultTransportService;
47 import org.thingsboard.server.gen.transport.TransportProtos; 47 import org.thingsboard.server.gen.transport.TransportProtos;
48 import org.thingsboard.server.gen.transport.TransportProtos.AttributeUpdateNotificationMsg; 48 import org.thingsboard.server.gen.transport.TransportProtos.AttributeUpdateNotificationMsg;
@@ -52,12 +52,12 @@ import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; @@ -52,12 +52,12 @@ import org.thingsboard.server.queue.util.TbLwM2mTransportComponent;
52 import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; 52 import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient;
53 import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientContext; 53 import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientContext;
54 import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientProfile; 54 import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientProfile;
  55 +import org.thingsboard.server.transport.lwm2m.server.client.ResultsAddKeyValueProto;
55 import org.thingsboard.server.transport.lwm2m.server.client.ResultsAnalyzerParameters; 56 import org.thingsboard.server.transport.lwm2m.server.client.ResultsAnalyzerParameters;
56 import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl; 57 import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl;
57 58
58 import javax.annotation.PostConstruct; 59 import javax.annotation.PostConstruct;
59 import java.util.ArrayList; 60 import java.util.ArrayList;
60 -import java.util.Arrays;  
61 import java.util.Collection; 61 import java.util.Collection;
62 import java.util.HashSet; 62 import java.util.HashSet;
63 import java.util.LinkedHashSet; 63 import java.util.LinkedHashSet;
@@ -76,24 +76,19 @@ import java.util.stream.Collectors; @@ -76,24 +76,19 @@ import java.util.stream.Collectors;
76 76
77 import static org.eclipse.leshan.core.attributes.Attribute.OBJECT_VERSION; 77 import static org.eclipse.leshan.core.attributes.Attribute.OBJECT_VERSION;
78 import static org.thingsboard.server.common.data.lwm2m.LwM2mConstants.LWM2M_SEPARATOR_PATH; 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 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.CLIENT_NOT_AUTHORIZED; 79 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.CLIENT_NOT_AUTHORIZED;
81 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.DEVICE_ATTRIBUTES_REQUEST; 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 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.GET_TYPE_OPER_DISCOVER; 81 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.GET_TYPE_OPER_DISCOVER;
85 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.GET_TYPE_OPER_OBSERVE; 82 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.GET_TYPE_OPER_OBSERVE;
86 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.GET_TYPE_OPER_READ; 83 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.GET_TYPE_OPER_READ;
87 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.LOG_LW2M_ERROR; 84 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.LOG_LW2M_ERROR;
88 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.LOG_LW2M_INFO; 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 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.LWM2M_STRATEGY_2; 86 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.LWM2M_STRATEGY_2;
91 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.POST_TYPE_OPER_EXECUTE; 87 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.POST_TYPE_OPER_EXECUTE;
92 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.POST_TYPE_OPER_WRITE_REPLACE; 88 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.POST_TYPE_OPER_WRITE_REPLACE;
93 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.PUT_TYPE_OPER_WRITE_ATTRIBUTES; 89 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.PUT_TYPE_OPER_WRITE_ATTRIBUTES;
94 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.SERVICE_CHANNEL; 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 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.getAckCallback; 92 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.getAckCallback;
98 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.validateObjectVerFromKey; 93 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.validateObjectVerFromKey;
99 94
@@ -163,6 +158,7 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService { @@ -163,6 +158,7 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
163 transportService.registerAsyncSession(sessionInfo, new LwM2mSessionMsgListener(this, sessionInfo)); 158 transportService.registerAsyncSession(sessionInfo, new LwM2mSessionMsgListener(this, sessionInfo));
164 transportService.process(sessionInfo, DefaultTransportService.getSessionEventMsg(SessionEvent.OPEN), null); 159 transportService.process(sessionInfo, DefaultTransportService.getSessionEventMsg(SessionEvent.OPEN), null);
165 transportService.process(sessionInfo, TransportProtos.SubscribeToAttributeUpdatesMsg.newBuilder().build(), null); 160 transportService.process(sessionInfo, TransportProtos.SubscribeToAttributeUpdatesMsg.newBuilder().build(), null);
  161 + transportService.process(sessionInfo, TransportProtos.SubscribeToRPCMsg.newBuilder().build(), null);
166 this.initLwM2mFromClientValue(registration, lwM2MClient); 162 this.initLwM2mFromClientValue(registration, lwM2MClient);
167 this.sendLogsToThingsboard(LOG_LW2M_INFO + ": Client create after Registration", registration); 163 this.sendLogsToThingsboard(LOG_LW2M_INFO + ": Client create after Registration", registration);
168 } else { 164 } else {
@@ -309,33 +305,32 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService { @@ -309,33 +305,32 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
309 @Override 305 @Override
310 public void onAttributeUpdate(AttributeUpdateNotificationMsg msg, TransportProtos.SessionInfoProto sessionInfo) { 306 public void onAttributeUpdate(AttributeUpdateNotificationMsg msg, TransportProtos.SessionInfoProto sessionInfo) {
311 if (msg.getSharedUpdatedCount() > 0) { 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 LwM2mClient lwM2MClient = lwM2mClientContext.getLwM2mClient(new UUID(sessionInfo.getSessionIdMSB(), sessionInfo.getSessionIdLSB())); 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 ResourceModel resourceModel = lwM2MClient.getResourceModel(pathIdVer); 314 ResourceModel resourceModel = lwM2MClient.getResourceModel(pathIdVer);
320 if (resourceModel != null && resourceModel.operations.isWritable()) { 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 } else { 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 String logMsg = String.format("%s: attributeUpdate: Resource path - %s value - %s is not Writable and cannot be updated", 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 this.sendLogsToThingsboard(logMsg, lwM2MClient.getRegistration()); 321 this.sendLogsToThingsboard(logMsg, lwM2MClient.getRegistration());
328 } 322 }
329 } else { 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 String logMsg = String.format("%s: attributeUpdate: attribute name - %s value - %s is not present as attribute in profile and cannot be updated", 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 this.sendLogsToThingsboard(logMsg, lwM2MClient.getRegistration()); 327 this.sendLogsToThingsboard(logMsg, lwM2MClient.getRegistration());
334 } 328 }
335 }); 329 });
336 } else if (msg.getSharedDeletedCount() > 0) { 330 } else if (msg.getSharedDeletedCount() > 0) {
337 log.info("[{}] delete [{}] onAttributeUpdate", msg.getSharedDeletedList(), sessionInfo); 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,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 * @param registration - Id of Registration LwM2M Client 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 SessionInfoProto sessionInfo = this.getValidateSessionInfo(registration); 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,7 +493,7 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
517 this.initReadAttrTelemetryObserveToClient(registration, lwM2MClient, GET_TYPE_OPER_READ, clientObjects); 493 this.initReadAttrTelemetryObserveToClient(registration, lwM2MClient, GET_TYPE_OPER_READ, clientObjects);
518 this.initReadAttrTelemetryObserveToClient(registration, lwM2MClient, GET_TYPE_OPER_OBSERVE, clientObjects); 494 this.initReadAttrTelemetryObserveToClient(registration, lwM2MClient, GET_TYPE_OPER_OBSERVE, clientObjects);
519 this.initReadAttrTelemetryObserveToClient(registration, lwM2MClient, PUT_TYPE_OPER_WRITE_ATTRIBUTES, clientObjects); 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,17 +553,20 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
577 * @param registration - Registration LwM2M Client 553 * @param registration - Registration LwM2M Client
578 */ 554 */
579 private void updateAttrTelemetry(Registration registration, Set<String> paths) { 555 private void updateAttrTelemetry(Registration registration, Set<String> paths) {
580 - JsonObject attributes = new JsonObject();  
581 - JsonObject telemetries = new JsonObject();  
582 try { 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 } catch (Exception e) { 567 } catch (Exception e) {
585 log.error("UpdateAttrTelemetry", e); 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,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 * @param registration - Registration LwM2M Client 685 * @param registration - Registration LwM2M Client
721 * @param path - 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 if (path != null && path.size() > 0) { 689 if (path != null && path.size() > 0) {
  690 + ResultsAddKeyValueProto results = new ResultsAddKeyValueProto();
725 LwM2mClientProfile lwM2MClientProfile = lwM2mClientContext.getProfile(registration); 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 JsonObject names = lwM2mClientContext.getProfiles().get(lwM2MClient.getProfileId()).getPostKeyNameProfile(); 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 try { 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 } catch (Exception e) { 755 } catch (Exception e) {
753 log.error("Failed to add parameters.", e); 756 log.error("Failed to add parameters.", e);
754 } 757 }
755 } 758 }
756 } else { 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,9 +779,9 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
774 * @param path - 779 * @param path -
775 * @return - return value of Resource by idPath 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 LwM2mResource resourceValue = null; 783 LwM2mResource resourceValue = null;
779 - if (new LwM2mPath(convertToObjectIdFromIdVer(path)).isResource()) { 784 + if (new LwM2mPath(convertPathFromIdVerToObjectId(path)).isResource()) {
780 resourceValue = lwM2MClient.getResources().get(path).getLwM2mResource(); 785 resourceValue = lwM2MClient.getResources().get(path).getLwM2mResource();
781 } 786 }
782 return resourceValue; 787 return resourceValue;
@@ -959,7 +964,7 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService { @@ -959,7 +964,7 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
959 */ 964 */
960 private void readResourceValueObserve(Registration registration, Set<String> targets, String typeOper) { 965 private void readResourceValueObserve(Registration registration, Set<String> targets, String typeOper) {
961 targets.forEach(target -> { 966 targets.forEach(target -> {
962 - LwM2mPath pathIds = new LwM2mPath(convertToObjectIdFromIdVer(target)); 967 + LwM2mPath pathIds = new LwM2mPath(convertPathFromIdVerToObjectId(target));
963 if (pathIds.isResource()) { 968 if (pathIds.isResource()) {
964 if (GET_TYPE_OPER_READ.equals(typeOper)) { 969 if (GET_TYPE_OPER_READ.equals(typeOper)) {
965 lwM2mTransportRequest.sendAllRequest(registration, target, typeOper, 970 lwM2mTransportRequest.sendAllRequest(registration, target, typeOper,
@@ -1050,19 +1055,23 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService { @@ -1050,19 +1055,23 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
1050 private void cancelObserveIsValue(Registration registration, Set<String> paramAnallyzer) { 1055 private void cancelObserveIsValue(Registration registration, Set<String> paramAnallyzer) {
1051 LwM2mClient lwM2MClient = lwM2mClientContext.getLwM2mClientWithReg(registration, null); 1056 LwM2mClient lwM2MClient = lwM2mClientContext.getLwM2mClientWithReg(registration, null);
1052 paramAnallyzer.forEach(p -> { 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 if (valueNew != null && (valueOld == null || !valueNew.toString().equals(valueOld.toString()))) { 1066 if (valueNew != null && (valueOld == null || !valueNew.toString().equals(valueOld.toString()))) {
1062 lwM2mTransportRequest.sendAllRequest(lwM2MClient.getRegistration(), path, POST_TYPE_OPER_WRITE_REPLACE, 1067 lwM2mTransportRequest.sendAllRequest(lwM2MClient.getRegistration(), path, POST_TYPE_OPER_WRITE_REPLACE,
1063 ContentFormat.TLV.getName(), null, valueNew, this.lwM2mTransportContextServer.getLwM2MTransportConfigServer().getTimeout()); 1068 ContentFormat.TLV.getName(), null, valueNew, this.lwM2mTransportContextServer.getLwM2MTransportConfigServer().getTimeout());
1064 } else { 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,9 +1091,9 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
1082 * @param name - 1091 * @param name -
1083 * @return path if path isPresent in postProfile 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,7 +1103,7 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
1094 * @param name - 1103 * @param name -
1095 * @return - 1104 * @return -
1096 */ 1105 */
1097 - private String getPathAttributeUpdateProfile(TransportProtos.SessionInfoProto sessionInfo, String name) { 1106 + private String getPresentPathIntoProfile(TransportProtos.SessionInfoProto sessionInfo, String name) {
1098 LwM2mClientProfile profile = lwM2mClientContext.getProfile(new UUID(sessionInfo.getDeviceProfileIdMSB(), sessionInfo.getDeviceProfileIdLSB())); 1107 LwM2mClientProfile profile = lwM2mClientContext.getProfile(new UUID(sessionInfo.getDeviceProfileIdMSB(), sessionInfo.getDeviceProfileIdLSB()));
1099 LwM2mClient lwM2mClient = lwM2mClientContext.getLwM2MClient(sessionInfo); 1108 LwM2mClient lwM2mClient = lwM2mClientContext.getLwM2MClient(sessionInfo);
1100 return profile.getPostKeyNameProfile().getAsJsonObject().entrySet().stream() 1109 return profile.getPostKeyNameProfile().getAsJsonObject().entrySet().stream()
@@ -1105,41 +1114,50 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService { @@ -1105,41 +1114,50 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
1105 /** 1114 /**
1106 * Update resource value on client: if there is a difference in values between the current resource values and the shared attribute values 1115 * Update resource value on client: if there is a difference in values between the current resource values and the shared attribute values
1107 * #1 Get path resource by result attributesResponse 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 * @param attributesResponse - 1118 * @param attributesResponse -
1115 * @param sessionInfo - 1119 * @param sessionInfo -
1116 */ 1120 */
1117 public void onGetAttributesResponse(TransportProtos.GetAttributeResponseMsg attributesResponse, TransportProtos.SessionInfoProto sessionInfo) { 1121 public void onGetAttributesResponse(TransportProtos.GetAttributeResponseMsg attributesResponse, TransportProtos.SessionInfoProto sessionInfo) {
1118 try { 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 } catch (Exception e) { 1125 } catch (Exception e) {
1138 log.error(String.valueOf(e)); 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 * @param lwM2MClient - 1161 * @param lwM2MClient -
1144 * @return SessionInfoProto - 1162 * @return SessionInfoProto -
1145 */ 1163 */
@@ -1257,7 +1275,7 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService { @@ -1257,7 +1275,7 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
1257 1275
1258 private boolean validateResourceInModel(LwM2mClient lwM2mClient, String pathIdVer, boolean isWritableNotOptional) { 1276 private boolean validateResourceInModel(LwM2mClient lwM2mClient, String pathIdVer, boolean isWritableNotOptional) {
1259 ResourceModel resourceModel = lwM2mClient.getResourceModel(pathIdVer); 1277 ResourceModel resourceModel = lwM2mClient.getResourceModel(pathIdVer);
1260 - Integer objectId = new LwM2mPath(convertToObjectIdFromIdVer(pathIdVer)).getObjectId(); 1278 + Integer objectId = new LwM2mPath(convertPathFromIdVerToObjectId(pathIdVer)).getObjectId();
1261 String objectVer = validateObjectVerFromKey(pathIdVer); 1279 String objectVer = validateObjectVerFromKey(pathIdVer);
1262 return resourceModel != null && (isWritableNotOptional ? 1280 return resourceModel != null && (isWritableNotOptional ?
1263 objectId != null && objectVer != null && objectVer.equals(lwM2mClient.getRegistration().getSupportedVersion(objectId)) && resourceModel.operations.isWritable() : 1281 objectId != null && objectVer != null && objectVer.equals(lwM2mClient.getRegistration().getSupportedVersion(objectId)) && resourceModel.operations.isWritable() :
@@ -39,7 +39,7 @@ import java.util.concurrent.CopyOnWriteArrayList; @@ -39,7 +39,7 @@ import java.util.concurrent.CopyOnWriteArrayList;
39 import java.util.stream.Collectors; 39 import java.util.stream.Collectors;
40 40
41 import static org.thingsboard.server.common.data.lwm2m.LwM2mConstants.LWM2M_SEPARATOR_PATH; 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 @Slf4j 44 @Slf4j
45 @Data 45 @Data
@@ -83,7 +83,7 @@ public class LwM2mClient implements Cloneable { @@ -83,7 +83,7 @@ public class LwM2mClient implements Cloneable {
83 this.resources.get(pathRez).setLwM2mResource(rez); 83 this.resources.get(pathRez).setLwM2mResource(rez);
84 return true; 84 return true;
85 } else { 85 } else {
86 - LwM2mPath pathIds = new LwM2mPath(convertToObjectIdFromIdVer(pathRez)); 86 + LwM2mPath pathIds = new LwM2mPath(convertPathFromIdVerToObjectId(pathRez));
87 ResourceModel resourceModel = modelProvider.getObjectModel(registration).getResourceModel(pathIds.getObjectId(), pathIds.getResourceId()); 87 ResourceModel resourceModel = modelProvider.getObjectModel(registration).getResourceModel(pathIds.getObjectId(), pathIds.getResourceId());
88 if (resourceModel != null) { 88 if (resourceModel != null) {
89 this.resources.put(pathRez, new ResourceValue(rez, resourceModel)); 89 this.resources.put(pathRez, new ResourceValue(rez, resourceModel));
@@ -110,7 +110,7 @@ public class LwM2mClient implements Cloneable { @@ -110,7 +110,7 @@ public class LwM2mClient implements Cloneable {
110 public void deleteResources(String pathIdVer, LwM2mModelProvider modelProvider) { 110 public void deleteResources(String pathIdVer, LwM2mModelProvider modelProvider) {
111 Set<String> key = getKeysEqualsIdVer(pathIdVer); 111 Set<String> key = getKeysEqualsIdVer(pathIdVer);
112 key.forEach(pathRez -> { 112 key.forEach(pathRez -> {
113 - LwM2mPath pathIds = new LwM2mPath(convertToObjectIdFromIdVer(pathRez)); 113 + LwM2mPath pathIds = new LwM2mPath(convertPathFromIdVerToObjectId(pathRez));
114 ResourceModel resourceModel = modelProvider.getObjectModel(registration).getResourceModel(pathIds.getObjectId(), pathIds.getResourceId()); 114 ResourceModel resourceModel = modelProvider.getObjectModel(registration).getResourceModel(pathIds.getObjectId(), pathIds.getResourceId());
115 if (resourceModel != null) { 115 if (resourceModel != null) {
116 this.resources.get(pathRez).setResourceModel(resourceModel); 116 this.resources.get(pathRez).setResourceModel(resourceModel);
@@ -132,7 +132,7 @@ public class LwM2mClient implements Cloneable { @@ -132,7 +132,7 @@ public class LwM2mClient implements Cloneable {
132 } 132 }
133 133
134 private void saveResourceModel(String pathRez, LwM2mModelProvider modelProvider) { 134 private void saveResourceModel(String pathRez, LwM2mModelProvider modelProvider) {
135 - LwM2mPath pathIds = new LwM2mPath(convertToObjectIdFromIdVer(pathRez)); 135 + LwM2mPath pathIds = new LwM2mPath(convertPathFromIdVerToObjectId(pathRez));
136 ResourceModel resourceModel = modelProvider.getObjectModel(registration).getResourceModel(pathIds.getObjectId(), pathIds.getResourceId()); 136 ResourceModel resourceModel = modelProvider.getObjectModel(registration).getResourceModel(pathIds.getObjectId(), pathIds.getResourceId());
137 this.resources.get(pathRez).setResourceModel(resourceModel); 137 this.resources.get(pathRez).setResourceModel(resourceModel);
138 } 138 }
@@ -35,7 +35,7 @@ import java.util.UUID; @@ -35,7 +35,7 @@ import java.util.UUID;
35 import java.util.concurrent.ConcurrentHashMap; 35 import java.util.concurrent.ConcurrentHashMap;
36 36
37 import static org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode.NO_SEC; 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 @Service 40 @Service
41 @TbLwM2mTransportComponent 41 @TbLwM2mTransportComponent
@@ -185,7 +185,7 @@ public class LwM2mClientContextImpl implements LwM2mClientContext { @@ -185,7 +185,7 @@ public class LwM2mClientContextImpl implements LwM2mClientContext {
185 Arrays.stream(registration.getObjectLinks()).forEach(url -> { 185 Arrays.stream(registration.getObjectLinks()).forEach(url -> {
186 LwM2mPath pathIds = new LwM2mPath(url.getUrl()); 186 LwM2mPath pathIds = new LwM2mPath(url.getUrl());
187 if (!pathIds.isRoot()) { 187 if (!pathIds.isRoot()) {
188 - clientObjects.add(convertToIdVerFromObjectId(url.getUrl(), registration)); 188 + clientObjects.add(convertPathFromObjectIdToIdVer(url.getUrl(), registration));
189 } 189 }
190 }); 190 });
191 return (clientObjects.size() > 0) ? clientObjects : null; 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,14 +18,12 @@ package org.thingsboard.server.transport.lwm2m.utils;
18 import lombok.extern.slf4j.Slf4j; 18 import lombok.extern.slf4j.Slf4j;
19 import org.eclipse.leshan.core.model.ResourceModel.Type; 19 import org.eclipse.leshan.core.model.ResourceModel.Type;
20 import org.eclipse.leshan.core.node.LwM2mPath; 20 import org.eclipse.leshan.core.node.LwM2mPath;
  21 +import org.eclipse.leshan.core.node.ObjectLink;
21 import org.eclipse.leshan.core.node.codec.CodecException; 22 import org.eclipse.leshan.core.node.codec.CodecException;
22 import org.eclipse.leshan.core.node.codec.LwM2mValueConverter; 23 import org.eclipse.leshan.core.node.codec.LwM2mValueConverter;
23 import org.eclipse.leshan.core.util.Hex; 24 import org.eclipse.leshan.core.util.Hex;
24 import org.eclipse.leshan.core.util.StringUtils; 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 import java.math.BigInteger; 27 import java.math.BigInteger;
30 import java.text.DateFormat; 28 import java.text.DateFormat;
31 import java.text.SimpleDateFormat; 29 import java.text.SimpleDateFormat;
@@ -111,15 +109,16 @@ public class LwM2mValueConverterImpl implements LwM2mValueConverter { @@ -111,15 +109,16 @@ public class LwM2mValueConverterImpl implements LwM2mValueConverter {
111 case INTEGER: 109 case INTEGER:
112 log.debug("Trying to convert long value {} to date", value); 110 log.debug("Trying to convert long value {} to date", value);
113 /** let's assume we received the millisecond since 1970/1/1 */ 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 case STRING: 113 case STRING:
116 log.debug("Trying to convert string value {} to date", value); 114 log.debug("Trying to convert string value {} to date", value);
117 /** let's assume we received an ISO 8601 format date */ 115 /** let's assume we received an ISO 8601 format date */
118 try { 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 log.debug("Unable to convert string to date", e); 122 log.debug("Unable to convert string to date", e);
124 throw new CodecException("Unable to convert string (%s) to date for resource %s", value, 123 throw new CodecException("Unable to convert string (%s) to date for resource %s", value,
125 resourcePath); 124 resourcePath);
@@ -147,6 +146,8 @@ public class LwM2mValueConverterImpl implements LwM2mValueConverter { @@ -147,6 +146,8 @@ public class LwM2mValueConverterImpl implements LwM2mValueConverter {
147 return formatter.format(new Date(timeValue)); 146 return formatter.format(new Date(timeValue));
148 case OPAQUE: 147 case OPAQUE:
149 return Hex.encodeHexString((byte[])value); 148 return Hex.encodeHexString((byte[])value);
  149 + case OBJLNK:
  150 + return ObjectLink.decodeFromString((String) value);
150 default: 151 default:
151 break; 152 break;
152 } 153 }
@@ -164,10 +165,14 @@ public class LwM2mValueConverterImpl implements LwM2mValueConverter { @@ -164,10 +165,14 @@ public class LwM2mValueConverterImpl implements LwM2mValueConverter {
164 } 165 }
165 } 166 }
166 break; 167 break;
  168 + case OBJLNK:
  169 + if (currentType == Type.STRING) {
  170 + return ObjectLink.fromPath(value.toString());
  171 + }
167 default: 172 default:
168 } 173 }
169 174
170 throw new CodecException("Invalid value type for resource %s, expected %s, got %s", resourcePath, expectedType, 175 throw new CodecException("Invalid value type for resource %s, expected %s, got %s", resourcePath, expectedType,
171 currentType); 176 currentType);
172 } 177 }
173 -} 178 + }
@@ -119,6 +119,18 @@ redis: @@ -119,6 +119,18 @@ redis:
119 119
120 # LWM2M server parameters 120 # LWM2M server parameters
121 transport: 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 # Local LwM2M transport parameters 134 # Local LwM2M transport parameters
123 lwm2m: 135 lwm2m:
124 # Enable/disable lvm2m transport protocol. 136 # Enable/disable lvm2m transport protocol.
@@ -180,15 +192,6 @@ transport: @@ -180,15 +192,6 @@ transport:
180 # Use redis for Security and Registration stores 192 # Use redis for Security and Registration stores
181 redis.enabled: "${LWM2M_REDIS_ENABLED:false}" 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 queue: 195 queue:
193 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) 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 kafka: 197 kafka:
@@ -82,8 +82,6 @@ @@ -82,8 +82,6 @@
82 <strong>{{ 'device-profile.lwm2m.required' | translate }}</strong> 82 <strong>{{ 'device-profile.lwm2m.required' | translate }}</strong>
83 </mat-error> 83 </mat-error>
84 </mat-form-field> 84 </mat-form-field>
85 - </div>  
86 - <div fxLayout="row" fxLayoutGap="8px">  
87 <mat-form-field fxFlex> 85 <mat-form-field fxFlex>
88 <mat-label>{{ 'device-profile.lwm2m.default-min-period' | translate }}</mat-label> 86 <mat-label>{{ 'device-profile.lwm2m.default-min-period' | translate }}</mat-label>
89 <input matInput type="number" formControlName="defaultMinPeriod" required> 87 <input matInput type="number" formControlName="defaultMinPeriod" required>
@@ -93,13 +91,16 @@ @@ -93,13 +91,16 @@
93 <strong>{{ 'device-profile.lwm2m.required' | translate }}</strong> 91 <strong>{{ 'device-profile.lwm2m.required' | translate }}</strong>
94 </mat-error> 92 </mat-error>
95 </mat-form-field> 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 <mat-label>{{ 'device-profile.lwm2m.binding' | translate }}</mat-label> 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 </mat-form-field> 104 </mat-form-field>
104 </div> 105 </div>
105 <div> 106 <div>
@@ -22,7 +22,8 @@ import { AppState } from '@app/core/core.state'; @@ -22,7 +22,8 @@ import { AppState } from '@app/core/core.state';
22 import { coerceBooleanProperty } from '@angular/cdk/coercion'; 22 import { coerceBooleanProperty } from '@angular/cdk/coercion';
23 import { 23 import {
24 ATTRIBUTE, 24 ATTRIBUTE,
25 - DEFAULT_BINDING, 25 + BINDING_MODE,
  26 + BINDING_MODE_NAMES,
26 getDefaultProfileConfig, 27 getDefaultProfileConfig,
27 INSTANCES, 28 INSTANCES,
28 KEY_NAME, 29 KEY_NAME,
@@ -55,6 +56,9 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro @@ -55,6 +56,9 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro
55 private requiredValue: boolean; 56 private requiredValue: boolean;
56 private disabled = false; 57 private disabled = false;
57 58
  59 + bindingModeType = BINDING_MODE;
  60 + bindingModeTypes = Object.keys(BINDING_MODE);
  61 + bindingModeTypeNamesMap = BINDING_MODE_NAMES;
58 lwm2mDeviceProfileFormGroup: FormGroup; 62 lwm2mDeviceProfileFormGroup: FormGroup;
59 lwm2mDeviceConfigFormGroup: FormGroup; 63 lwm2mDeviceConfigFormGroup: FormGroup;
60 bootstrapServers: string; 64 bootstrapServers: string;
@@ -86,7 +90,7 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro @@ -86,7 +90,7 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro
86 lifetime: [null, Validators.required], 90 lifetime: [null, Validators.required],
87 defaultMinPeriod: [null, Validators.required], 91 defaultMinPeriod: [null, Validators.required],
88 notifIfDisabled: [true, []], 92 notifIfDisabled: [true, []],
89 - binding: [DEFAULT_BINDING, Validators.required], 93 + binding:[],
90 bootstrapServer: [null, Validators.required], 94 bootstrapServer: [null, Validators.required],
91 lwm2mServer: [null, Validators.required], 95 lwm2mServer: [null, Validators.required],
92 }); 96 });
@@ -44,6 +44,35 @@ export const KEY_REGEXP_NUMBER = /^(\-?|\+?)\d*$/; @@ -44,6 +44,35 @@ export const KEY_REGEXP_NUMBER = /^(\-?|\+?)\d*$/;
44 export const INSTANCES_ID_VALUE_MIN = 0; 44 export const INSTANCES_ID_VALUE_MIN = 0;
45 export const INSTANCES_ID_VALUE_MAX = 65535; 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 export enum ATTRIBUTE_LWM2M_ENUM { 76 export enum ATTRIBUTE_LWM2M_ENUM {
48 dim = 'dim', 77 dim = 'dim',
49 ver = 'ver', 78 ver = 'ver',
@@ -62,8 +91,7 @@ export const ATTRIBUTE_LWM2M_LABEL = new Map<ATTRIBUTE_LWM2M_ENUM, string>( @@ -62,8 +91,7 @@ export const ATTRIBUTE_LWM2M_LABEL = new Map<ATTRIBUTE_LWM2M_ENUM, string>(
62 [ATTRIBUTE_LWM2M_ENUM.pmax, 'pmax='], 91 [ATTRIBUTE_LWM2M_ENUM.pmax, 'pmax='],
63 [ATTRIBUTE_LWM2M_ENUM.gt, '>'], 92 [ATTRIBUTE_LWM2M_ENUM.gt, '>'],
64 [ATTRIBUTE_LWM2M_ENUM.lt, '<'], 93 [ATTRIBUTE_LWM2M_ENUM.lt, '<'],
65 - [ATTRIBUTE_LWM2M_ENUM.st, 'st='],  
66 - 94 + [ATTRIBUTE_LWM2M_ENUM.st, 'st=']
67 ] 95 ]
68 ); 96 );
69 97