Commit 99238feae030b6f5f340aafb6ce3561d11d94a85

Authored by nickAS21
1 parent 688a2720

Lwm2m: composite read/write

Showing 14 changed files with 354 additions and 31 deletions
@@ -23,37 +23,41 @@ import lombok.Getter; @@ -23,37 +23,41 @@ import lombok.Getter;
23 public enum LwM2mOperationType { 23 public enum LwM2mOperationType {
24 24
25 READ(0, "Read", true), 25 READ(0, "Read", true),
26 - DISCOVER(1, "Discover", true),  
27 - DISCOVER_ALL(2, "DiscoverAll", false),  
28 - OBSERVE_READ_ALL(3, "ObserveReadAll", false), 26 + READ_COMPOSITE(1, "ReadComposite", true),
  27 + DISCOVER(2, "Discover", true),
  28 + DISCOVER_ALL(3, "DiscoverAll", false),
  29 + OBSERVE_READ_ALL(4, "ObserveReadAll", false),
29 30
30 - OBSERVE(4, "Observe", true),  
31 - OBSERVE_CANCEL(5, "ObserveCancel", true),  
32 - OBSERVE_CANCEL_ALL(6, "ObserveCancelAll", false),  
33 - EXECUTE(7, "Execute", true), 31 + OBSERVE(5, "Observe", true),
  32 + OBSERVE_COMPOSITE(6, "ObserveComposite", true),
  33 + OBSERVE_CANCEL(7, "ObserveCancel", true),
  34 + OBSERVE_COMPOSITE_CANCEL(8, "ObserveCompositeCancel", true),
  35 + OBSERVE_CANCEL_ALL(9, "ObserveCancelAll", false),
  36 + EXECUTE(10, "Execute", true),
34 /** 37 /**
35 * Replaces the Object Instance or the Resource(s) with the new value provided in the “Write” operation. (see 38 * Replaces the Object Instance or the Resource(s) with the new value provided in the “Write” operation. (see
36 * section 5.3.3 of the LW M2M spec). 39 * section 5.3.3 of the LW M2M spec).
37 * if all resources are to be replaced 40 * if all resources are to be replaced
38 */ 41 */
39 - WRITE_REPLACE(8, "WriteReplace", true), 42 + WRITE_REPLACE(11, "WriteReplace", true),
40 43
41 /** 44 /**
42 * Adds or updates Resources provided in the new value and leaves other existing Resources unchanged. (see section 45 * Adds or updates Resources provided in the new value and leaves other existing Resources unchanged. (see section
43 * 5.3.3 of the LW M2M spec). 46 * 5.3.3 of the LW M2M spec).
44 * if this is a partial update request 47 * if this is a partial update request
45 */ 48 */
46 - WRITE_UPDATE(9, "WriteUpdate", true),  
47 - WRITE_ATTRIBUTES(10, "WriteAttributes", true),  
48 - DELETE(11, "Delete", true), 49 + WRITE_UPDATE(12, "WriteUpdate", true),
  50 + WRITE_COMPOSITE(14, "WriteComposite", true),
  51 + WRITE_ATTRIBUTES(15, "WriteAttributes", true),
  52 + DELETE(16, "Delete", true),
49 53
50 // only for RPC 54 // only for RPC
51 - FW_UPDATE(12, "FirmwareUpdate", false); 55 + FW_UPDATE(17, "FirmwareUpdate", false);
52 56
53 -// FW_READ_INFO(12, "FirmwareReadInfo"),  
54 -// SW_READ_INFO(15, "SoftwareReadInfo"),  
55 -// SW_UPDATE(16, "SoftwareUpdate"),  
56 -// SW_UNINSTALL(18, "SoftwareUninstall"); 57 +// FW_READ_INFO(18, "FirmwareReadInfo"),
  58 +// SW_READ_INFO(19, "SoftwareReadInfo"),
  59 +// SW_UPDATE(20, "SoftwareUpdate"),
  60 +// SW_UNINSTALL(21, "SoftwareUninstall");
57 61
58 @Getter 62 @Getter
59 private final int code; 63 private final int code;
@@ -450,4 +450,5 @@ public class LwM2mTransportUtil { @@ -450,4 +450,5 @@ public class LwM2mTransportUtil {
450 } 450 }
451 return lwm2mResourceValue; 451 return lwm2mResourceValue;
452 } 452 }
  453 +
453 } 454 }
@@ -31,17 +31,21 @@ import org.eclipse.leshan.core.request.DeleteRequest; @@ -31,17 +31,21 @@ import org.eclipse.leshan.core.request.DeleteRequest;
31 import org.eclipse.leshan.core.request.DiscoverRequest; 31 import org.eclipse.leshan.core.request.DiscoverRequest;
32 import org.eclipse.leshan.core.request.ExecuteRequest; 32 import org.eclipse.leshan.core.request.ExecuteRequest;
33 import org.eclipse.leshan.core.request.ObserveRequest; 33 import org.eclipse.leshan.core.request.ObserveRequest;
  34 +import org.eclipse.leshan.core.request.ReadCompositeRequest;
