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 23 public enum LwM2mOperationType {
24 24
25 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 38 * Replaces the Object Instance or the Resource(s) with the new value provided in the “Write” operation. (see
36 39 * section 5.3.3 of the LW M2M spec).
37 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 45 * Adds or updates Resources provided in the new value and leaves other existing Resources unchanged. (see section
43 46 * 5.3.3 of the LW M2M spec).
44 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 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 62 @Getter
59 63 private final int code;
... ...
... ... @@ -450,4 +450,5 @@ public class LwM2mTransportUtil {
450 450 }
451 451 return lwm2mResourceValue;
452 452 }
  453 +
453 454 }
... ...
... ... @@ -31,17 +31,21 @@ import org.eclipse.leshan.core.request.DeleteRequest;
31 31 import org.eclipse.leshan.core.request.DiscoverRequest;
32 32 import org.eclipse.leshan.core.request.ExecuteRequest;
33 33 import org.eclipse.leshan.core.request.ObserveRequest;
  34 +import org.eclipse.leshan.core.request.ReadCompositeRequest;
34 35 import org.eclipse.leshan.core.request.ReadRequest;
35 36 import org.eclipse.leshan.core.request.SimpleDownlinkRequest;
36 37 import org.eclipse.leshan.core.request.WriteAttributesRequest;
  38 +import org.eclipse.leshan.core.request.WriteCompositeRequest;
37 39 import org.eclipse.leshan.core.request.WriteRequest;
38 40 import org.eclipse.leshan.core.response.DeleteResponse;
39 41 import org.eclipse.leshan.core.response.DiscoverResponse;
40 42 import org.eclipse.leshan.core.response.ExecuteResponse;
41 43 import org.eclipse.leshan.core.response.LwM2mResponse;
42 44 import org.eclipse.leshan.core.response.ObserveResponse;
  45 +import org.eclipse.leshan.core.response.ReadCompositeResponse;
43 46 import org.eclipse.leshan.core.response.ReadResponse;
44 47 import org.eclipse.leshan.core.response.WriteAttributesResponse;
  48 +import org.eclipse.leshan.core.response.WriteCompositeResponse;
45 49 import org.eclipse.leshan.core.response.WriteResponse;
46 50 import org.eclipse.leshan.core.util.Hex;
47 51 import org.eclipse.leshan.server.registration.Registration;
... ... @@ -54,6 +58,7 @@ import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportContext;
54 58 import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient;
55 59 import org.thingsboard.server.transport.lwm2m.server.common.LwM2MExecutorAwareService;
56 60 import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogService;
  61 +import org.thingsboard.server.transport.lwm2m.server.uplink.DefaultLwM2MUplinkMsgHandler;
57 62 import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl;
58 63
59 64 import javax.annotation.PostConstruct;
... ... @@ -63,6 +68,7 @@ import java.util.Collection;
63 68 import java.util.Date;
64 69 import java.util.LinkedList;
65 70 import java.util.List;
  71 +import java.util.Map;
