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; | ... | ... |
... | ... | @@ -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(); | ... | ... |