34 import org.eclipse.leshan.core.request.ReadRequest; 35 import org.eclipse.leshan.core.request.ReadRequest;
35 import org.eclipse.leshan.core.request.SimpleDownlinkRequest; 36 import org.eclipse.leshan.core.request.SimpleDownlinkRequest;
36 import org.eclipse.leshan.core.request.WriteAttributesRequest; 37 import org.eclipse.leshan.core.request.WriteAttributesRequest;
  38 +import org.eclipse.leshan.core.request.WriteCompositeRequest;
37 import org.eclipse.leshan.core.request.WriteRequest; 39 import org.eclipse.leshan.core.request.WriteRequest;
38 import org.eclipse.leshan.core.response.DeleteResponse; 40 import org.eclipse.leshan.core.response.DeleteResponse;
39 import org.eclipse.leshan.core.response.DiscoverResponse; 41 import org.eclipse.leshan.core.response.DiscoverResponse;
40 import org.eclipse.leshan.core.response.ExecuteResponse; 42 import org.eclipse.leshan.core.response.ExecuteResponse;
41 import org.eclipse.leshan.core.response.LwM2mResponse; 43 import org.eclipse.leshan.core.response.LwM2mResponse;
42 import org.eclipse.leshan.core.response.ObserveResponse; 44 import org.eclipse.leshan.core.response.ObserveResponse;
  45 +import org.eclipse.leshan.core.response.ReadCompositeResponse;
43 import org.eclipse.leshan.core.response.ReadResponse; 46 import org.eclipse.leshan.core.response.ReadResponse;
44 import org.eclipse.leshan.core.response.WriteAttributesResponse; 47 import org.eclipse.leshan.core.response.WriteAttributesResponse;
  48 +import org.eclipse.leshan.core.response.WriteCompositeResponse;
45 import org.eclipse.leshan.core.response.WriteResponse; 49 import org.eclipse.leshan.core.response.WriteResponse;
46 import org.eclipse.leshan.core.util.Hex; 50 import org.eclipse.leshan.core.util.Hex;
47 import org.eclipse.leshan.server.registration.Registration; 51 import org.eclipse.leshan.server.registration.Registration;
@@ -54,6 +58,7 @@ import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportContext; @@ -54,6 +58,7 @@ import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportContext;
54 import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; 58 import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient;
55 import org.thingsboard.server.transport.lwm2m.server.common.LwM2MExecutorAwareService; 59 import org.thingsboard.server.transport.lwm2m.server.common.LwM2MExecutorAwareService;
56 import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogService; 60 import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogService;
  61 +import org.thingsboard.server.transport.lwm2m.server.uplink.DefaultLwM2MUplinkMsgHandler;
57 import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl; 62 import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl;
58 63
59 import javax.annotation.PostConstruct; 64 import javax.annotation.PostConstruct;
@@ -63,6 +68,7 @@ import java.util.Collection; @@ -63,6 +68,7 @@ import java.util.Collection;
63 import java.util.Date; 68 import java.util.Date;
64 import java.util.LinkedList; 69 import java.util.LinkedList;
65 import java.util.List; 70 import java.util.List;
  71 +import java.util.Map;
66 import java.util.Set; 72 import java.util.Set;
67 import java.util.function.Function; 73 import java.util.function.Function;
68 import java.util.function.Predicate; 74 import java.util.function.Predicate;
@@ -110,18 +116,44 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im @@ -110,18 +116,44 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im
110 @Override 116 @Override
111 public void sendReadRequest(LwM2mClient client, TbLwM2MReadRequest request, DownlinkRequestCallback<ReadRequest, ReadResponse> callback) { 117 public void sendReadRequest(LwM2mClient client, TbLwM2MReadRequest request, DownlinkRequestCallback<ReadRequest, ReadResponse> callback) {
112 validateVersionedId(client, request); 118 validateVersionedId(client, request);
113 - ReadRequest downlink = new ReadRequest(getContentFormat(client, request), request.getObjectId()); 119 + ReadRequest downlink = new ReadRequest(getRequestContentFormat(client, request), request.getObjectId());
114 sendRequest(client, downlink, request.getTimeout(), callback); 120 sendRequest(client, downlink, request.getTimeout(), callback);
115 } 121 }
116 122
117 @Override 123 @Override
  124 +// public void sendReadCompositeRequest(LwM2mClient client, TbLwM2MReadCompositeRequest request, DownlinkRequestCallback<ReadCompositeRequest, ReadCompositeResponse> callback) {
  125 + public void sendReadCompositeRequest(LwM2mClient client, String [] paths, DefaultLwM2MUplinkMsgHandler lwM2MUplinkMsgHandler) {
  126 +// validateVersionedId(client, request);
  127 + DownlinkRequestCallback<ReadCompositeRequest, ReadCompositeResponse> callback = new TbLwM2MReadCompositeCallback(lwM2MUplinkMsgHandler, logService, client, null);
  128 + ContentFormat requestContentFormat = ContentFormat.SENML_JSON;
  129 + ContentFormat responseContentFormat = ContentFormat.SENML_JSON;
  130 + ReadCompositeRequest downlink = new ReadCompositeRequest(requestContentFormat, responseContentFormat, paths);
  131 + sendReadRequestComposite(client, downlink, this.config.getTimeout(), callback);
  132 + }
  133 +
  134 + @Override
  135 + public void sendWriteCompositeRequest(LwM2mClient client, Map<String, Object> nodes, DefaultLwM2MUplinkMsgHandler handler) {
  136 +// ResourceModel resourceModelWrite = client.getResourceModel(request.getVersionedId(), this.config.getModelProvider());
  137 + TbLwM2MWriteResponseCompositeCallback callback = new TbLwM2MWriteResponseCompositeCallback (handler, logService, client, null);
  138 + ContentFormat contentFormat = ContentFormat.SENML_JSON;
  139 + try {
  140 + WriteCompositeRequest downlink = new WriteCompositeRequest(contentFormat, nodes);
  141 + sendWriteCompositeRequest(client, downlink, this.config.getTimeout(), callback);
  142 + } catch (Exception e) {
  143 + callback.onError(JacksonUtil.toString(nodes), e);
  144 + }
  145 +
  146 + }
  147 +
  148 +
  149 + @Override