66 72 import java.util.Set;
67 73 import java.util.function.Function;
68 74 import java.util.function.Predicate;
... ... @@ -110,18 +116,44 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im
110 116 @Override
111 117 public void sendReadRequest(LwM2mClient client, TbLwM2MReadRequest request, DownlinkRequestCallback<ReadRequest, ReadResponse> callback) {
112 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 120 sendRequest(client, downlink, request.getTimeout(), callback);
115 121 }
116 122
117 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 150 public void sendObserveRequest(LwM2mClient client, TbLwM2MObserveRequest request, DownlinkRequestCallback<ObserveRequest, ObserveResponse> callback) {
119 151 validateVersionedId(client, request);
120 152 LwM2mPath resultIds = new LwM2mPath(request.getObjectId());
121 153 Set<Observation> observations = context.getServer().getObservationService().getObservations(client.getRegistration());
122 154 if (observations.stream().noneMatch(observation -> observation.getPath().equals(resultIds))) {
123 155 ObserveRequest downlink;
124   - ContentFormat contentFormat = getContentFormat(client, request);
  156 + ContentFormat contentFormat = getRequestContentFormat(client, request);
125 157 if (resultIds.isResource()) {
126 158 downlink = new ObserveRequest(contentFormat, resultIds.getObjectId(), resultIds.getObjectInstanceId(), resultIds.getResourceId());
127 159 } else if (resultIds.isObjectInstance()) {
... ... @@ -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 380 private WriteRequest getWriteRequestSingleResource(ResourceModel.Type type, ContentFormat contentFormat, int objectId, int instanceId, int resourceId, Object value) {
282 381 switch (type) {
283 382 case STRING: // String
... ... @@ -347,7 +446,7 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im
347 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 19
20 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 31 import org.eclipse.leshan.core.response.WriteAttributesResponse;
32 32 import org.eclipse.leshan.core.response.WriteResponse;
33 33 import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient;
  34 +import org.thingsboard.server.transport.lwm2m.server.uplink.DefaultLwM2MUplinkMsgHandler;
34 35
35 36 import java.util.List;
  37 +import java.util.Map;
36 38 import java.util.Set;
37 39
38 40 public interface LwM2mDownlinkMsgHandler {
39 41
40 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 47 void sendObserveRequest(LwM2mClient client, TbLwM2MObserveRequest request, DownlinkRequestCallback<ObserveRequest, ObserveResponse> callback);
43 48
44 49 void sendObserveAllRequest(LwM2mClient client, TbLwM2MObserveAllRequest request, DownlinkRequestCallback<TbLwM2MObserveAllRequest, Set<String>> callback);
... ... @@ -59,6 +64,8 @@ public interface LwM2mDownlinkMsgHandler {
59 64
60 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 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 24 public class TbLwM2MObserveRequest extends AbstractTbLwM2MTargetedDownlinkRequest<ObserveResponse> implements HasContentFormat {
25 25
26 26 @Getter
27   - private final ContentFormat contentFormat;
  27 + private final ContentFormat requestContentFormat;
28 28
29 29 @Builder
30   - private TbLwM2MObserveRequest(String versionedId, long timeout, ContentFormat contentFormat) {
  30 + private TbLwM2MObserveRequest(String versionedId, long timeout, ContentFormat requestContentFormat) {
31 31 super(versionedId, timeout);
32   - this.contentFormat = contentFormat;
  32 + this.requestContentFormat = requestContentFormat;
33 33 }
34 34
35 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 24 public class TbLwM2MReadRequest extends AbstractTbLwM2MTargetedDownlinkRequest<ReadResponse> implements HasContentFormat {
25 25
26 26 @Getter
27   - private final ContentFormat contentFormat;
  27 + private final ContentFormat requestContentFormat;
28 28
29 29 @Builder
30   - private TbLwM2MReadRequest(String versionedId, long timeout, ContentFormat contentFormat) {
  30 + private TbLwM2MReadRequest(String versionedId, long timeout, ContentFormat requestContentFormat) {
31 31 super(versionedId, timeout);
32   - this.contentFormat = contentFormat;
  32 + this.requestContentFormat = requestContentFormat;
33 33 }
34 34
35 35 @Override
... ...
... ... @@ -18,7 +18,6 @@ package org.thingsboard.server.transport.lwm2m.server.downlink;
18 18 import lombok.extern.slf4j.Slf4j;
19 19 import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient;
20 20 import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogService;
21   -import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mUplinkMsgHandler;
22 21
23 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 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 39 @Override
36 40 public void onSuccess(R request, T response) {
37 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 30 import org.eclipse.leshan.core.observation.Observation;
31 31 import org.eclipse.leshan.core.request.ObserveRequest;
32 32 import org.eclipse.leshan.core.request.ReadRequest;
  33 +import org.eclipse.leshan.core.request.WriteCompositeRequest;
33 34 import org.eclipse.leshan.core.request.WriteRequest;
34 35 import org.eclipse.leshan.core.response.ObserveResponse;
  36 +import org.eclipse.leshan.core.response.ReadCompositeResponse;
35 37 import org.eclipse.leshan.core.response.ReadResponse;
36 38 import org.eclipse.leshan.server.registration.Registration;
37 39 import org.springframework.context.annotation.Lazy;
38 40 import org.springframework.stereotype.Service;
39 41 import org.thingsboard.common.util.DonAsynchron;
40   -import org.thingsboard.server.cache.ota.OtaPackageDataCache;
41 42 import org.thingsboard.server.common.data.Device;
42 43 import org.thingsboard.server.common.data.DeviceProfile;
43 44 import org.thingsboard.server.common.data.StringUtils;
... ... @@ -83,8 +84,6 @@ import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MWriteAttrib
83 84 import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MWriteAttributesRequest;
84 85 import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogService;
85 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 87 import org.thingsboard.server.transport.lwm2m.server.rpc.LwM2MRpcRequestHandler;
89 88 import org.thingsboard.server.transport.lwm2m.server.store.TbLwM2MDtlsSessionStore;
90 89 import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl;
... ... @@ -94,6 +93,7 @@ import javax.annotation.PreDestroy;
94 93 import java.util.ArrayList;
95 94 import java.util.Collection;
96 95 import java.util.Collections;
  96 +import java.util.HashMap;
97 97 import java.util.HashSet;
98 98 import java.util.List;
99 99 import java.util.Map;
... ... @@ -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 374 * @param sessionInfo -
359 375 * @param deviceProfile -
... ... @@ -429,6 +445,17 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl
429 445 if (supportedObjects != null && supportedObjects.size() > 0) {
430 446 // #1
431 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 459 this.sendObserveRequests(lwM2MClient, profile, supportedObjects);
433 460 this.sendWriteAttributeRequests(lwM2MClient, profile, supportedObjects);
434 461 // Removed. Used only for debug.
... ... @@ -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 750 //TODO: review and optimize the logic to minimize number of the requests to device.
716 751 private void onDeviceProfileUpdate(List<LwM2mClient> clients, DeviceProfile deviceProfile) {
717 752 var oldProfile = clientContext.getProfile(deviceProfile.getUuidId());
... ...
... ... @@ -16,7 +16,9 @@
16 16 package org.thingsboard.server.transport.lwm2m.server.uplink;
17 17
18 18 import org.eclipse.leshan.core.observation.Observation;
  19 +import org.eclipse.leshan.core.request.WriteCompositeRequest;
19 20 import org.eclipse.leshan.core.request.WriteRequest;
  21 +import org.eclipse.leshan.core.response.ReadCompositeResponse;
20 22 import org.eclipse.leshan.core.response.ReadResponse;
21 23 import org.eclipse.leshan.server.registration.Registration;
22 24 import org.thingsboard.server.common.data.Device;
... ... @@ -40,6 +42,8 @@ public interface LwM2mUplinkMsgHandler {
40 42
41 43 void onUpdateValueAfterReadResponse(Registration registration, String path, ReadResponse response);
42 44
  45 + void onUpdateValueAfterReadCompositeResponse(Registration registration, String path, ReadCompositeResponse response);
  46 +
43 47 void onDeviceProfileUpdate(TransportProtos.SessionInfoProto sessionInfo, DeviceProfile deviceProfile);
44 48
45 49 void onDeviceUpdate(TransportProtos.SessionInfoProto sessionInfo, Device device, Optional<DeviceProfile> deviceProfileOpt);
... ... @@ -54,6 +58,8 @@ public interface LwM2mUplinkMsgHandler {
54 58
55 59 void onWriteResponseOk(LwM2mClient client, String path, WriteRequest request);
56 60
  61 + void onWriteCompositeResponseOk(LwM2mClient client, WriteCompositeRequest request);
  62 +
57 63 void onToTransportUpdateCredentials(TransportProtos.ToTransportUpdateCredentialsProto updateCredentials);
58 64
59 65 LwM2MTransportServerConfig getConfig();
... ...