118 public void sendObserveRequest(LwM2mClient client, TbLwM2MObserveRequest request, DownlinkRequestCallback<ObserveRequest, ObserveResponse> callback) { 150 public void sendObserveRequest(LwM2mClient client, TbLwM2MObserveRequest request, DownlinkRequestCallback<ObserveRequest, ObserveResponse> callback) {
119 validateVersionedId(client, request); 151 validateVersionedId(client, request);
120 LwM2mPath resultIds = new LwM2mPath(request.getObjectId()); 152 LwM2mPath resultIds = new LwM2mPath(request.getObjectId());
121 Set<Observation> observations = context.getServer().getObservationService().getObservations(client.getRegistration()); 153 Set<Observation> observations = context.getServer().getObservationService().getObservations(client.getRegistration());
122 if (observations.stream().noneMatch(observation -> observation.getPath().equals(resultIds))) { 154 if (observations.stream().noneMatch(observation -> observation.getPath().equals(resultIds))) {
123 ObserveRequest downlink; 155 ObserveRequest downlink;
124 - ContentFormat contentFormat = getContentFormat(client, request); 156 + ContentFormat contentFormat = getRequestContentFormat(client, request);
125 if (resultIds.isResource()) { 157 if (resultIds.isResource()) {
126 downlink = new ObserveRequest(contentFormat, resultIds.getObjectId(), resultIds.getObjectInstanceId(), resultIds.getResourceId()); 158 downlink = new ObserveRequest(contentFormat, resultIds.getObjectId(), resultIds.getObjectInstanceId(), resultIds.getResourceId());
127 } else if (resultIds.isObjectInstance()) { 159 } else if (resultIds.isObjectInstance()) {
@@ -278,6 +310,73 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im @@ -278,6 +310,73 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im
278 } 310 }
279 } 311 }
280 312
  313 + private <R extends SimpleDownlinkRequest<T>, T extends LwM2mResponse> void sendWriteCompositeRequest(LwM2mClient client, WriteCompositeRequest request, long timeoutInMs, DownlinkRequestCallback<WriteCompositeRequest, WriteCompositeResponse> callback) {
  314 + Registration registration = client.getRegistration();
  315 + try {
  316 + logService.log(client, String.format("[%s][%s] Sending request: %s to %s", registration.getId(), registration.getSocketAddress(), request.getClass().getSimpleName(), request.getPaths()));
  317 + context.getServer().send(registration, request, timeoutInMs, response -> {
  318 + executor.submit(() -> {
  319 + try {
  320 + callback.onSuccess(request, response);
  321 + } catch (Exception e) {
  322 + log.error("[{}] failed to process successful response [{}] ", registration.getEndpoint(), response, e);
  323 + }
  324 + });
  325 + }, e -> {
  326 + executor.submit(() -> {
  327 + callback.onError(JacksonUtil.toString(request), e);
  328 + });
  329 + });
  330 + } catch (Exception e) {
  331 + callback.onError(JacksonUtil.toString(request), e);
  332 + }
  333 + }
  334 +
  335 + private <R extends SimpleDownlinkRequest<T>, T extends LwM2mResponse> void sendReadRequestComposite(LwM2mClient client, ReadCompositeRequest request, long timeoutInMs, DownlinkRequestCallback<ReadCompositeRequest, ReadCompositeResponse> callback) {
  336 + Registration registration = client.getRegistration();
  337 + try {
  338 + logService.log(client, String.format("[%s][%s] Sending request: %s to %s", registration.getId(), registration.getSocketAddress(), request.getClass().getSimpleName(), request.getPaths()));
  339 + context.getServer().send(registration, request, timeoutInMs, response -> {
  340 + executor.submit(() -> {
  341 + try {
  342 + /**
  343 + * [{"bn":"/3/0/","n":"0","vs":"Thingsboard Test Device"},
  344 + * {"n":"1","vs":"Model 500"},
  345 + * {"n":"2","vs":"TH-500-000-0001"},
  346 + * {"n":"3","vs":"TestThingsboard@TestMore1024_2.04"},
  347 + * {"n":"6","v":1},{"n":"7","v":56},
  348 + * {"n":"8","v":42},{"n":"9","v":16},
  349 + * {"n":"10","v":127619},{"n":"13","v":1624520988},
  350 + * {"n":"14","vs":"+03"},{"n":"15","vs":"Europe/Kiev"},
  351 + * {"n":"16","vs":"U"},{"n":"17","vs":"smart meters"},
  352 + * {"n":"18","vs":"1.01"},{"n":"19","vs":"1.02"},
  353 + * {"n":"20","v":3},{"n":"21","v":256000},
  354 + * {"bn":"/5/0/","n":"1","vs":""},
  355 + * {"n":"3","v":0},{"n":"5","v":0},
  356 + * {"n":"6","vs":""},{"n":"7","vs":""},
  357 + * {"n":"8/0","v":0},{"n":"8/1","v":1},
  358 + * {"n":"9","v":2},
  359 + * {"bn":"/1/0/","n":"0","v":123},
  360 + * {"n":"1","v":300},
  361 + * {"n":"6","vb":false},
  362 + * {"n":"22","vs":"U"},
  363 + * {"n":"7","vs":"U"}]
  364 + */
  365 + callback.onSuccess(request, response);
  366 + } catch (Exception e) {
  367 + log.error("[{}] failed to process successful response [{}] ", registration.getEndpoint(), response, e);
  368 + }
  369 + });
  370 + }, e -> {
  371 + executor.submit(() -> {
  372 + callback.onError(JacksonUtil.toString(request), e);
  373 + });
  374 + });
  375 + } catch (Exception e) {
  376 + callback.onError(JacksonUtil.toString(request), e);
  377 + }
  378 + }
  379 +
281 private WriteRequest getWriteRequestSingleResource(ResourceModel.Type type, ContentFormat contentFormat, int objectId, int instanceId, int resourceId, Object value) { 380 private WriteRequest getWriteRequestSingleResource(ResourceModel.Type type, ContentFormat contentFormat, int objectId, int instanceId, int resourceId, Object value) {
282 switch (type) { 381 switch (type) {
283 case STRING: // String 382 case STRING: // String
@@ -347,7 +446,7 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im @@ -347,7 +446,7 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im
347 throw new CodecException("Invalid ResourceModel_Type for %s ContentFormat.", type); 446 throw new CodecException("Invalid ResourceModel_Type for %s ContentFormat.", type);
348 } 447 }
349 448
350 - private static ContentFormat getContentFormat(LwM2mClient client, HasContentFormat request) {  
351 - return request.getContentFormat() != null ? request.getContentFormat() : client.getDefaultContentFormat(); 449 + private static ContentFormat getRequestContentFormat(LwM2mClient client, HasContentFormat request) {
  450 + return request.getRequestContentFormat() != null ? request.getRequestContentFormat() : client.getDefaultContentFormat();
352 } 451 }
353 } 452 }
@@ -19,5 +19,9 @@ import org.eclipse.leshan.core.request.ContentFormat; @@ -19,5 +19,9 @@ import org.eclipse.leshan.core.request.ContentFormat;
19 19
20 public interface HasContentFormat { 20 public interface HasContentFormat {
21 21
22 - ContentFormat getContentFormat(); 22 + ContentFormat getRequestContentFormat();
  23 +
  24 + default ContentFormat getResponseContentFormat() {
  25 + return null;
  26 + }
23 } 27 }
@@ -31,14 +31,19 @@ import org.eclipse.leshan.core.response.ReadResponse; @@ -31,14 +31,19 @@ import org.eclipse.leshan.core.response.ReadResponse;
31 import org.eclipse.leshan.core.response.WriteAttributesResponse; 31 import org.eclipse.leshan.core.response.WriteAttributesResponse;
32 import org.eclipse.leshan.core.response.WriteResponse; 32 import org.eclipse.leshan.core.response.WriteResponse;
33 import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; 33 import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient;
  34 +import org.thingsboard.server.transport.lwm2m.server.uplink.DefaultLwM2MUplinkMsgHandler;
34 35
35 import java.util.List; 36 import java.util.List;
  37 +import java.util.Map;
36 import java.util.Set; 38 import java.util.Set;
37 39
38 public interface LwM2mDownlinkMsgHandler { 40 public interface LwM2mDownlinkMsgHandler {
39 41
40 void sendReadRequest(LwM2mClient client, TbLwM2MReadRequest request, DownlinkRequestCallback<ReadRequest, ReadResponse> callback); 42 void sendReadRequest(LwM2mClient client, TbLwM2MReadRequest request, DownlinkRequestCallback<ReadRequest, ReadResponse> callback);
41 43
  44 +// void sendReadCompositeRequest(LwM2mClient client, TbLwM2MReadCompositeRequest request, DownlinkRequestCallback<ReadCompositeRequest, ReadCompositeResponse> callback);
  45 + void sendReadCompositeRequest(LwM2mClient client, String [] paths, DefaultLwM2MUplinkMsgHandler lwM2MUplinkMsgHandler);
  46 +
42 void sendObserveRequest(LwM2mClient client, TbLwM2MObserveRequest request, DownlinkRequestCallback<ObserveRequest, ObserveResponse> callback); 47 void sendObserveRequest(LwM2mClient client, TbLwM2MObserveRequest request, DownlinkRequestCallback<ObserveRequest, ObserveResponse> callback);
43 48
44 void sendObserveAllRequest(LwM2mClient client, TbLwM2MObserveAllRequest request, DownlinkRequestCallback<TbLwM2MObserveAllRequest, Set<String>> callback); 49 void sendObserveAllRequest(LwM2mClient client, TbLwM2MObserveAllRequest request, DownlinkRequestCallback<TbLwM2MObserveAllRequest, Set<String>> callback);
@@ -59,6 +64,8 @@ public interface LwM2mDownlinkMsgHandler { @@ -59,6 +64,8 @@ public interface LwM2mDownlinkMsgHandler {
59 64
60 void sendWriteReplaceRequest(LwM2mClient client, TbLwM2MWriteReplaceRequest request, DownlinkRequestCallback<WriteRequest, WriteResponse> callback); 65 void sendWriteReplaceRequest(LwM2mClient client, TbLwM2MWriteReplaceRequest request, DownlinkRequestCallback<WriteRequest, WriteResponse> callback);
61 66
  67 + void sendWriteCompositeRequest(LwM2mClient client, Map<String, Object> nodes, DefaultLwM2MUplinkMsgHandler handler);
  68 +
62 void sendWriteUpdateRequest(LwM2mClient client, TbLwM2MWriteUpdateRequest request, DownlinkRequestCallback<WriteRequest, WriteResponse> callback); 69 void sendWriteUpdateRequest(LwM2mClient client, TbLwM2MWriteUpdateRequest request, DownlinkRequestCallback<WriteRequest, WriteResponse> callback);
63 70
64 71
@@ -24,12 +24,12 @@ import org.thingsboard.server.transport.lwm2m.server.LwM2mOperationType; @@ -24,12 +24,12 @@ import org.thingsboard.server.transport.lwm2m.server.LwM2mOperationType;
24 public class TbLwM2MObserveRequest extends AbstractTbLwM2MTargetedDownlinkRequest<ObserveResponse> implements HasContentFormat { 24 public class TbLwM2MObserveRequest extends AbstractTbLwM2MTargetedDownlinkRequest<ObserveResponse> implements HasContentFormat {
25 25
26 @Getter 26 @Getter
27 - private final ContentFormat contentFormat; 27 + private final ContentFormat requestContentFormat;
28 28
29 @Builder 29 @Builder
30 - private TbLwM2MObserveRequest(String versionedId, long timeout, ContentFormat contentFormat) { 30 + private TbLwM2MObserveRequest(String versionedId, long timeout, ContentFormat requestContentFormat) {
31 super(versionedId, timeout); 31 super(versionedId, timeout);
32 - this.contentFormat = contentFormat; 32 + this.requestContentFormat = requestContentFormat;
33 } 33 }
34 34
35 @Override 35 @Override
  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.downlink;
  17 +
  18 +import lombok.extern.slf4j.Slf4j;
  19 +import org.eclipse.leshan.core.request.ReadCompositeRequest;
  20 +import org.eclipse.leshan.core.response.ReadCompositeResponse;
  21 +import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient;
  22 +import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogService;
  23 +import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mUplinkMsgHandler;
  24 +
  25 +@Slf4j
  26 +public class TbLwM2MReadCompositeCallback extends TbLwM2MUplinkTargetedCallback<ReadCompositeRequest, ReadCompositeResponse> {
  27 +
  28 + public TbLwM2MReadCompositeCallback(LwM2mUplinkMsgHandler handler, LwM2MTelemetryLogService logService, LwM2mClient client, String targetId) {
  29 + super(handler, logService, client, targetId);
  30 + }
  31 +
  32 + @Override
  33 + public void onSuccess(ReadCompositeRequest request, ReadCompositeResponse response) {
  34 + super.onSuccess(request, response);
  35 + handler.onUpdateValueAfterReadCompositeResponse(client.getRegistration(), versionedId, response);
  36 + }
  37 +
  38 +}
  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.downlink;
  17 +
  18 +import lombok.Builder;
  19 +import lombok.Getter;
  20 +import org.eclipse.leshan.core.request.ContentFormat;
  21 +import org.eclipse.leshan.core.response.ReadCompositeResponse;
  22 +import org.thingsboard.server.transport.lwm2m.server.LwM2mOperationType;
  23 +
  24 +public class TbLwM2MReadCompositeRequest extends AbstractTbLwM2MTargetedDownlinkRequest<ReadCompositeResponse> implements HasContentFormat {
  25 +
  26 + @Getter
  27 + private final ContentFormat requestContentFormat;
  28 +
  29 + @Getter
  30 + private final ContentFormat responseContentFormat;
  31 +
  32 + @Builder
  33 + private TbLwM2MReadCompositeRequest(String versionedId, long timeout, ContentFormat requestContentFormat, ContentFormat responseContentFormat) {
  34 + super(versionedId, timeout);
  35 + this.requestContentFormat = requestContentFormat;
  36 + this.responseContentFormat = responseContentFormat;
  37 + }
  38 +
  39 + @Override
  40 + public LwM2mOperationType getType() {
  41 + return LwM2mOperationType.READ_COMPOSITE;
  42 + }
  43 +
  44 +}
@@ -24,12 +24,12 @@ import org.thingsboard.server.transport.lwm2m.server.LwM2mOperationType; @@ -24,12 +24,12 @@ import org.thingsboard.server.transport.lwm2m.server.LwM2mOperationType;
24 public class TbLwM2MReadRequest extends AbstractTbLwM2MTargetedDownlinkRequest<ReadResponse> implements HasContentFormat { 24 public class TbLwM2MReadRequest extends AbstractTbLwM2MTargetedDownlinkRequest<ReadResponse> implements HasContentFormat {
25 25
26 @Getter 26 @Getter
27 - private final ContentFormat contentFormat; 27 + private final ContentFormat requestContentFormat;
28 28
29 @Builder 29 @Builder
30 - private TbLwM2MReadRequest(String versionedId, long timeout, ContentFormat contentFormat) { 30 + private TbLwM2MReadRequest(String versionedId, long timeout, ContentFormat requestContentFormat) {
31 super(versionedId, timeout); 31 super(versionedId, timeout);
32 - this.contentFormat = contentFormat; 32 + this.requestContentFormat = requestContentFormat;
33 } 33 }
34 34
35 @Override 35 @Override
@@ -18,7 +18,6 @@ package org.thingsboard.server.transport.lwm2m.server.downlink; @@ -18,7 +18,6 @@ package org.thingsboard.server.transport.lwm2m.server.downlink;
18 import lombok.extern.slf4j.Slf4j; 18 import lombok.extern.slf4j.Slf4j;
19 import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; 19 import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient;
20 import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogService; 20 import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogService;
21 -import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mUplinkMsgHandler;  
22 21
23 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LWM2M_INFO; 22 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LWM2M_INFO;
24 23
@@ -32,6 +31,11 @@ public abstract class TbLwM2MTargetedCallback<R, T> extends AbstractTbLwM2MReque @@ -32,6 +31,11 @@ public abstract class TbLwM2MTargetedCallback<R, T> extends AbstractTbLwM2MReque
32 this.versionedId = versionedId; 31 this.versionedId = versionedId;
33 } 32 }
34 33
  34 + public TbLwM2MTargetedCallback(LwM2MTelemetryLogService logService, LwM2mClient client) {
  35 + super(logService, client);
  36 + this.versionedId = null;
  37 + }
  38 +
35 @Override 39 @Override
36 public void onSuccess(R request, T response) { 40 public void onSuccess(R request, T response) {
37 //TODO convert camelCase to "camel case" using .split("(?<!(^|[A-Z]))(?=[A-Z])|(?<!^)(?=[A-Z][a-z])") 41 //TODO convert camelCase to "camel case" using .split("(?<!(^|[A-Z]))(?=[A-Z])|(?<!^)(?=[A-Z][a-z])")
  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.downlink;
  17 +
  18 +import lombok.Builder;
  19 +import lombok.Getter;
  20 +import org.eclipse.leshan.core.request.ContentFormat;
  21 +import org.eclipse.leshan.core.response.WriteCompositeResponse;
  22 +import org.thingsboard.server.transport.lwm2m.server.LwM2mOperationType;
  23 +
  24 +public class TbLwM2MWriteCompositeRequest extends AbstractTbLwM2MTargetedDownlinkRequest<WriteCompositeResponse> {
  25 +
  26 + @Getter
  27 + private final ContentFormat contentFormat;
  28 + @Getter
  29 + private final Object value;
  30 +
  31 + @Builder
  32 + private TbLwM2MWriteCompositeRequest(String versionedId, long timeout, ContentFormat contentFormat, Object value) {
  33 + super(versionedId, timeout);
  34 + this.contentFormat = contentFormat;
  35 + this.value = value;
  36 + }
  37 +
  38 + @Override
  39 + public LwM2mOperationType getType() {
  40 + return LwM2mOperationType.WRITE_REPLACE;
  41 + }
  42 +
  43 +
  44 +
  45 +}
  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.downlink;
  17 +
  18 +import org.eclipse.leshan.core.request.WriteCompositeRequest;
  19 +import org.eclipse.leshan.core.response.WriteCompositeResponse;
  20 +import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient;
  21 +import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogService;
  22 +import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mUplinkMsgHandler;
  23 +
  24 +public class TbLwM2MWriteResponseCompositeCallback extends TbLwM2MUplinkTargetedCallback<WriteCompositeRequest, WriteCompositeResponse> {
  25 +
  26 + public TbLwM2MWriteResponseCompositeCallback(LwM2mUplinkMsgHandler handler, LwM2MTelemetryLogService logService, LwM2mClient client, String targetId) {
  27 + super(handler, logService, client, targetId);
  28 + }
  29 +
  30 + @Override
  31 + public void onSuccess(WriteCompositeRequest request, WriteCompositeResponse response) {
  32 + super.onSuccess(request, response);
  33 + handler.onWriteCompositeResponseOk(client, request);
  34 + }
  35 +
  36 +}
@@ -30,14 +30,15 @@ import org.eclipse.leshan.core.node.LwM2mResource; @@ -30,14 +30,15 @@ import org.eclipse.leshan.core.node.LwM2mResource;
30 import org.eclipse.leshan.core.observation.Observation; 30 import org.eclipse.leshan.core.observation.Observation;
31 import org.eclipse.leshan.core.request.ObserveRequest; 31 import org.eclipse.leshan.core.request.ObserveRequest;
32 import org.eclipse.leshan.core.request.ReadRequest; 32 import org.eclipse.leshan.core.request.ReadRequest;
  33 +import org.eclipse.leshan.core.request.WriteCompositeRequest;
33 import org.eclipse.leshan.core.request.WriteRequest; 34 import org.eclipse.leshan.core.request.WriteRequest;
34 import org.eclipse.leshan.core.response.ObserveResponse; 35 import org.eclipse.leshan.core.response.ObserveResponse;
  36 +import org.eclipse.leshan.core.response.ReadCompositeResponse;
35 import org.eclipse.leshan.core.response.ReadResponse; 37 import org.eclipse.leshan.core.response.ReadResponse;
36 import org.eclipse.leshan.server.registration.Registration; 38 import org.eclipse.leshan.server.registration.Registration;
37 import org.springframework.context.annotation.Lazy; 39 import org.springframework.context.annotation.Lazy;
38 import org.springframework.stereotype.Service; 40 import org.springframework.stereotype.Service;
39 import org.thingsboard.common.util.DonAsynchron; 41 import org.thingsboard.common.util.DonAsynchron;
40 -import org.thingsboard.server.cache.ota.OtaPackageDataCache;  
41 import org.thingsboard.server.common.data.Device; 42 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.data.StringUtils; 44 import org.thingsboard.server.common.data.StringUtils;
@@ -83,8 +84,6 @@ import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MWriteAttrib @@ -83,8 +84,6 @@ import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MWriteAttrib
83 import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MWriteAttributesRequest; 84 import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MWriteAttributesRequest;
84 import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogService; 85 import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogService;
85 import org.thingsboard.server.transport.lwm2m.server.ota.LwM2MOtaUpdateService; 86 import org.thingsboard.server.transport.lwm2m.server.ota.LwM2MOtaUpdateService;
86 -import org.thingsboard.server.transport.lwm2m.server.ota.firmware.LwM2MFirmwareUpdateStrategy;  
87 -import org.thingsboard.server.transport.lwm2m.server.ota.software.LwM2MSoftwareUpdateStrategy;  
88 import org.thingsboard.server.transport.lwm2m.server.rpc.LwM2MRpcRequestHandler; 87 import org.thingsboard.server.transport.lwm2m.server.rpc.LwM2MRpcRequestHandler;
89 import org.thingsboard.server.transport.lwm2m.server.store.TbLwM2MDtlsSessionStore; 88 import org.thingsboard.server.transport.lwm2m.server.store.TbLwM2MDtlsSessionStore;
90 import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl; 89 import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl;
@@ -94,6 +93,7 @@ import javax.annotation.PreDestroy; @@ -94,6 +93,7 @@ import javax.annotation.PreDestroy;
94 import java.util.ArrayList; 93 import java.util.ArrayList;
95 import java.util.Collection; 94 import java.util.Collection;
96 import java.util.Collections; 95 import java.util.Collections;
  96 +import java.util.HashMap;
97 import java.util.HashSet; 97 import java.util.HashSet;
98 import java.util.List; 98 import java.util.List;
99 import java.util.Map; 99 import java.util.Map;
@@ -354,6 +354,22 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl @@ -354,6 +354,22 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl
354 } 354 }
355 } 355 }
356 356
  357 + public void onUpdateValueAfterReadCompositeResponse(Registration registration, String path, ReadCompositeResponse response) {
  358 + log.warn("201) ReadCompositeResponse: [{}]", response);
  359 + if (response.getContent() != null) {
  360 + LwM2mClient lwM2MClient = clientContext.getClientByEndpoint(registration.getEndpoint());
  361 + response.getContent().forEach((k, v) -> {
  362 + if (v instanceof LwM2mObject) {
  363 + this.updateObjectResourceValue(lwM2MClient, (LwM2mObject) v, k.toString());
  364 + } else if (v instanceof LwM2mObjectInstance) {
  365 + this.updateObjectInstanceResourceValue(lwM2MClient, (LwM2mObjectInstance) v, k.toString());
  366 + } else if (v instanceof LwM2mResource) {
  367 + this.updateResourcesValue(lwM2MClient, (LwM2mResource) v, k.toString());
  368 + }
  369 + });
  370 + }
  371 + }
  372 +
357 /** 373 /**
358 * @param sessionInfo - 374 * @param sessionInfo -
359 * @param deviceProfile - 375 * @param deviceProfile -
@@ -429,6 +445,17 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl @@ -429,6 +445,17 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl
429 if (supportedObjects != null && supportedObjects.size() > 0) { 445 if (supportedObjects != null && supportedObjects.size() > 0) {
430 // #1 446 // #1
431 this.sendReadRequests(lwM2MClient, profile, supportedObjects); 447 this.sendReadRequests(lwM2MClient, profile, supportedObjects);
  448 + // test composite
  449 + String[] paths = new String[]{"/3/0", "/1/0", "/5/0"};
  450 +// String [] paths = new String[] {"/5"};
  451 +// String [] paths = new String[] {"/"};
  452 +// String [] paths = new String[] {"/9"};
  453 + defaultLwM2MDownlinkMsgHandler.sendReadCompositeRequest(lwM2MClient, paths, this);
  454 + Map<String, Object> nodes = new HashMap<>();
  455 + nodes.put("/3/0/14", "+02");
  456 + nodes.put("/1/0/2", 100);
  457 + nodes.put("/5/0/1", "coap://localhost:5685");
  458 + defaultLwM2MDownlinkMsgHandler.sendWriteCompositeRequest(lwM2MClient, nodes, this);
432 this.sendObserveRequests(lwM2MClient, profile, supportedObjects); 459 this.sendObserveRequests(lwM2MClient, profile, supportedObjects);
433 this.sendWriteAttributeRequests(lwM2MClient, profile, supportedObjects); 460 this.sendWriteAttributeRequests(lwM2MClient, profile, supportedObjects);
434 // Removed. Used only for debug. 461 // Removed. Used only for debug.
@@ -712,6 +739,14 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl @@ -712,6 +739,14 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl
712 739
713 } 740 }
714 741
  742 + @Override
  743 + public void onWriteCompositeResponseOk(LwM2mClient client, WriteCompositeRequest request) {
  744 + log.warn("202) ReadCompositeResponse: [{}]", request.getNodes());
  745 + request.getNodes().forEach((k, v) -> {
  746 + this.updateResourcesValue(client, (LwM2mResource) v, k.toString());
  747 + });
  748 + }
  749 +
715 //TODO: review and optimize the logic to minimize number of the requests to device. 750 //TODO: review and optimize the logic to minimize number of the requests to device.
716 private void onDeviceProfileUpdate(List<LwM2mClient> clients, DeviceProfile deviceProfile) { 751 private void onDeviceProfileUpdate(List<LwM2mClient> clients, DeviceProfile deviceProfile) {
717 var oldProfile = clientContext.getProfile(deviceProfile.getUuidId()); 752 var oldProfile = clientContext.getProfile(deviceProfile.getUuidId());
@@ -16,7 +16,9 @@ @@ -16,7 +16,9 @@
16 package org.thingsboard.server.transport.lwm2m.server.uplink; 16 package org.thingsboard.server.transport.lwm2m.server.uplink;
17 17
18 import org.eclipse.leshan.core.observation.Observation; 18 import org.eclipse.leshan.core.observation.Observation;
  19 +import org.eclipse.leshan.core.request.WriteCompositeRequest;
19 import org.eclipse.leshan.core.request.WriteRequest; 20 import org.eclipse.leshan.core.request.WriteRequest;
  21 +import org.eclipse.leshan.core.response.ReadCompositeResponse;
20 import org.eclipse.leshan.core.response.ReadResponse; 22 import org.eclipse.leshan.core.response.ReadResponse;
21 import org.eclipse.leshan.server.registration.Registration; 23 import org.eclipse.leshan.server.registration.Registration;
22 import org.thingsboard.server.common.data.Device; 24 import org.thingsboard.server.common.data.Device;
@@ -40,6 +42,8 @@ public interface LwM2mUplinkMsgHandler { @@ -40,6 +42,8 @@ public interface LwM2mUplinkMsgHandler {
40 42
41 void onUpdateValueAfterReadResponse(Registration registration, String path, ReadResponse response); 43 void onUpdateValueAfterReadResponse(Registration registration, String path, ReadResponse response);
42 44
  45 + void onUpdateValueAfterReadCompositeResponse(Registration registration, String path, ReadCompositeResponse response);
  46 +
43 void onDeviceProfileUpdate(TransportProtos.SessionInfoProto sessionInfo, DeviceProfile deviceProfile); 47 void onDeviceProfileUpdate(TransportProtos.SessionInfoProto sessionInfo, DeviceProfile deviceProfile);
44 48
45 void onDeviceUpdate(TransportProtos.SessionInfoProto sessionInfo, Device device, Optional<DeviceProfile> deviceProfileOpt); 49 void onDeviceUpdate(TransportProtos.SessionInfoProto sessionInfo, Device device, Optional<DeviceProfile> deviceProfileOpt);
@@ -54,6 +58,8 @@ public interface LwM2mUplinkMsgHandler { @@ -54,6 +58,8 @@ public interface LwM2mUplinkMsgHandler {
54 58
55 void onWriteResponseOk(LwM2mClient client, String path, WriteRequest request); 59 void onWriteResponseOk(LwM2mClient client, String path, WriteRequest request);
56 60
  61 + void onWriteCompositeResponseOk(LwM2mClient client, WriteCompositeRequest request);
  62 +
57 void onToTransportUpdateCredentials(TransportProtos.ToTransportUpdateCredentialsProto updateCredentials); 63 void onToTransportUpdateCredentials(TransportProtos.ToTransportUpdateCredentialsProto updateCredentials);
58 64
59 LwM2MTransportServerConfig getConfig(); 65 LwM2MTransportServerConfig getConfig();