Commit e33420d3a89264b3df099654eea8b3671ca0fbec
Committed by
GitHub
1 parent
9dcb7b9b
Lwm2m: firmwareUpdate (#4516)
* Lwm2m: firmwareUpdate * Lwm2m: firmwareUpdate with merge master * Lwm2m: firmwareUpdate cleaned * Lwm2m: delete Californium.properties * Lwm2m: merge with master
Showing
17 changed files
with
435 additions
and
208 deletions
... | ... | @@ -185,7 +185,7 @@ public class DefaultTbResourceService implements TbResourceService { |
185 | 185 | instance.setId(0); |
186 | 186 | List<LwM2mResourceObserve> resources = new ArrayList<>(); |
187 | 187 | obj.resources.forEach((k, v) -> { |
188 | - if (!v.operations.isExecutable()) { | |
188 | + if (v.operations.isReadable()) { | |
189 | 189 | LwM2mResourceObserve lwM2MResourceObserve = new LwM2mResourceObserve(k, v.name, false, false, false); |
190 | 190 | resources.add(lwM2MResourceObserve); |
191 | 191 | } | ... | ... |
... | ... | @@ -95,8 +95,8 @@ public class DataConstants { |
95 | 95 | |
96 | 96 | //firmware |
97 | 97 | //telemetry |
98 | - public static final String CURRENT_FIRMWARE_TITLE = "cur_fw_title"; | |
99 | - public static final String CURRENT_FIRMWARE_VERSION = "cur_fw_version"; | |
98 | + public static final String CURRENT_FIRMWARE_TITLE = "current_fw_title"; | |
99 | + public static final String CURRENT_FIRMWARE_VERSION = "current_fw_version"; | |
100 | 100 | public static final String TARGET_FIRMWARE_TITLE = "target_fw_title"; |
101 | 101 | public static final String TARGET_FIRMWARE_VERSION = "target_fw_version"; |
102 | 102 | public static final String TARGET_FIRMWARE_TS = "target_fw_ts"; | ... | ... |
... | ... | @@ -55,7 +55,7 @@ import static org.eclipse.californium.scandium.dtls.cipher.CipherSuite.TLS_ECDHE |
55 | 55 | import static org.eclipse.californium.scandium.dtls.cipher.CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8; |
56 | 56 | import static org.eclipse.californium.scandium.dtls.cipher.CipherSuite.TLS_PSK_WITH_AES_128_CBC_SHA256; |
57 | 57 | import static org.eclipse.californium.scandium.dtls.cipher.CipherSuite.TLS_PSK_WITH_AES_128_CCM_8; |
58 | -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.getCoapConfig; | |
58 | +import static org.thingsboard.server.transport.lwm2m.server.LwM2mNetworkConfig.getCoapConfig; | |
59 | 59 | |
60 | 60 | @Slf4j |
61 | 61 | @Component |
... | ... | @@ -93,7 +93,6 @@ public class LwM2MTransportBootstrapServerConfiguration { |
93 | 93 | builder.setCoapConfig(getCoapConfig(bootstrapPortNoSec, bootstrapSecurePort)); |
94 | 94 | |
95 | 95 | /** Define model provider (Create Models )*/ |
96 | -// builder.setModel(new StaticModel(contextS.getLwM2MTransportConfigServer().getModelsValueCommon())); | |
97 | 96 | |
98 | 97 | /** Create credentials */ |
99 | 98 | this.setServerWithCredentials(builder); | ... | ... |
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; | |
17 | + | |
18 | +import org.eclipse.californium.core.network.config.NetworkConfig; | |
19 | + | |
20 | +public class LwM2mNetworkConfig { | |
21 | + | |
22 | + public static NetworkConfig getCoapConfig(Integer serverPortNoSec, Integer serverSecurePort) { | |
23 | + NetworkConfig coapConfig = new NetworkConfig(); | |
24 | + coapConfig.setInt(NetworkConfig.Keys.COAP_PORT,serverPortNoSec); | |
25 | + coapConfig.setInt(NetworkConfig.Keys.COAP_SECURE_PORT,serverSecurePort); | |
26 | + /** | |
27 | + * Example:Property for large packet: | |
28 | + * #NetworkConfig config = new NetworkConfig(); | |
29 | + * #config.setInt(NetworkConfig.Keys.MAX_MESSAGE_SIZE,32); | |
30 | + * #config.setInt(NetworkConfig.Keys.PREFERRED_BLOCK_SIZE,32); | |
31 | + * #config.setInt(NetworkConfig.Keys.MAX_RESOURCE_BODY_SIZE,2048); | |
32 | + * #config.setInt(NetworkConfig.Keys.MAX_RETRANSMIT,3); | |
33 | + * #config.setInt(NetworkConfig.Keys.MAX_TRANSMIT_WAIT,120000); | |
34 | + */ | |
35 | + | |
36 | + /** | |
37 | + * Property to indicate if the response should always include the Block2 option \ | |
38 | + * when client request early blockwise negociation but the response can be sent on one packet. | |
39 | + * - value of false indicate that the server will respond without block2 option if no further blocks are required. | |
40 | + * - value of true indicate that the server will response with block2 option event if no further blocks are required. | |
41 | + * CoAP client will try to use block mode | |
42 | + * or adapt the block size when receiving a 4.13 Entity too large response code | |
43 | + */ | |
44 | + coapConfig.setBoolean(NetworkConfig.Keys.BLOCKWISE_STRICT_BLOCK2_OPTION, true); | |
45 | + /*** | |
46 | + * Property to indicate if the response should always include the Block2 option \ | |
47 | + * when client request early blockwise negociation but the response can be sent on one packet. | |
48 | + * - value of false indicate that the server will respond without block2 option if no further blocks are required. | |
49 | + * - value of true indicate that the server will response with block2 option event if no further blocks are required. | |
50 | + */ | |
51 | + coapConfig.setBoolean(NetworkConfig.Keys.BLOCKWISE_ENTITY_TOO_LARGE_AUTO_FAILOVER, true); | |
52 | + | |
53 | + coapConfig.setInt(NetworkConfig.Keys.BLOCKWISE_STATUS_LIFETIME, 300000); | |
54 | + /** | |
55 | + * !!! REQUEST_ENTITY_TOO_LARGE CODE=4.13 | |
56 | + * The maximum size of a resource body (in bytes) that will be accepted | |
57 | + * as the payload of a POST/PUT or the response to a GET request in a | |
58 | + * transparent> blockwise transfer. | |
59 | + * This option serves as a safeguard against excessive memory | |
60 | + * consumption when many resources contain large bodies that cannot be | |
61 | + * transferred in a single CoAP message. This option has no impact on | |
62 | + * *manually* managed blockwise transfers in which the blocks are handled individually. | |
63 | + * Note that this option does not prevent local clients or resource | |
64 | + * implementations from sending large bodies as part of a request or response to a peer. | |
65 | + * The default value of this property is DEFAULT_MAX_RESOURCE_BODY_SIZE = 8192 | |
66 | + * A value of {@code 0} turns off transparent handling of blockwise transfers altogether. | |
67 | + */ | |
68 | +// coapConfig.setInt(NetworkConfig.Keys.MAX_RESOURCE_BODY_SIZE, 8192); | |
69 | + coapConfig.setInt(NetworkConfig.Keys.MAX_RESOURCE_BODY_SIZE, 16384); | |
70 | + /** | |
71 | + * The default DTLS response matcher. | |
72 | + * Supported values are STRICT, RELAXED, or PRINCIPAL. | |
73 | + * The default value is STRICT. | |
74 | + * Create new instance of udp endpoint context matcher. | |
75 | + * Params: | |
76 | + * checkAddress | |
77 | + * – true with address check, (STRICT, UDP) | |
78 | + * - false, without | |
79 | + */ | |
80 | + coapConfig.setString(NetworkConfig.Keys.RESPONSE_MATCHING, "STRICT"); | |
81 | + /** | |
82 | + * https://tools.ietf.org/html/rfc7959#section-2.9.3 | |
83 | + * The block size (number of bytes) to use when doing a blockwise transfer. \ | |
84 | + * This value serves as the upper limit for block size in blockwise transfers | |
85 | + */ | |
86 | + coapConfig.setInt(NetworkConfig.Keys.PREFERRED_BLOCK_SIZE, 512); | |
87 | + /** | |
88 | + * The maximum payload size (in bytes) that can be transferred in a | |
89 | + * single message, i.e. without requiring a blockwise transfer. | |
90 | + * NB: this value MUST be adapted to the maximum message size supported by the transport layer. | |
91 | + * In particular, this value cannot exceed the network's MTU if UDP is used as the transport protocol | |
92 | + * DEFAULT_VALUE = 1024 | |
93 | + */ | |
94 | + coapConfig.setInt(NetworkConfig.Keys.MAX_MESSAGE_SIZE, 512); | |
95 | + | |
96 | + coapConfig.setInt(NetworkConfig.Keys.MAX_RETRANSMIT, 4); | |
97 | + | |
98 | + return coapConfig; | |
99 | + } | |
100 | +} | ... | ... |
... | ... | @@ -26,6 +26,7 @@ import org.eclipse.leshan.server.registration.RegistrationUpdate; |
26 | 26 | |
27 | 27 | import java.util.Collection; |
28 | 28 | |
29 | +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.LOG_LW2M_INFO; | |
29 | 30 | import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.convertPathFromObjectIdToIdVer; |
30 | 31 | |
31 | 32 | @Slf4j |
... | ... | @@ -85,17 +86,19 @@ public class LwM2mServerListener { |
85 | 86 | |
86 | 87 | @Override |
87 | 88 | public void cancelled(Observation observation) { |
88 | - log.info("Received notification cancelled from [{}] ", observation.getPath()); | |
89 | + String msg = String.format("%s: Cancel Observation %s.", LOG_LW2M_INFO, observation.getPath()); | |
90 | + service.sendLogsToThingsboard(msg, observation.getRegistrationId()); | |
91 | + log.trace(msg); | |
89 | 92 | } |
90 | 93 | |
91 | 94 | @Override |
92 | 95 | public void onResponse(Observation observation, Registration registration, ObserveResponse response) { |
93 | 96 | if (registration != null) { |
94 | 97 | try { |
95 | - service.onObservationResponse(registration, convertPathFromObjectIdToIdVer(observation.getPath().toString(), | |
98 | + service.onUpdateValueAfterReadResponse(registration, convertPathFromObjectIdToIdVer(observation.getPath().toString(), | |
96 | 99 | registration), response, null); |
97 | 100 | } catch (Exception e) { |
98 | - log.error("[{}] onResponse", e.toString()); | |
101 | + log.error("Observation/Read onResponse", e); | |
99 | 102 | |
100 | 103 | } |
101 | 104 | } |
... | ... | @@ -108,7 +111,10 @@ public class LwM2mServerListener { |
108 | 111 | |
109 | 112 | @Override |
110 | 113 | public void newObservation(Observation observation, Registration registration) { |
111 | - log.info("Received newObservation from [{}] endpoint [{}] ", observation.getPath(), registration.getEndpoint()); | |
114 | + String msg = String.format("%s: Successful start newObservation %s.", LOG_LW2M_INFO, | |
115 | + observation.getPath()); | |
116 | + service.sendLogsToThingsboard(msg, registration.getId()); | |
117 | + log.trace(msg); | |
112 | 118 | } |
113 | 119 | }; |
114 | 120 | ... | ... |
... | ... | @@ -25,7 +25,6 @@ import com.google.gson.JsonSyntaxException; |
25 | 25 | import com.google.gson.reflect.TypeToken; |
26 | 26 | import lombok.extern.slf4j.Slf4j; |
27 | 27 | import org.apache.commons.lang3.StringUtils; |
28 | -import org.eclipse.californium.core.network.config.NetworkConfig; | |
29 | 28 | import org.eclipse.leshan.core.attributes.Attribute; |
30 | 29 | import org.eclipse.leshan.core.attributes.AttributeSet; |
31 | 30 | import org.eclipse.leshan.core.model.ObjectModel; |
... | ... | @@ -40,7 +39,6 @@ import org.eclipse.leshan.core.node.codec.CodecException; |
40 | 39 | import org.eclipse.leshan.core.request.DownlinkRequest; |
41 | 40 | import org.eclipse.leshan.core.request.WriteAttributesRequest; |
42 | 41 | import org.eclipse.leshan.core.util.Hex; |
43 | -import org.eclipse.leshan.server.californium.LeshanServerBuilder; | |
44 | 42 | import org.eclipse.leshan.server.registration.Registration; |
45 | 43 | import org.nustaq.serialization.FSTConfiguration; |
46 | 44 | import org.thingsboard.server.common.data.DeviceProfile; |
... | ... | @@ -50,7 +48,6 @@ import org.thingsboard.server.common.transport.TransportServiceCallback; |
50 | 48 | import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; |
51 | 49 | import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientProfile; |
52 | 50 | |
53 | -import java.io.File; | |
54 | 51 | import java.io.IOException; |
55 | 52 | import java.util.ArrayList; |
56 | 53 | import java.util.Arrays; |
... | ... | @@ -72,7 +69,6 @@ import static org.thingsboard.server.common.data.lwm2m.LwM2mConstants.LWM2M_SEPA |
72 | 69 | @Slf4j |
73 | 70 | public class LwM2mTransportHandler { |
74 | 71 | |
75 | - // public static final String BASE_DEVICE_API_TOPIC = "v1/devices/me"; | |
76 | 72 | public static final String TRANSPORT_DEFAULT_LWM2M_VERSION = "1.0"; |
77 | 73 | public static final String CLIENT_LWM2M_SETTINGS = "clientLwM2mSettings"; |
78 | 74 | public static final String BOOTSTRAP = "bootstrap"; |
... | ... | @@ -85,19 +81,12 @@ public class LwM2mTransportHandler { |
85 | 81 | public static final String KEY_NAME = "keyName"; |
86 | 82 | public static final String OBSERVE_LWM2M = "observe"; |
87 | 83 | public static final String ATTRIBUTE_LWM2M = "attributeLwm2m"; |
88 | -// public static final String RESOURCE_VALUE = "resValue"; | |
89 | -// public static final String RESOURCE_TYPE = "resType"; | |
90 | 84 | |
91 | 85 | private static final String REQUEST = "/request"; |
92 | - // private static final String RESPONSE = "/response"; | |
93 | 86 | private static final String ATTRIBUTES = "/" + ATTRIBUTE; |
94 | 87 | public static final String TELEMETRIES = "/" + TELEMETRY; |
95 | - // public static final String ATTRIBUTES_RESPONSE = ATTRIBUTES + RESPONSE; | |
96 | 88 | public static final String ATTRIBUTES_REQUEST = ATTRIBUTES + REQUEST; |
97 | - // public static final String DEVICE_ATTRIBUTES_RESPONSE = ATTRIBUTES_RESPONSE + "/"; | |
98 | 89 | public static final String DEVICE_ATTRIBUTES_REQUEST = ATTRIBUTES_REQUEST + "/"; |
99 | -// public static final String DEVICE_ATTRIBUTES_TOPIC = BASE_DEVICE_API_TOPIC + ATTRIBUTES; | |
100 | -// public static final String DEVICE_TELEMETRY_TOPIC = BASE_DEVICE_API_TOPIC + TELEMETRIES; | |
101 | 90 | |
102 | 91 | public static final long DEFAULT_TIMEOUT = 2 * 60 * 1000L; // 2min in ms |
103 | 92 | |
... | ... | @@ -112,6 +101,11 @@ public class LwM2mTransportHandler { |
112 | 101 | |
113 | 102 | public static final String CLIENT_NOT_AUTHORIZED = "Client not authorized"; |
114 | 103 | |
104 | + public static final Integer FR_OBJECT_ID = 5; | |
105 | + public static final Integer FR_RESOURCE_VER_ID = 7; | |
106 | + public static final String FR_PATH_RESOURCE_VER_ID = LWM2M_SEPARATOR_PATH + FR_OBJECT_ID + LWM2M_SEPARATOR_PATH | |
107 | + + "0" + LWM2M_SEPARATOR_PATH + FR_RESOURCE_VER_ID; | |
108 | + | |
115 | 109 | public enum LwM2mTypeServer { |
116 | 110 | BOOTSTRAP(0, "bootstrap"), |
117 | 111 | CLIENT(1, "client"); |
... | ... | @@ -168,6 +162,8 @@ public class LwM2mTransportHandler { |
168 | 162 | WRITE_ATTRIBUTES(8, "WriteAttributes"), |
169 | 163 | DELETE(9, "Delete"); |
170 | 164 | |
165 | +// READ_INFO_FW(10, "ReadInfoFirmware"); | |
166 | + | |
171 | 167 | public int code; |
172 | 168 | public String type; |
173 | 169 | |
... | ... | @@ -190,21 +186,6 @@ public class LwM2mTransportHandler { |
190 | 186 | public static final String SERVICE_CHANNEL = "SERVICE"; |
191 | 187 | public static final String RESPONSE_CHANNEL = "RESP"; |
192 | 188 | |
193 | - public static NetworkConfig getCoapConfig(Integer serverPortNoSec, Integer serverSecurePort) { | |
194 | - NetworkConfig coapConfig; | |
195 | - File configFile = new File(NetworkConfig.DEFAULT_FILE_NAME); | |
196 | - if (configFile.isFile()) { | |
197 | - coapConfig = new NetworkConfig(); | |
198 | - coapConfig.load(configFile); | |
199 | - } else { | |
200 | - coapConfig = LeshanServerBuilder.createDefaultNetworkConfig(); | |
201 | - coapConfig.store(configFile); | |
202 | - } | |
203 | - coapConfig.setString("COAP_PORT", Integer.toString(serverPortNoSec)); | |
204 | - coapConfig.setString("COAP_SECURE_PORT", Integer.toString(serverSecurePort)); | |
205 | - return coapConfig; | |
206 | - } | |
207 | - | |
208 | 189 | public static boolean equalsResourceValue(Object valueOld, Object valueNew, ResourceModel.Type type, LwM2mPath resourcePath) throws CodecException { |
209 | 190 | switch (type) { |
210 | 191 | case BOOLEAN: | ... | ... |
... | ... | @@ -67,6 +67,7 @@ import static org.eclipse.californium.core.coap.CoAP.ResponseCode.CONTENT; |
67 | 67 | import static org.eclipse.leshan.core.ResponseCode.BAD_REQUEST; |
68 | 68 | import static org.eclipse.leshan.core.ResponseCode.NOT_FOUND; |
69 | 69 | import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.DEFAULT_TIMEOUT; |
70 | +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.FR_PATH_RESOURCE_VER_ID; | |
70 | 71 | import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.LOG_LW2M_ERROR; |
71 | 72 | import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.LOG_LW2M_INFO; |
72 | 73 | import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.LOG_LW2M_VALUE; |
... | ... | @@ -125,7 +126,6 @@ public class LwM2mTransportRequest { |
125 | 126 | public void sendAllRequest(Registration registration, String targetIdVer, LwM2mTypeOper typeOper, |
126 | 127 | String contentFormatName, Object params, long timeoutInMs, Lwm2mClientRpcRequest rpcRequest) { |
127 | 128 | try { |
128 | - | |
129 | 129 | String target = convertPathFromIdVerToObjectId(targetIdVer); |
130 | 130 | DownlinkRequest request = null; |
131 | 131 | ContentFormat contentFormat = contentFormatName != null ? ContentFormat.fromName(contentFormatName.toUpperCase()) : ContentFormat.DEFAULT; |
... | ... | @@ -145,11 +145,11 @@ public class LwM2mTransportRequest { |
145 | 145 | break; |
146 | 146 | case OBSERVE: |
147 | 147 | if (resultIds.isResource()) { |
148 | - request = new ObserveRequest(resultIds.getObjectId(), resultIds.getObjectInstanceId(), resultIds.getResourceId()); | |
148 | + request = new ObserveRequest(contentFormat, resultIds.getObjectId(), resultIds.getObjectInstanceId(), resultIds.getResourceId()); | |
149 | 149 | } else if (resultIds.isObjectInstance()) { |
150 | - request = new ObserveRequest(resultIds.getObjectId(), resultIds.getObjectInstanceId()); | |
150 | + request = new ObserveRequest(contentFormat, resultIds.getObjectId(), resultIds.getObjectInstanceId()); | |
151 | 151 | } else if (resultIds.getObjectId() >= 0) { |
152 | - request = new ObserveRequest(resultIds.getObjectId()); | |
152 | + request = new ObserveRequest(contentFormat, resultIds.getObjectId()); | |
153 | 153 | } |
154 | 154 | break; |
155 | 155 | case OBSERVE_CANCEL: |
... | ... | @@ -171,8 +171,6 @@ public class LwM2mTransportRequest { |
171 | 171 | break; |
172 | 172 | case WRITE_REPLACE: |
173 | 173 | // Request to write a <b>String Single-Instance Resource</b> using the TLV content format. |
174 | -// resource = lwM2MClient.getResourceModel(targetIdVer); | |
175 | -// if (contentFormat.equals(ContentFormat.TLV) && !resource.multiple) { | |
176 | 174 | resourceModel = lwM2MClient.getResourceModel(targetIdVer, this.lwM2mTransportContextServer.getLwM2MTransportConfigServer() |
177 | 175 | .getModelProvider()); |
178 | 176 | if (contentFormat.equals(ContentFormat.TLV)) { |
... | ... | @@ -181,7 +179,6 @@ public class LwM2mTransportRequest { |
181 | 179 | registration, rpcRequest); |
182 | 180 | } |
183 | 181 | // Mode.REPLACE && Request to write a <b>String Single-Instance Resource</b> using the given content format (TEXT, TLV, JSON) |
184 | -// else if (!contentFormat.equals(ContentFormat.TLV) && !resource.multiple) { | |
185 | 182 | else if (!contentFormat.equals(ContentFormat.TLV)) { |
186 | 183 | request = this.getWriteRequestSingleResource(contentFormat, resultIds.getObjectId(), |
187 | 184 | resultIds.getObjectInstanceId(), resultIds.getResourceId(), params, resourceModel.type, |
... | ... | @@ -215,13 +212,16 @@ public class LwM2mTransportRequest { |
215 | 212 | long finalTimeoutInMs = timeoutInMs; |
216 | 213 | lwM2MClient.getQueuedRequests().add(() -> sendRequest(registration, lwM2MClient, finalRequest, finalTimeoutInMs, rpcRequest)); |
217 | 214 | } catch (Exception e) { |
218 | - log.error("[{}] [{}] [{}] Failed to send downlink.", registration.getEndpoint(), targetIdVer, typeOper, e); | |
215 | + log.error("[{}] [{}] [{}] Failed to send downlink.", registration.getEndpoint(), targetIdVer, typeOper.name(), e); | |
216 | + } | |
217 | + } else if (OBSERVE_CANCEL == typeOper) { | |
218 | + log.trace("[{}], [{}] - [{}] SendRequest", registration.getEndpoint(), typeOper.name(), targetIdVer); | |
219 | + if (rpcRequest != null) { | |
220 | + rpcRequest.setInfoMsg(null); | |
221 | + serviceImpl.sentRpcRequest(rpcRequest, CONTENT.name(), null, null); | |
219 | 222 | } |
220 | - } else if (OBSERVE_CANCEL == typeOper && rpcRequest != null) { | |
221 | - rpcRequest.setInfoMsg(null); | |
222 | - serviceImpl.sentRpcRequest(rpcRequest, CONTENT.name(), null, null); | |
223 | 223 | } else { |
224 | - log.error("[{}], [{}] - [{}] error SendRequest", registration.getEndpoint(), typeOper, targetIdVer); | |
224 | + log.error("[{}], [{}] - [{}] error SendRequest", registration.getEndpoint(), typeOper.name(), targetIdVer); | |
225 | 225 | if (rpcRequest != null) { |
226 | 226 | String errorMsg = resourceModel == null ? String.format("Path %s not found in object version", targetIdVer) : "SendRequest - null"; |
227 | 227 | serviceImpl.sentRpcRequest(rpcRequest, NOT_FOUND.getName(), errorMsg, LOG_LW2M_ERROR); |
... | ... | @@ -236,8 +236,8 @@ public class LwM2mTransportRequest { |
236 | 236 | Set<String> observationPaths = observations.stream().map(observation -> observation.getPath().toString()).collect(Collectors.toUnmodifiableSet()); |
237 | 237 | String msg = String.format("%s: type operation %s observation paths - %s", LOG_LW2M_INFO, |
238 | 238 | OBSERVE_READ_ALL.type, observationPaths); |
239 | - serviceImpl.sendLogsToThingsboard(msg, registration); | |
240 | - log.info("[{}], [{}]", registration.getEndpoint(), msg); | |
239 | + serviceImpl.sendLogsToThingsboard(msg, registration.getId()); | |
240 | + log.trace("[{}] [{}], [{}]", typeOper.name(), registration.getEndpoint(), msg); | |
241 | 241 | if (rpcRequest != null) { |
242 | 242 | String valueMsg = String.format("Observation paths - %s", observationPaths); |
243 | 243 | serviceImpl.sentRpcRequest(rpcRequest, CONTENT.name(), valueMsg, LOG_LW2M_VALUE); |
... | ... | @@ -246,7 +246,7 @@ public class LwM2mTransportRequest { |
246 | 246 | } catch (Exception e) { |
247 | 247 | String msg = String.format("%s: type operation %s %s", LOG_LW2M_ERROR, |
248 | 248 | typeOper.name(), e.getMessage()); |
249 | - serviceImpl.sendLogsToThingsboard(msg, registration); | |
249 | + serviceImpl.sendLogsToThingsboard(msg, registration.getId()); | |
250 | 250 | throw new Exception(e); |
251 | 251 | } |
252 | 252 | } |
... | ... | @@ -261,45 +261,53 @@ public class LwM2mTransportRequest { |
261 | 261 | private void sendRequest(Registration registration, LwM2mClient lwM2MClient, DownlinkRequest request, long timeoutInMs, Lwm2mClientRpcRequest rpcRequest) { |
262 | 262 | leshanServer.send(registration, request, timeoutInMs, (ResponseCallback<?>) response -> { |
263 | 263 | if (!lwM2MClient.isInit()) { |
264 | - lwM2MClient.initValue(this.serviceImpl, convertPathFromObjectIdToIdVer(request.getPath().toString(), registration)); | |
264 | + lwM2MClient.initReadValue(this.serviceImpl, convertPathFromObjectIdToIdVer(request.getPath().toString(), registration)); | |
265 | 265 | } |
266 | 266 | if (CoAP.ResponseCode.isSuccess(((Response) response.getCoapResponse()).getCode())) { |
267 | 267 | this.handleResponse(registration, request.getPath().toString(), response, request, rpcRequest); |
268 | - if (request instanceof WriteRequest && ((WriteRequest) request).isReplaceRequest()) { | |
269 | - LwM2mNode node = ((WriteRequest) request).getNode(); | |
270 | - Object value = this.converter.convertValue(((LwM2mSingleResource) node).getValue(), | |
271 | - ((LwM2mSingleResource) node).getType(), ResourceModel.Type.STRING, request.getPath()); | |
272 | - String msg = String.format("%s: sendRequest Replace: CoapCde - %s Lwm2m code - %d name - %s Resource path - %s value - %s SendRequest to Client", | |
273 | - LOG_LW2M_INFO, ((Response) response.getCoapResponse()).getCode(), response.getCode().getCode(), | |
274 | - response.getCode().getName(), request.getPath().toString(), value); | |
275 | - serviceImpl.sendLogsToThingsboard(msg, registration); | |
276 | - log.info("[{}] [{}] - [{}] [{}] Update SendRequest[{}]", registration.getEndpoint(), | |
277 | - ((Response) response.getCoapResponse()).getCode(), response.getCode(), | |
278 | - request.getPath().toString(), value); | |
279 | - serviceImpl.sentRpcRequest(rpcRequest, response.getCode().getName(), null, LOG_LW2M_INFO); | |
280 | - } | |
281 | 268 | } else { |
282 | - String msg = String.format("%s: sendRequest: CoapCode - %s Lwm2m code - %d name - %s Resource path - %s SendRequest to Client", LOG_LW2M_ERROR, | |
269 | + String msg = String.format("%s: SendRequest %s: CoapCode - %s Lwm2m code - %d name - %s Resource path - %s", LOG_LW2M_ERROR, request.getClass().getName().toString(), | |
283 | 270 | ((Response) response.getCoapResponse()).getCode(), response.getCode().getCode(), response.getCode().getName(), request.getPath().toString()); |
284 | - serviceImpl.sendLogsToThingsboard(msg, registration); | |
285 | - log.error("[{}], [{}] - [{}] [{}] error SendRequest", registration.getEndpoint(), ((Response) response.getCoapResponse()).getCode(), response.getCode(), request.getPath().toString()); | |
271 | + serviceImpl.sendLogsToThingsboard(msg, registration.getId()); | |
272 | + log.error("[{}] [{}], [{}] - [{}] [{}] error SendRequest", request.getClass().getName().toString(), registration.getEndpoint(), | |
273 | + ((Response) response.getCoapResponse()).getCode(), response.getCode(), request.getPath().toString()); | |
274 | + if (!lwM2MClient.isInit()) { | |
275 | + lwM2MClient.initReadValue(this.serviceImpl, convertPathFromObjectIdToIdVer(request.getPath().toString(), registration)); | |
276 | + } | |
286 | 277 | if (rpcRequest != null) { |
287 | 278 | serviceImpl.sentRpcRequest(rpcRequest, response.getCode().getName(), response.getErrorMessage(), LOG_LW2M_ERROR); |
288 | 279 | } |
280 | + /** Not Found | |
281 | + * set setClient_fw_version = empty | |
282 | + **/ | |
283 | + if (FR_PATH_RESOURCE_VER_ID.equals(request.getPath().toString()) && lwM2MClient.isUpdateFw()) { | |
284 | + lwM2MClient.setUpdateFw(false); | |
285 | + lwM2MClient.getFrUpdate().setClientFwVersion(""); | |
286 | + log.warn("updateFirmwareClient1"); | |
287 | + serviceImpl.updateFirmwareClient(lwM2MClient); | |
288 | + } | |
289 | 289 | } |
290 | 290 | }, e -> { |
291 | + /** version == null | |
292 | + * set setClient_fw_version = empty | |
293 | + **/ | |
294 | + if (FR_PATH_RESOURCE_VER_ID.equals(request.getPath().toString()) && lwM2MClient.isUpdateFw()) { | |
295 | + lwM2MClient.setUpdateFw(false); | |
296 | + lwM2MClient.getFrUpdate().setClientFwVersion(""); | |
297 | + log.warn("updateFirmwareClient2"); | |
298 | + serviceImpl.updateFirmwareClient(lwM2MClient); | |
299 | + } | |
291 | 300 | if (!lwM2MClient.isInit()) { |
292 | - lwM2MClient.initValue(this.serviceImpl, convertPathFromObjectIdToIdVer(request.getPath().toString(), registration)); | |
301 | + lwM2MClient.initReadValue(this.serviceImpl, convertPathFromObjectIdToIdVer(request.getPath().toString(), registration)); | |
293 | 302 | } |
294 | - String msg = String.format("%s: sendRequest: Resource path - %s msg error - %s SendRequest to Client", | |
295 | - LOG_LW2M_ERROR, request.getPath().toString(), e.getMessage()); | |
296 | - serviceImpl.sendLogsToThingsboard(msg, registration); | |
297 | - log.error("[{}] - [{}] error SendRequest", request.getPath().toString(), e.toString()); | |
303 | + String msg = String.format("%s: SendRequest %s: Resource path - %s msg error - %s", | |
304 | + LOG_LW2M_ERROR, request.getClass().getName().toString(), request.getPath().toString(), e.getMessage()); | |
305 | + serviceImpl.sendLogsToThingsboard(msg, registration.getId()); | |
306 | + log.error("[{}] [{}] - [{}] error SendRequest", request.getClass().getName().toString(), request.getPath().toString(), e.toString()); | |
298 | 307 | if (rpcRequest != null) { |
299 | 308 | serviceImpl.sentRpcRequest(rpcRequest, CoAP.CodeClass.ERROR_RESPONSE.name(), e.getMessage(), LOG_LW2M_ERROR); |
300 | 309 | } |
301 | 310 | }); |
302 | - | |
303 | 311 | } |
304 | 312 | |
305 | 313 | private WriteRequest getWriteRequestSingleResource(ContentFormat contentFormat, Integer objectId, Integer instanceId, |
... | ... | @@ -323,7 +331,9 @@ public class LwM2mTransportRequest { |
323 | 331 | Date date = new Date(Long.decode(value.toString())); |
324 | 332 | return (contentFormat == null) ? new WriteRequest(objectId, instanceId, resourceId, date) : new WriteRequest(contentFormat, objectId, instanceId, resourceId, date); |
325 | 333 | case OPAQUE: // byte[] value, base64 |
326 | - return (contentFormat == null) ? new WriteRequest(objectId, instanceId, resourceId, Hex.decodeHex(value.toString().toCharArray())) : new WriteRequest(contentFormat, objectId, instanceId, resourceId, Hex.decodeHex(value.toString().toCharArray())); | |
334 | + byte[] valueRequest = value instanceof byte[] ? (byte[]) value : Hex.decodeHex(value.toString().toCharArray()); | |
335 | + return (contentFormat == null) ? new WriteRequest(objectId, instanceId, resourceId, valueRequest) : | |
336 | + new WriteRequest(contentFormat, objectId, instanceId, resourceId, valueRequest); | |
327 | 337 | default: |
328 | 338 | } |
329 | 339 | } |
... | ... | @@ -337,7 +347,7 @@ public class LwM2mTransportRequest { |
337 | 347 | String patn = "/" + objectId + "/" + instanceId + "/" + resourceId; |
338 | 348 | String msg = String.format(LOG_LW2M_ERROR + ": NumberFormatException: Resource path - %s type - %s value - %s msg error - %s SendRequest to Client", |
339 | 349 | patn, type, value, e.toString()); |
340 | - serviceImpl.sendLogsToThingsboard(msg, registration); | |
350 | + serviceImpl.sendLogsToThingsboard(msg, registration.getId()); | |
341 | 351 | log.error("Path: [{}] type: [{}] value: [{}] errorMsg: [{}]]", patn, type, value, e.toString()); |
342 | 352 | if (rpcRequest != null) { |
343 | 353 | String errorMsg = String.format("NumberFormatException: Resource path - %s type - %s value - %s", patn, type, value); |
... | ... | @@ -369,7 +379,7 @@ public class LwM2mTransportRequest { |
369 | 379 | DownlinkRequest request, Lwm2mClientRpcRequest rpcRequest) { |
370 | 380 | String pathIdVer = convertPathFromObjectIdToIdVer(path, registration); |
371 | 381 | if (response instanceof ReadResponse) { |
372 | - serviceImpl.onObservationResponse(registration, pathIdVer, (ReadResponse) response, rpcRequest); | |
382 | + serviceImpl.onUpdateValueAfterReadResponse(registration, pathIdVer, (ReadResponse) response, rpcRequest); | |
373 | 383 | } else if (response instanceof CancelObservationResponse) { |
374 | 384 | log.info("[{}] Path [{}] CancelObservationResponse 3_Send", pathIdVer, response); |
375 | 385 | |
... | ... | @@ -389,14 +399,33 @@ public class LwM2mTransportRequest { |
389 | 399 | } else if (response instanceof WriteAttributesResponse) { |
390 | 400 | log.info("[{}] Path [{}] WriteAttributesResponse 8_Send", pathIdVer, response); |
391 | 401 | } else if (response instanceof WriteResponse) { |
392 | - log.info("[{}] Path [{}] WriteAttributesResponse 9_Send", pathIdVer, response); | |
402 | + log.info("[{}] Path [{}] WriteResponse 9_Send", pathIdVer, response); | |
403 | + this.infoWriteResponse(registration, response, request); | |
393 | 404 | serviceImpl.onWriteResponseOk(registration, pathIdVer, (WriteRequest) request); |
394 | 405 | } |
395 | - if (rpcRequest != null && (response instanceof ExecuteResponse | |
396 | - || response instanceof WriteAttributesResponse | |
397 | - || response instanceof DeleteResponse)) { | |
398 | - rpcRequest.setInfoMsg(null); | |
399 | - serviceImpl.sentRpcRequest(rpcRequest, response.getCode().getName(), null, null); | |
406 | + if (rpcRequest != null) { | |
407 | + if (response instanceof ExecuteResponse | |
408 | + || response instanceof WriteAttributesResponse | |
409 | + || response instanceof DeleteResponse) { | |
410 | + rpcRequest.setInfoMsg(null); | |
411 | + serviceImpl.sentRpcRequest(rpcRequest, response.getCode().getName(), null, null); | |
412 | + } else if (response instanceof WriteResponse) { | |
413 | + serviceImpl.sentRpcRequest(rpcRequest, response.getCode().getName(), null, LOG_LW2M_INFO); | |
414 | + } | |
400 | 415 | } |
401 | 416 | } |
417 | + | |
418 | + private void infoWriteResponse(Registration registration, LwM2mResponse response, | |
419 | + DownlinkRequest request) { | |
420 | + LwM2mNode node = ((WriteRequest) request).getNode(); | |
421 | + Object value = this.converter.convertValue(((LwM2mSingleResource) node).getValue(), | |
422 | + ((LwM2mSingleResource) node).getType(), ResourceModel.Type.STRING, request.getPath()); | |
423 | + String msg = String.format("%s: Update finished successfully: CoapCde - %s Lwm2m code - %d name - %s Resource path - %s value - %s", | |
424 | + LOG_LW2M_INFO, ((Response) response.getCoapResponse()).getCode(), response.getCode().getCode(), | |
425 | + response.getCode().getName(), request.getPath().toString(), value); | |
426 | + serviceImpl.sendLogsToThingsboard(msg, registration.getId()); | |
427 | + log.warn("[{}] [{}] [{}] - [{}] [{}] Update finished successfully: [{}]", request.getClass().getName().toString(), registration.getEndpoint(), | |
428 | + ((Response) response.getCoapResponse()).getCode(), response.getCode(), | |
429 | + request.getPath().toString(), value); | |
430 | + } | |
402 | 431 | } | ... | ... |
... | ... | @@ -16,6 +16,8 @@ |
16 | 16 | package org.thingsboard.server.transport.lwm2m.server; |
17 | 17 | |
18 | 18 | import lombok.extern.slf4j.Slf4j; |
19 | +import org.eclipse.californium.core.network.config.NetworkConfig; | |
20 | +import org.eclipse.californium.core.network.stack.BlockwiseLayer; | |
19 | 21 | import org.eclipse.californium.scandium.config.DtlsConnectorConfig; |
20 | 22 | import org.eclipse.leshan.core.node.codec.DefaultLwM2mNodeDecoder; |
21 | 23 | import org.eclipse.leshan.core.node.codec.DefaultLwM2mNodeEncoder; |
... | ... | @@ -57,7 +59,7 @@ import static org.eclipse.californium.scandium.dtls.cipher.CipherSuite.TLS_ECDHE |
57 | 59 | import static org.eclipse.californium.scandium.dtls.cipher.CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8; |
58 | 60 | import static org.eclipse.californium.scandium.dtls.cipher.CipherSuite.TLS_PSK_WITH_AES_128_CBC_SHA256; |
59 | 61 | import static org.eclipse.californium.scandium.dtls.cipher.CipherSuite.TLS_PSK_WITH_AES_128_CCM_8; |
60 | -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.getCoapConfig; | |
62 | +import static org.thingsboard.server.transport.lwm2m.server.LwM2mNetworkConfig.getCoapConfig; | |
61 | 63 | |
62 | 64 | @Slf4j |
63 | 65 | @Component |
... | ... | @@ -92,7 +94,10 @@ public class LwM2mTransportServerConfiguration { |
92 | 94 | /** Use a magic converter to support bad type send by the UI. */ |
93 | 95 | builder.setEncoder(new DefaultLwM2mNodeEncoder(LwM2mValueConverterImpl.getInstance())); |
94 | 96 | |
97 | + | |
95 | 98 | /** Create CoAP Config */ |
99 | + NetworkConfig networkConfig = getCoapConfig(serverPortNoSec, serverSecurePort); | |
100 | + BlockwiseLayer blockwiseLayer = new BlockwiseLayer(networkConfig); | |
96 | 101 | builder.setCoapConfig(getCoapConfig(serverPortNoSec, serverSecurePort)); |
97 | 102 | |
98 | 103 | /** Define model provider (Create Models )*/ |
... | ... | @@ -110,6 +115,7 @@ public class LwM2mTransportServerConfiguration { |
110 | 115 | |
111 | 116 | /** Create DTLS Config */ |
112 | 117 | DtlsConnectorConfig.Builder dtlsConfig = new DtlsConnectorConfig.Builder(); |
118 | + dtlsConfig.setServerOnly(true); | |
113 | 119 | dtlsConfig.setRecommendedSupportedGroupsOnly(this.context.getLwM2MTransportConfigServer().isRecommendedSupportedGroups()); |
114 | 120 | dtlsConfig.setRecommendedCipherSuitesOnly(this.context.getLwM2MTransportConfigServer().isRecommendedCiphers()); |
115 | 121 | if (this.pskMode) { | ... | ... |
... | ... | @@ -39,7 +39,7 @@ public interface LwM2mTransportService extends TbTransportService { |
39 | 39 | |
40 | 40 | void setCancelObservations(Registration registration); |
41 | 41 | |
42 | - void onObservationResponse(Registration registration, String path, ReadResponse response, Lwm2mClientRpcRequest rpcRequest); | |
42 | + void onUpdateValueAfterReadResponse(Registration registration, String path, ReadResponse response, Lwm2mClientRpcRequest rpcRequest); | |
43 | 43 | |
44 | 44 | void onAttributeUpdate(TransportProtos.AttributeUpdateNotificationMsg msg, TransportProtos.SessionInfoProto sessionInfo); |
45 | 45 | |
... | ... | @@ -60,6 +60,4 @@ public interface LwM2mTransportService extends TbTransportService { |
60 | 60 | void doTrigger(Registration registration, String path); |
61 | 61 | |
62 | 62 | void doDisconnect(TransportProtos.SessionInfoProto sessionInfo); |
63 | - | |
64 | - | |
65 | 63 | } | ... | ... |
... | ... | @@ -38,10 +38,12 @@ import org.eclipse.leshan.server.registration.Registration; |
38 | 38 | import org.springframework.context.annotation.Lazy; |
39 | 39 | import org.springframework.stereotype.Service; |
40 | 40 | import org.thingsboard.common.util.JacksonUtil; |
41 | +import org.thingsboard.server.cache.firmware.FirmwareDataCache; | |
41 | 42 | import org.thingsboard.server.common.data.Device; |
42 | 43 | import org.thingsboard.server.common.data.DeviceProfile; |
43 | -import org.thingsboard.server.common.data.DeviceTransportType; | |
44 | +import org.thingsboard.server.common.data.id.FirmwareId; | |
44 | 45 | import org.thingsboard.server.common.transport.TransportService; |
46 | +import org.thingsboard.server.common.transport.TransportServiceCallback; | |
45 | 47 | import org.thingsboard.server.common.transport.adaptor.AdaptorException; |
46 | 48 | import org.thingsboard.server.common.transport.service.DefaultTransportService; |
47 | 49 | import org.thingsboard.server.gen.transport.TransportProtos; |
... | ... | @@ -77,9 +79,12 @@ import java.util.stream.Collectors; |
77 | 79 | |
78 | 80 | import static org.eclipse.californium.core.coap.CoAP.ResponseCode.BAD_REQUEST; |
79 | 81 | import static org.eclipse.leshan.core.attributes.Attribute.OBJECT_VERSION; |
82 | +import static org.thingsboard.server.common.data.DataConstants.FIRMWARE_VERSION; | |
83 | +import static org.thingsboard.server.common.data.lwm2m.LwM2mConstants.LWM2M_SEPARATOR_KEY; | |
80 | 84 | import static org.thingsboard.server.common.data.lwm2m.LwM2mConstants.LWM2M_SEPARATOR_PATH; |
81 | 85 | import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.CLIENT_NOT_AUTHORIZED; |
82 | 86 | import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.DEVICE_ATTRIBUTES_REQUEST; |
87 | +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.FR_PATH_RESOURCE_VER_ID; | |
83 | 88 | import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.LOG_LW2M_ERROR; |
84 | 89 | import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.LOG_LW2M_INFO; |
85 | 90 | import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.LOG_LW2M_VALUE; |
... | ... | @@ -110,6 +115,8 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService { |
110 | 115 | private ExecutorService executorUpdateRegistered; |
111 | 116 | private ExecutorService executorUnRegistered; |
112 | 117 | private LwM2mValueConverterImpl converter; |
118 | + private FirmwareDataCache firmwareDataCache; | |
119 | + | |
113 | 120 | |
114 | 121 | private final TransportService transportService; |
115 | 122 | |
... | ... | @@ -121,12 +128,15 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService { |
121 | 128 | |
122 | 129 | private final LwM2mTransportRequest lwM2mTransportRequest; |
123 | 130 | |
124 | - public LwM2mTransportServiceImpl(TransportService transportService, LwM2mTransportContextServer lwM2mTransportContextServer, LwM2mClientContext lwM2mClientContext, LeshanServer leshanServer, @Lazy LwM2mTransportRequest lwM2mTransportRequest) { | |
131 | + public LwM2mTransportServiceImpl(TransportService transportService, LwM2mTransportContextServer lwM2mTransportContextServer, | |
132 | + LwM2mClientContext lwM2mClientContext, LeshanServer leshanServer, | |
133 | + @Lazy LwM2mTransportRequest lwM2mTransportRequest, FirmwareDataCache firmwareDataCache) { | |
125 | 134 | this.transportService = transportService; |
126 | 135 | this.lwM2mTransportContextServer = lwM2mTransportContextServer; |
127 | 136 | this.lwM2mClientContext = lwM2mClientContext; |
128 | 137 | this.leshanServer = leshanServer; |
129 | 138 | this.lwM2mTransportRequest = lwM2mTransportRequest; |
139 | + this.firmwareDataCache = firmwareDataCache; | |
130 | 140 | } |
131 | 141 | |
132 | 142 | @PostConstruct |
... | ... | @@ -168,8 +178,9 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService { |
168 | 178 | transportService.process(sessionInfo, DefaultTransportService.getSessionEventMsg(SessionEvent.OPEN), null); |
169 | 179 | transportService.process(sessionInfo, TransportProtos.SubscribeToAttributeUpdatesMsg.newBuilder().build(), null); |
170 | 180 | transportService.process(sessionInfo, TransportProtos.SubscribeToRPCMsg.newBuilder().build(), null); |
181 | + this.getInfoFirmwareUpdate(lwM2MClient); | |
171 | 182 | this.initLwM2mFromClientValue(registration, lwM2MClient); |
172 | - this.sendLogsToThingsboard(LOG_LW2M_INFO + ": Client create after Registration", registration); | |
183 | + this.sendLogsToThingsboard(LOG_LW2M_INFO + ": Client create after Registration", registration.getId()); | |
173 | 184 | } else { |
174 | 185 | log.error("Client: [{}] onRegistered [{}] name [{}] sessionInfo ", registration.getId(), registration.getEndpoint(), null); |
175 | 186 | } |
... | ... | @@ -224,7 +235,7 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService { |
224 | 235 | executorUnRegistered.submit(() -> { |
225 | 236 | try { |
226 | 237 | this.setCancelObservations(registration); |
227 | - this.sendLogsToThingsboard(LOG_LW2M_INFO + ": Client unRegistration", registration); | |
238 | + this.sendLogsToThingsboard(LOG_LW2M_INFO + ": Client unRegistration", registration.getId()); | |
228 | 239 | this.closeClientSession(registration); |
229 | 240 | } catch (Throwable t) { |
230 | 241 | log.error("[{}] endpoint [{}] error Unable un registration.", registration.getEndpoint(), t); |
... | ... | @@ -257,7 +268,7 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService { |
257 | 268 | @Override |
258 | 269 | public void onSleepingDev(Registration registration) { |
259 | 270 | log.info("[{}] [{}] Received endpoint Sleeping version event", registration.getId(), registration.getEndpoint()); |
260 | - this.sendLogsToThingsboard(LOG_LW2M_INFO + ": Client is sleeping!", registration); | |
271 | + this.sendLogsToThingsboard(LOG_LW2M_INFO + ": Client is sleeping!", registration.getId()); | |
261 | 272 | |
262 | 273 | //TODO: associate endpointId with device information. |
263 | 274 | } |
... | ... | @@ -280,7 +291,7 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService { |
280 | 291 | * @param response - observe |
281 | 292 | */ |
282 | 293 | @Override |
283 | - public void onObservationResponse(Registration registration, String path, ReadResponse response, Lwm2mClientRpcRequest rpcRequest) { | |
294 | + public void onUpdateValueAfterReadResponse(Registration registration, String path, ReadResponse response, Lwm2mClientRpcRequest rpcRequest) { | |
284 | 295 | if (response.getContent() != null) { |
285 | 296 | if (response.getContent() instanceof LwM2mObject) { |
286 | 297 | LwM2mObject lwM2mObject = (LwM2mObject) response.getContent(); |
... | ... | @@ -304,20 +315,26 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService { |
304 | 315 | |
305 | 316 | /** |
306 | 317 | * Update - send request in change value resources in Client |
307 | - * Path to resources from profile equal keyName or from ModelObject equal name | |
308 | - * Only for resources: isWritable && isPresent as attribute in profile -> LwM2MClientProfile (format: CamelCase) | |
309 | - * Delete - nothing * | |
318 | + * 1. FirmwareUpdate: | |
319 | + * - If msg.getSharedUpdatedList().forEach(tsKvProto -> {tsKvProto.getKv().getKey().indexOf(FIRMWARE_UPDATE_PREFIX, 0) == 0 | |
320 | + * 2. Shared Other AttributeUpdate | |
321 | + * -- Path to resources from profile equal keyName or from ModelObject equal name | |
322 | + * -- Only for resources: isWritable && isPresent as attribute in profile -> LwM2MClientProfile (format: CamelCase) | |
323 | + * 3. Delete - nothing | |
310 | 324 | * |
311 | 325 | * @param msg - |
312 | 326 | */ |
313 | 327 | @Override |
314 | 328 | public void onAttributeUpdate(AttributeUpdateNotificationMsg msg, TransportProtos.SessionInfoProto sessionInfo) { |
329 | + LwM2mClient lwM2MClient = lwM2mClientContext.getLwM2mClient(new UUID(sessionInfo.getSessionIdMSB(), sessionInfo.getSessionIdLSB())); | |
315 | 330 | if (msg.getSharedUpdatedCount() > 0) { |
316 | 331 | msg.getSharedUpdatedList().forEach(tsKvProto -> { |
317 | 332 | String pathName = tsKvProto.getKv().getKey(); |
318 | 333 | String pathIdVer = this.getPresentPathIntoProfile(sessionInfo, pathName); |
319 | 334 | Object valueNew = this.lwM2mTransportContextServer.getValueFromKvProto(tsKvProto.getKv()); |
320 | - LwM2mClient lwM2MClient = lwM2mClientContext.getLwM2mClient(new UUID(sessionInfo.getSessionIdMSB(), sessionInfo.getSessionIdLSB())); | |
335 | + if (FIRMWARE_VERSION.equals(pathName) && !valueNew.equals(lwM2MClient.getFrUpdate().getCurrentFwVersion())) { | |
336 | + this.getInfoFirmwareUpdate(lwM2MClient); | |
337 | + } | |
321 | 338 | if (pathIdVer != null) { |
322 | 339 | ResourceModel resourceModel = lwM2MClient.getResourceModel(pathIdVer, this.lwM2mTransportContextServer.getLwM2MTransportConfigServer() |
323 | 340 | .getModelProvider()); |
... | ... | @@ -327,19 +344,26 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService { |
327 | 344 | log.error("Resource path - [{}] value - [{}] is not Writable and cannot be updated", pathIdVer, valueNew); |
328 | 345 | String logMsg = String.format("%s: attributeUpdate: Resource path - %s value - %s is not Writable and cannot be updated", |
329 | 346 | LOG_LW2M_ERROR, pathIdVer, valueNew); |
330 | - this.sendLogsToThingsboard(logMsg, lwM2MClient.getRegistration()); | |
347 | + this.sendLogsToThingsboard(logMsg, lwM2MClient.getRegistration().getId()); | |
331 | 348 | } |
332 | 349 | } else { |
333 | 350 | log.error("Resource name name - [{}] value - [{}] is not present as attribute/telemetry in profile and cannot be updated", pathName, valueNew); |
334 | 351 | String logMsg = String.format("%s: attributeUpdate: attribute name - %s value - %s is not present as attribute in profile and cannot be updated", |
335 | 352 | LOG_LW2M_ERROR, pathName, valueNew); |
336 | - this.sendLogsToThingsboard(logMsg, lwM2MClient.getRegistration()); | |
353 | + this.sendLogsToThingsboard(logMsg, lwM2MClient.getRegistration().getId()); | |
337 | 354 | } |
355 | + | |
338 | 356 | }); |
339 | 357 | } else if (msg.getSharedDeletedCount() > 0) { |
358 | + msg.getSharedUpdatedList().forEach(tsKvProto -> { | |
359 | + String pathName = tsKvProto.getKv().getKey(); | |
360 | + Object valueNew = this.lwM2mTransportContextServer.getValueFromKvProto(tsKvProto.getKv()); | |
361 | + if (FIRMWARE_VERSION.equals(pathName) && !valueNew.equals(lwM2MClient.getFrUpdate().getCurrentFwVersion())) { | |
362 | + lwM2MClient.getFrUpdate().setCurrentFwVersion((String) valueNew); | |
363 | + } | |
364 | + }); | |
340 | 365 | log.info("[{}] delete [{}] onAttributeUpdate", msg.getSharedDeletedList(), sessionInfo); |
341 | 366 | } |
342 | - | |
343 | 367 | } |
344 | 368 | |
345 | 369 | /** |
... | ... | @@ -455,23 +479,21 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService { |
455 | 479 | } |
456 | 480 | if (rpcRequest.has(lwm2mClientRpcRequest.paramsKey) && rpcRequest.get(lwm2mClientRpcRequest.paramsKey).isJsonObject()) { |
457 | 481 | lwm2mClientRpcRequest.setParams(new Gson().fromJson(rpcRequest.get(lwm2mClientRpcRequest.paramsKey) |
458 | - .getAsJsonObject().toString(), new TypeToken<ConcurrentHashMap<String, Object>>() { | |
459 | - }.getType())); | |
482 | + .getAsJsonObject().toString(), new TypeToken<ConcurrentHashMap<String, Object>>() { | |
483 | + }.getType())); | |
460 | 484 | } |
461 | 485 | lwm2mClientRpcRequest.setSessionInfo(sessionInfo); |
462 | 486 | if (OBSERVE_READ_ALL != lwm2mClientRpcRequest.getTypeOper() && lwm2mClientRpcRequest.getTargetIdVer() == null) { |
463 | 487 | lwm2mClientRpcRequest.setErrorMsg(lwm2mClientRpcRequest.targetIdVerKey + " and " + |
464 | 488 | lwm2mClientRpcRequest.keyNameKey + " is null or bad format"); |
465 | - } | |
466 | - else if ((EXECUTE == lwm2mClientRpcRequest.getTypeOper() | |
489 | + } else if ((EXECUTE == lwm2mClientRpcRequest.getTypeOper() | |
467 | 490 | || WRITE_REPLACE == lwm2mClientRpcRequest.getTypeOper()) |
468 | - && lwm2mClientRpcRequest.getTargetIdVer() !=null | |
491 | + && lwm2mClientRpcRequest.getTargetIdVer() != null | |
469 | 492 | && !(new LwM2mPath(convertPathFromIdVerToObjectId(lwm2mClientRpcRequest.getTargetIdVer())).isResource() |
470 | 493 | || new LwM2mPath(convertPathFromIdVerToObjectId(lwm2mClientRpcRequest.getTargetIdVer())).isResourceInstance())) { |
471 | - lwm2mClientRpcRequest.setErrorMsg("Invalid parameter " + lwm2mClientRpcRequest.targetIdVerKey | |
494 | + lwm2mClientRpcRequest.setErrorMsg("Invalid parameter " + lwm2mClientRpcRequest.targetIdVerKey | |
472 | 495 | + ". Only Resource or ResourceInstance can be this operation"); |
473 | - } | |
474 | - else if (WRITE_UPDATE == lwm2mClientRpcRequest.getTypeOper()){ | |
496 | + } else if (WRITE_UPDATE == lwm2mClientRpcRequest.getTypeOper()) { | |
475 | 497 | lwm2mClientRpcRequest.setErrorMsg("Procedures In Development..."); |
476 | 498 | } |
477 | 499 | } else { |
... | ... | @@ -483,23 +505,23 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService { |
483 | 505 | return lwm2mClientRpcRequest; |
484 | 506 | } |
485 | 507 | |
486 | - public void sentRpcRequest (Lwm2mClientRpcRequest rpcRequest, String requestCode, String msg, String typeMsg) { | |
508 | + public void sentRpcRequest(Lwm2mClientRpcRequest rpcRequest, String requestCode, String msg, String typeMsg) { | |
487 | 509 | rpcRequest.setResponseCode(requestCode); |
488 | - if (LOG_LW2M_ERROR.equals(typeMsg)) { | |
489 | - rpcRequest.setInfoMsg(null); | |
490 | - rpcRequest.setValueMsg(null); | |
491 | - if (rpcRequest.getErrorMsg() == null) { | |
492 | - msg = msg.isEmpty() ? null : msg; | |
493 | - rpcRequest.setErrorMsg(msg); | |
494 | - } | |
495 | - } else if (LOG_LW2M_INFO.equals(typeMsg)) { | |
496 | - if (rpcRequest.getInfoMsg() == null) { | |
497 | - rpcRequest.setInfoMsg(msg); | |
498 | - } | |
499 | - } else if (LOG_LW2M_VALUE.equals(typeMsg)) { | |
500 | - if (rpcRequest.getValueMsg() == null) { | |
501 | - rpcRequest.setValueMsg(msg); | |
502 | - } | |
510 | + if (LOG_LW2M_ERROR.equals(typeMsg)) { | |
511 | + rpcRequest.setInfoMsg(null); | |
512 | + rpcRequest.setValueMsg(null); | |
513 | + if (rpcRequest.getErrorMsg() == null) { | |
514 | + msg = msg.isEmpty() ? null : msg; | |
515 | + rpcRequest.setErrorMsg(msg); | |
516 | + } | |
517 | + } else if (LOG_LW2M_INFO.equals(typeMsg)) { | |
518 | + if (rpcRequest.getInfoMsg() == null) { | |
519 | + rpcRequest.setInfoMsg(msg); | |
520 | + } | |
521 | + } else if (LOG_LW2M_VALUE.equals(typeMsg)) { | |
522 | + if (rpcRequest.getValueMsg() == null) { | |
523 | + rpcRequest.setValueMsg(msg); | |
524 | + } | |
503 | 525 | } |
504 | 526 | this.onToDeviceRpcResponse(rpcRequest.getDeviceRpcResponseResultMsg(), rpcRequest.getSessionInfo()); |
505 | 527 | } |
... | ... | @@ -556,7 +578,7 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService { |
556 | 578 | */ |
557 | 579 | protected void onAwakeDev(Registration registration) { |
558 | 580 | log.info("[{}] [{}] Received endpoint Awake version event", registration.getId(), registration.getEndpoint()); |
559 | - this.sendLogsToThingsboard(LOG_LW2M_INFO + ": Client is awake!", registration); | |
581 | + this.sendLogsToThingsboard(LOG_LW2M_INFO + ": Client is awake!", registration.getId()); | |
560 | 582 | //TODO: associate endpointId with device information. |
561 | 583 | } |
562 | 584 | |
... | ... | @@ -583,10 +605,10 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService { |
583 | 605 | |
584 | 606 | /** |
585 | 607 | * @param logMsg - text msg |
586 | - * @param registration - Id of Registration LwM2M Client | |
608 | + * @param registrationId - Id of Registration LwM2M Client | |
587 | 609 | */ |
588 | - public void sendLogsToThingsboard(String logMsg, Registration registration) { | |
589 | - SessionInfoProto sessionInfo = this.getValidateSessionInfo(registration); | |
610 | + public void sendLogsToThingsboard(String logMsg, String registrationId) { | |
611 | + SessionInfoProto sessionInfo = this.getValidateSessionInfo(registrationId); | |
590 | 612 | if (logMsg != null && sessionInfo != null) { |
591 | 613 | this.lwM2mTransportContextServer.sendParametersOnThingsboardTelemetry(this.lwM2mTransportContextServer.getKvLogyToThingsboard(logMsg), sessionInfo); |
592 | 614 | } |
... | ... | @@ -610,7 +632,7 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService { |
610 | 632 | if (clientObjects != null && clientObjects.size() > 0) { |
611 | 633 | if (LWM2M_STRATEGY_2 == LwM2mTransportHandler.getClientOnlyObserveAfterConnect(lwM2MClientProfile)) { |
612 | 634 | // #2 |
613 | - lwM2MClient.getPendingRequests().addAll(clientObjects); | |
635 | + lwM2MClient.getPendingReadRequests().addAll(clientObjects); | |
614 | 636 | clientObjects.forEach(path -> lwM2mTransportRequest.sendAllRequest(registration, path, READ, ContentFormat.TLV.getName(), |
615 | 637 | null, this.lwM2mTransportContextServer.getLwM2MTransportConfigServer().getTimeout(), null)); |
616 | 638 | } |
... | ... | @@ -652,6 +674,8 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService { |
652 | 674 | * Sending observe value of resources to thingsboard |
653 | 675 | * #1 Return old Value Resource from LwM2MClient |
654 | 676 | * #2 Update new Resources (replace old Resource Value on new Resource Value) |
677 | + * #3 If fr_update -> UpdateFirmware | |
678 | + * #4 updateAttrTelemetry | |
655 | 679 | * |
656 | 680 | * @param registration - Registration LwM2M Client |
657 | 681 | * @param lwM2mResource - LwM2mSingleResource response.getContent() |
... | ... | @@ -661,6 +685,19 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService { |
661 | 685 | LwM2mClient lwM2MClient = lwM2mClientContext.getLwM2mClientWithReg(registration, null); |
662 | 686 | if (lwM2MClient.saveResourceValue(path, lwM2mResource, this.lwM2mTransportContextServer.getLwM2MTransportConfigServer() |
663 | 687 | .getModelProvider())) { |
688 | + if (FR_PATH_RESOURCE_VER_ID.equals(convertPathFromIdVerToObjectId(path)) && | |
689 | + lwM2MClient.getFrUpdate().getCurrentFwVersion() != null | |
690 | + && !lwM2MClient.getFrUpdate().getCurrentFwVersion().equals(lwM2MClient.getFrUpdate().getClientFwVersion()) | |
691 | + && lwM2MClient.isUpdateFw()) { | |
692 | + | |
693 | + /** version != null | |
694 | + * set setClient_fw_version = value | |
695 | + **/ | |
696 | + lwM2MClient.setUpdateFw(false); | |
697 | + lwM2MClient.getFrUpdate().setClientFwVersion(lwM2mResource.getValue().toString()); | |
698 | + log.warn("updateFirmwareClient3"); | |
699 | + this.updateFirmwareClient(lwM2MClient); | |
700 | + } | |
664 | 701 | Set<String> paths = new HashSet<>(); |
665 | 702 | paths.add(path); |
666 | 703 | this.updateAttrTelemetry(registration, paths); |
... | ... | @@ -669,6 +706,7 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService { |
669 | 706 | } |
670 | 707 | } |
671 | 708 | |
709 | + | |
672 | 710 | /** |
673 | 711 | * send Attribute and Telemetry to Thingsboard |
674 | 712 | * #1 - get AttrName/TelemetryName with value from LwM2MClient: |
... | ... | @@ -723,22 +761,23 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService { |
723 | 761 | params = this.getPathForWriteAttributes(lwM2MClientProfile.getPostAttributeLwm2mProfile()); |
724 | 762 | result = params.keySet(); |
725 | 763 | } |
726 | - if (!result.isEmpty()) { | |
764 | + if (result != null && !result.isEmpty()) { | |
727 | 765 | // #1 |
728 | 766 | Set<String> pathSend = result.stream().filter(target -> { |
729 | 767 | return target.split(LWM2M_SEPARATOR_PATH).length < 3 ? |
730 | 768 | clientObjects.contains("/" + target.split(LWM2M_SEPARATOR_PATH)[1]) : |
731 | 769 | clientObjects.contains("/" + target.split(LWM2M_SEPARATOR_PATH)[1] + "/" + target.split(LWM2M_SEPARATOR_PATH)[2]); |
732 | 770 | } |
733 | - ) | |
734 | - .collect(Collectors.toUnmodifiableSet()); | |
771 | + ).collect(Collectors.toUnmodifiableSet()); | |
735 | 772 | if (!pathSend.isEmpty()) { |
736 | - lwM2MClient.getPendingRequests().addAll(pathSend); | |
773 | + lwM2MClient.getPendingReadRequests().addAll(pathSend); | |
737 | 774 | ConcurrentHashMap<String, Object> finalParams = params; |
738 | - pathSend.forEach(target -> lwM2mTransportRequest.sendAllRequest(registration, target, typeOper, ContentFormat.TLV.getName(), | |
739 | - finalParams != null ? finalParams.get(target) : null, this.lwM2mTransportContextServer.getLwM2MTransportConfigServer().getTimeout(), null)); | |
775 | + pathSend.forEach(target -> { | |
776 | + lwM2mTransportRequest.sendAllRequest(registration, target, typeOper, ContentFormat.TLV.getName(), | |
777 | + finalParams != null ? finalParams.get(target) : null, this.lwM2mTransportContextServer.getLwM2MTransportConfigServer().getTimeout(), null); | |
778 | + }); | |
740 | 779 | if (OBSERVE.equals(typeOper)) { |
741 | - lwM2MClient.initValue(this, null); | |
780 | + lwM2MClient.initReadValue(this, null); | |
742 | 781 | } |
743 | 782 | } |
744 | 783 | } |
... | ... | @@ -969,7 +1008,7 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService { |
969 | 1008 | // update value in Resources |
970 | 1009 | registrationIds.forEach(registrationId -> { |
971 | 1010 | Registration registration = lwM2mClientContext.getRegistration(registrationId); |
972 | - this.readResourceValueObserve(registration, sendAttrToThingsboard.getPathPostParametersAdd(), READ); | |
1011 | + this.readObserveFromProfile(registration, sendAttrToThingsboard.getPathPostParametersAdd(), READ); | |
973 | 1012 | // send attr/telemetry to tingsboard for new path |
974 | 1013 | this.updateAttrTelemetry(registration, sendAttrToThingsboard.getPathPostParametersAdd()); |
975 | 1014 | }); |
... | ... | @@ -998,12 +1037,12 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService { |
998 | 1037 | registrationIds.forEach(registrationId -> { |
999 | 1038 | Registration registration = lwM2mClientContext.getRegistration(registrationId); |
1000 | 1039 | if (postObserveAnalyzer.getPathPostParametersAdd().size() > 0) { |
1001 | - this.readResourceValueObserve(registration, postObserveAnalyzer.getPathPostParametersAdd(), OBSERVE); | |
1040 | + this.readObserveFromProfile(registration, postObserveAnalyzer.getPathPostParametersAdd(), OBSERVE); | |
1002 | 1041 | } |
1003 | 1042 | // 5.3 del |
1004 | 1043 | // send Request cancel observe to Client |
1005 | 1044 | if (postObserveAnalyzer.getPathPostParametersDel().size() > 0) { |
1006 | - this.cancelObserveIsValue(registration, postObserveAnalyzer.getPathPostParametersDel()); | |
1045 | + this.cancelObserveFromProfile(registration, postObserveAnalyzer.getPathPostParametersDel()); | |
1007 | 1046 | } |
1008 | 1047 | }); |
1009 | 1048 | } |
... | ... | @@ -1043,7 +1082,7 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService { |
1043 | 1082 | * @param registration - Registration LwM2M Client |
1044 | 1083 | * @param targets - path Resources == [ "/2/0/0", "/2/0/1"] |
1045 | 1084 | */ |
1046 | - private void readResourceValueObserve(Registration registration, Set<String> targets, LwM2mTypeOper typeOper) { | |
1085 | + private void readObserveFromProfile(Registration registration, Set<String> targets, LwM2mTypeOper typeOper) { | |
1047 | 1086 | targets.forEach(target -> { |
1048 | 1087 | LwM2mPath pathIds = new LwM2mPath(convertPathFromIdVerToObjectId(target)); |
1049 | 1088 | if (pathIds.isResource()) { |
... | ... | @@ -1133,7 +1172,7 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService { |
1133 | 1172 | |
1134 | 1173 | } |
1135 | 1174 | |
1136 | - private void cancelObserveIsValue(Registration registration, Set<String> paramAnallyzer) { | |
1175 | + private void cancelObserveFromProfile(Registration registration, Set<String> paramAnallyzer) { | |
1137 | 1176 | LwM2mClient lwM2MClient = lwM2mClientContext.getLwM2mClientWithReg(registration, null); |
1138 | 1177 | paramAnallyzer.forEach(pathIdVer -> { |
1139 | 1178 | if (this.getResourceValueFromLwM2MClient(lwM2MClient, pathIdVer) != null) { |
... | ... | @@ -1153,7 +1192,7 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService { |
1153 | 1192 | log.error("Failed update resource [{}] [{}]", path, valueNew); |
1154 | 1193 | String logMsg = String.format("%s: Failed update resource path - %s value - %s. Value is not changed or bad", |
1155 | 1194 | LOG_LW2M_ERROR, path, valueNew); |
1156 | - this.sendLogsToThingsboard(logMsg, lwM2MClient.getRegistration()); | |
1195 | + this.sendLogsToThingsboard(logMsg, lwM2MClient.getRegistration().getId()); | |
1157 | 1196 | log.info("Failed update resource [{}] [{}]", path, valueNew); |
1158 | 1197 | } |
1159 | 1198 | } |
... | ... | @@ -1182,8 +1221,10 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService { |
1182 | 1221 | } |
1183 | 1222 | |
1184 | 1223 | /** |
1185 | - * Update resource value on client: if there is a difference in values between the current resource values and the shared attribute values | |
1186 | - * #1 Get path resource by result attributesResponse | |
1224 | + * 1. FirmwareUpdate: | |
1225 | + * - msg.getSharedUpdatedList().forEach(tsKvProto -> {tsKvProto.getKv().getKey().indexOf(FIRMWARE_UPDATE_PREFIX, 0) == 0 | |
1226 | + * 2. Update resource value on client: if there is a difference in values between the current resource values and the shared attribute values | |
1227 | + * - Get path resource by result attributesResponse | |
1187 | 1228 | * |
1188 | 1229 | * @param attributesResponse - |
1189 | 1230 | * @param sessionInfo - |
... | ... | @@ -1191,6 +1232,7 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService { |
1191 | 1232 | public void onGetAttributesResponse(TransportProtos.GetAttributeResponseMsg attributesResponse, TransportProtos.SessionInfoProto sessionInfo) { |
1192 | 1233 | try { |
1193 | 1234 | List<TransportProtos.TsKvProto> tsKvProtos = attributesResponse.getSharedAttributeListList(); |
1235 | + | |
1194 | 1236 | this.updateAttriuteFromThingsboard(tsKvProtos, sessionInfo); |
1195 | 1237 | } catch (Exception e) { |
1196 | 1238 | log.error(String.valueOf(e)); |
... | ... | @@ -1274,7 +1316,7 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService { |
1274 | 1316 | */ |
1275 | 1317 | private SessionInfoProto getValidateSessionInfo(String registrationId) { |
1276 | 1318 | LwM2mClient lwM2MClient = lwM2mClientContext.getLwM2mClientWithReg(null, registrationId); |
1277 | - return getNewSessionInfoProto(lwM2MClient); | |
1319 | + return lwM2MClient != null ? this.getNewSessionInfoProto(lwM2MClient) : null; | |
1278 | 1320 | } |
1279 | 1321 | |
1280 | 1322 | /** |
... | ... | @@ -1293,28 +1335,88 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService { |
1293 | 1335 | } |
1294 | 1336 | |
1295 | 1337 | /** |
1296 | - * !!! sharedAttr === profileAttr !!! | |
1297 | - * If there is a difference in values between the current resource values and the shared attribute values | |
1298 | - * when the client connects to the server | |
1299 | - * #1 get attributes name from profile include name resources in ModelObject if resource isWritable | |
1300 | - * #2.1 #1 size > 0 => send Request getAttributes to thingsboard | |
1338 | + * #1. !!! sharedAttr === profileAttr !!! | |
1339 | + * - If there is a difference in values between the current resource values and the shared attribute values | |
1340 | + * - when the client connects to the server | |
1341 | + * #1.1 get attributes name from profile include name resources in ModelObject if resource isWritable | |
1342 | + * #1.2 #1 size > 0 => send Request getAttributes to thingsboard | |
1343 | + * #2. FirmwareAttribute subscribe: | |
1301 | 1344 | * |
1302 | 1345 | * @param lwM2MClient - LwM2M Client |
1303 | 1346 | */ |
1304 | 1347 | public void putDelayedUpdateResourcesThingsboard(LwM2mClient lwM2MClient) { |
1305 | 1348 | SessionInfoProto sessionInfo = this.getValidateSessionInfo(lwM2MClient.getRegistration()); |
1306 | 1349 | if (sessionInfo != null) { |
1307 | - //#1.1 + #1.2 | |
1308 | - List<String> attrSharedNames = this.getNamesAttrFromProfileIsWritable(lwM2MClient); | |
1309 | - if (attrSharedNames.size() > 0) { | |
1310 | - //#2.1 | |
1350 | + //#1.1 | |
1351 | + ConcurrentMap<String, String> keyNamesMap = this.getNamesFromProfileForSharedAttributes(lwM2MClient); | |
1352 | + if (keyNamesMap.values().size() > 0) { | |
1311 | 1353 | try { |
1312 | - TransportProtos.GetAttributeRequestMsg getAttributeMsg = lwM2mTransportContextServer.getAdaptor().convertToGetAttributes(null, attrSharedNames); | |
1354 | + //#1.2 | |
1355 | + TransportProtos.GetAttributeRequestMsg getAttributeMsg = lwM2mTransportContextServer.getAdaptor().convertToGetAttributes(null, keyNamesMap.values()); | |
1313 | 1356 | transportService.process(sessionInfo, getAttributeMsg, getAckCallback(lwM2MClient, getAttributeMsg.getRequestId(), DEVICE_ATTRIBUTES_REQUEST)); |
1314 | 1357 | } catch (AdaptorException e) { |
1315 | 1358 | log.warn("Failed to decode get attributes request", e); |
1316 | 1359 | } |
1317 | 1360 | } |
1361 | + | |
1362 | + } | |
1363 | + } | |
1364 | + | |
1365 | + public void getInfoFirmwareUpdate(LwM2mClient lwM2MClient) { | |
1366 | + SessionInfoProto sessionInfo = this.getValidateSessionInfo(lwM2MClient.getRegistration()); | |
1367 | + if (sessionInfo != null) { | |
1368 | + TransportProtos.GetFirmwareRequestMsg getFirmwareRequestMsg = TransportProtos.GetFirmwareRequestMsg.newBuilder() | |
1369 | + .setDeviceIdMSB(sessionInfo.getDeviceIdMSB()) | |
1370 | + .setDeviceIdLSB(sessionInfo.getDeviceIdLSB()) | |
1371 | + .setTenantIdMSB(sessionInfo.getTenantIdMSB()) | |
1372 | + .setTenantIdLSB(sessionInfo.getTenantIdLSB()) | |
1373 | + .build(); | |
1374 | + transportService.process(sessionInfo, getFirmwareRequestMsg, | |
1375 | + new TransportServiceCallback<>() { | |
1376 | + @Override | |
1377 | + public void onSuccess(TransportProtos.GetFirmwareResponseMsg response) { | |
1378 | + if (TransportProtos.ResponseStatus.SUCCESS.equals(response.getResponseStatus())) { | |
1379 | + lwM2MClient.getFrUpdate().setCurrentFwVersion(response.getVersion()); | |
1380 | + lwM2MClient.getFrUpdate().setCurrentFwId(new FirmwareId(new UUID(response.getFirmwareIdMSB(), response.getFirmwareIdLSB())).getId()); | |
1381 | + lwM2MClient.setUpdateFw(true); | |
1382 | + readRequestToClientFirmwareVer(lwM2MClient.getRegistration()); | |
1383 | + } else { | |
1384 | + log.trace("Firmware [{}] [{}]", lwM2MClient.getDeviceName(), response.getResponseStatus().toString()); | |
1385 | + } | |
1386 | + } | |
1387 | + | |
1388 | + @Override | |
1389 | + public void onError(Throwable e) { | |
1390 | + log.trace("Failed to process credentials ", e); | |
1391 | + } | |
1392 | + }); | |
1393 | + } | |
1394 | + } | |
1395 | + | |
1396 | + /** | |
1397 | + * @param registration | |
1398 | + */ | |
1399 | + public void readRequestToClientFirmwareVer(Registration registration) { | |
1400 | + String pathIdVer = convertPathFromObjectIdToIdVer(FR_PATH_RESOURCE_VER_ID, registration); | |
1401 | + lwM2mTransportRequest.sendAllRequest(registration, pathIdVer, READ, ContentFormat.TLV.getName(), | |
1402 | + null, lwM2mTransportContextServer.getLwM2MTransportConfigServer().getTimeout(), null); | |
1403 | + } | |
1404 | + | |
1405 | + /** | |
1406 | + * | |
1407 | + * @param lwM2MClient - | |
1408 | + */ | |
1409 | + public void updateFirmwareClient(LwM2mClient lwM2MClient) { | |
1410 | + if (!lwM2MClient.getFrUpdate().getCurrentFwVersion().equals(lwM2MClient.getFrUpdate().getClientFwVersion())) { | |
1411 | + int chunkSize = 0; | |
1412 | + int chunk = 0; | |
1413 | + byte[] firmwareChunk = firmwareDataCache.get(lwM2MClient.getFrUpdate().getCurrentFwId().toString(), chunkSize, chunk); | |
1414 | + Integer objectId = 5; | |
1415 | + String verSupportedObject = lwM2MClient.getRegistration().getSupportedObject().get(objectId); | |
1416 | + String targetIdVer = LWM2M_SEPARATOR_PATH + objectId + LWM2M_SEPARATOR_KEY + verSupportedObject + LWM2M_SEPARATOR_PATH + 0 + LWM2M_SEPARATOR_PATH + 0; | |
1417 | + lwM2mTransportRequest.sendAllRequest(lwM2MClient.getRegistration(), targetIdVer, WRITE_REPLACE, ContentFormat.TLV.getName(), | |
1418 | + firmwareChunk, lwM2mTransportContextServer.getLwM2MTransportConfigServer().getTimeout(), null); | |
1419 | + log.warn("updateFirmwareClient [{}] [{}]", lwM2MClient.getFrUpdate().getCurrentFwVersion(), lwM2MClient.getFrUpdate().getClientFwVersion()); | |
1318 | 1420 | } |
1319 | 1421 | } |
1320 | 1422 | |
... | ... | @@ -1326,23 +1428,12 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService { |
1326 | 1428 | * @param lwM2MClient - |
1327 | 1429 | * @return ArrayList keyNames from profile profileAttr && IsWritable |
1328 | 1430 | */ |
1329 | - private List<String> getNamesAttrFromProfileIsWritable(LwM2mClient lwM2MClient) { | |
1431 | + private ConcurrentMap<String, String> getNamesFromProfileForSharedAttributes(LwM2mClient lwM2MClient) { | |
1432 | + | |
1330 | 1433 | LwM2mClientProfile profile = lwM2mClientContext.getProfile(lwM2MClient.getProfileId()); |
1331 | - Set<String> attrSet = new Gson().fromJson(profile.getPostAttributeProfile(), | |
1332 | - new TypeToken<HashSet<String>>() { | |
1333 | - }.getType()); | |
1334 | - ConcurrentMap<String, String> keyNamesMap = new Gson().fromJson(profile.getPostKeyNameProfile().toString(), | |
1434 | + return new Gson().fromJson(profile.getPostKeyNameProfile().toString(), | |
1335 | 1435 | new TypeToken<ConcurrentHashMap<String, String>>() { |
1336 | 1436 | }.getType()); |
1337 | - | |
1338 | - ConcurrentMap<String, String> keyNamesIsWritable = keyNamesMap.entrySet() | |
1339 | - .stream() | |
1340 | - .filter(e -> (attrSet.contains(e.getKey()) && validateResourceInModel(lwM2MClient, e.getKey(), true))) | |
1341 | - .collect(Collectors.toConcurrentMap(Map.Entry::getKey, Map.Entry::getValue)); | |
1342 | - | |
1343 | - Set<String> namesIsWritable = ConcurrentHashMap.newKeySet(); | |
1344 | - namesIsWritable.addAll(new HashSet<>(keyNamesIsWritable.values())); | |
1345 | - return new ArrayList<>(namesIsWritable); | |
1346 | 1437 | } |
1347 | 1438 | |
1348 | 1439 | private boolean validateResourceInModel(LwM2mClient lwM2mClient, String pathIdVer, boolean isWritableNotOptional) { | ... | ... |
... | ... | @@ -24,11 +24,8 @@ import org.thingsboard.server.common.transport.adaptor.AdaptorException; |
24 | 24 | import org.thingsboard.server.common.transport.adaptor.JsonConverter; |
25 | 25 | import org.thingsboard.server.gen.transport.TransportProtos; |
26 | 26 | |
27 | -import java.util.Arrays; | |
28 | -import java.util.HashSet; | |
29 | -import java.util.List; | |
27 | +import java.util.Collection; | |
30 | 28 | import java.util.Random; |
31 | -import java.util.Set; | |
32 | 29 | |
33 | 30 | @Slf4j |
34 | 31 | @Component("LwM2MJsonAdaptor") |
... | ... | @@ -54,11 +51,7 @@ public class LwM2MJsonAdaptor implements LwM2MTransportAdaptor { |
54 | 51 | } |
55 | 52 | |
56 | 53 | @Override |
57 | - public TransportProtos.GetAttributeRequestMsg convertToGetAttributes(List<String> clientKeys, List<String> sharedKeys) throws AdaptorException { | |
58 | - return processGetAttributeRequestMsg(clientKeys, sharedKeys); | |
59 | - } | |
60 | - | |
61 | - protected TransportProtos.GetAttributeRequestMsg processGetAttributeRequestMsg(List<String> clientKeys, List<String> sharedKeys) throws AdaptorException { | |
54 | + public TransportProtos.GetAttributeRequestMsg convertToGetAttributes(Collection<String> clientKeys, Collection<String> sharedKeys) throws AdaptorException { | |
62 | 55 | try { |
63 | 56 | TransportProtos.GetAttributeRequestMsg.Builder result = TransportProtos.GetAttributeRequestMsg.newBuilder(); |
64 | 57 | Random random = new Random(); |
... | ... | @@ -75,14 +68,4 @@ public class LwM2MJsonAdaptor implements LwM2MTransportAdaptor { |
75 | 68 | throw new AdaptorException(e); |
76 | 69 | } |
77 | 70 | } |
78 | - | |
79 | - private Set<String> toStringSet(JsonElement requestBody, String name) { | |
80 | - JsonElement element = requestBody.getAsJsonObject().get(name); | |
81 | - if (element != null) { | |
82 | - return new HashSet<>(Arrays.asList(element.getAsString().split(","))); | |
83 | - } else { | |
84 | - return null; | |
85 | - } | |
86 | - } | |
87 | - | |
88 | 71 | } | ... | ... |
... | ... | @@ -19,7 +19,7 @@ import com.google.gson.JsonElement; |
19 | 19 | import org.thingsboard.server.common.transport.adaptor.AdaptorException; |
20 | 20 | import org.thingsboard.server.gen.transport.TransportProtos; |
21 | 21 | |
22 | -import java.util.List; | |
22 | +import java.util.Collection; | |
23 | 23 | |
24 | 24 | public interface LwM2MTransportAdaptor { |
25 | 25 | |
... | ... | @@ -27,5 +27,5 @@ public interface LwM2MTransportAdaptor { |
27 | 27 | |
28 | 28 | TransportProtos.PostAttributeMsg convertToPostAttributes(JsonElement jsonElement) throws AdaptorException; |
29 | 29 | |
30 | - TransportProtos.GetAttributeRequestMsg convertToGetAttributes(List<String> clientKeys, List<String> sharedKeys) throws AdaptorException; | |
30 | + TransportProtos.GetAttributeRequestMsg convertToGetAttributes(Collection<String> clientKeys, Collection<String> sharedKeys) throws AdaptorException; | |
31 | 31 | } | ... | ... |
... | ... | @@ -57,13 +57,15 @@ public class LwM2mClient implements Cloneable { |
57 | 57 | private UUID deviceId; |
58 | 58 | private UUID sessionId; |
59 | 59 | private UUID profileId; |
60 | + private volatile LwM2mFirmwareUpdate frUpdate; | |
60 | 61 | private Registration registration; |
61 | 62 | private ValidateDeviceCredentialsResponseMsg credentialsResponse; |
62 | 63 | private final Map<String, ResourceValue> resources; |
63 | 64 | private final Map<String, TransportProtos.TsKvProto> delayedRequests; |
64 | - private final List<String> pendingRequests; | |
65 | + private final List<String> pendingReadRequests; | |
65 | 66 | private final Queue<LwM2mQueuedRequest> queuedRequests; |
66 | 67 | private boolean init; |
68 | + private volatile boolean updateFw; | |
67 | 69 | |
68 | 70 | public Object clone() throws CloneNotSupportedException { |
69 | 71 | return super.clone(); |
... | ... | @@ -75,12 +77,14 @@ public class LwM2mClient implements Cloneable { |
75 | 77 | this.securityInfo = securityInfo; |
76 | 78 | this.credentialsResponse = credentialsResponse; |
77 | 79 | this.delayedRequests = new ConcurrentHashMap<>(); |
78 | - this.pendingRequests = new CopyOnWriteArrayList<>(); | |
80 | + this.pendingReadRequests = new CopyOnWriteArrayList<>(); | |
79 | 81 | this.resources = new ConcurrentHashMap<>(); |
80 | 82 | this.profileId = profileId; |
81 | 83 | this.sessionId = sessionId; |
82 | 84 | this.init = false; |
85 | + this.updateFw = false; | |
83 | 86 | this.queuedRequests = new ConcurrentLinkedQueue<>(); |
87 | + this.frUpdate = new LwM2mFirmwareUpdate(); | |
84 | 88 | } |
85 | 89 | |
86 | 90 | public boolean saveResourceValue(String pathRez, LwM2mResource rez, LwM2mModelProvider modelProvider) { |
... | ... | @@ -103,15 +107,13 @@ public class LwM2mClient implements Cloneable { |
103 | 107 | LwM2mPath pathIds = new LwM2mPath(convertPathFromIdVerToObjectId(pathRez)); |
104 | 108 | String verSupportedObject = registration.getSupportedObject().get(pathIds.getObjectId()); |
105 | 109 | String verRez = getVerFromPathIdVerOrId(pathRez); |
106 | - return (verRez == null || verSupportedObject.equals(verRez)) ? modelProvider.getObjectModel(registration) | |
110 | + return verRez == null || verRez.equals(verSupportedObject) ? modelProvider.getObjectModel(registration) | |
107 | 111 | .getResourceModel(pathIds.getObjectId(), pathIds.getResourceId()) : null; |
108 | 112 | } |
109 | 113 | |
110 | 114 | public Collection<LwM2mResource> getNewResourcesForInstance(String pathRezIdVer, LwM2mModelProvider modelProvider, |
111 | 115 | LwM2mValueConverterImpl converter) { |
112 | 116 | LwM2mPath pathIds = new LwM2mPath(convertPathFromIdVerToObjectId(pathRezIdVer)); |
113 | - String verSupportedObject = registration.getSupportedObject().get(pathIds.getObjectId()); | |
114 | - String verRez = getVerFromPathIdVerOrId(pathRezIdVer); | |
115 | 117 | Collection<LwM2mResource> resources = ConcurrentHashMap.newKeySet(); |
116 | 118 | Map<Integer, ResourceModel> resourceModels = modelProvider.getObjectModel(registration) |
117 | 119 | .getObjectModel(pathIds.getObjectId()).resources; |
... | ... | @@ -170,11 +172,11 @@ public class LwM2mClient implements Cloneable { |
170 | 172 | .collect(Collectors.toSet()); |
171 | 173 | } |
172 | 174 | |
173 | - public void initValue(LwM2mTransportServiceImpl serviceImpl, String path) { | |
175 | + public void initReadValue(LwM2mTransportServiceImpl serviceImpl, String path) { | |
174 | 176 | if (path != null) { |
175 | - this.pendingRequests.remove(path); | |
177 | + this.pendingReadRequests.remove(path); | |
176 | 178 | } |
177 | - if (this.pendingRequests.size() == 0) { | |
179 | + if (this.pendingReadRequests.size() == 0) { | |
178 | 180 | this.init = true; |
179 | 181 | serviceImpl.putDelayedUpdateResourcesThingsboard(this); |
180 | 182 | } | ... | ... |
... | ... | @@ -82,12 +82,12 @@ public class LwM2mClientContextImpl implements LwM2mClientContext { |
82 | 82 | |
83 | 83 | @Override |
84 | 84 | public LwM2mClient getLwM2mClientWithReg(Registration registration, String registrationId) { |
85 | - LwM2mClient client = registrationId != null ? | |
85 | + LwM2mClient client = registrationId != null && this.lwM2mClients.containsKey(registrationId) ? | |
86 | 86 | this.lwM2mClients.get(registrationId) : |
87 | - this.lwM2mClients.containsKey(registration.getId()) ? | |
88 | - this.lwM2mClients.get(registration.getId()) : | |
89 | - this.lwM2mClients.get(registration.getEndpoint()); | |
90 | - return client != null ? client : updateInSessionsLwM2MClient(registration); | |
87 | + registration !=null && this.lwM2mClients.containsKey(registration.getId()) ? | |
88 | + this.lwM2mClients.get(registration.getId()) : registration !=null && this.lwM2mClients.containsKey(registration) ? | |
89 | + this.lwM2mClients.get(registration.getEndpoint()) : null; | |
90 | + return client != null ? client : registration!= null ? updateInSessionsLwM2MClient(registration) : null; | |
91 | 91 | } |
92 | 92 | |
93 | 93 | @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.client; | |
17 | + | |
18 | +import lombok.Data; | |
19 | + | |
20 | +import java.util.UUID; | |
21 | + | |
22 | +@Data | |
23 | +public class LwM2mFirmwareUpdate { | |
24 | + private volatile String clientFwVersion; | |
25 | + private volatile String currentFwVersion; | |
26 | + private volatile UUID currentFwId; | |
27 | +} | ... | ... |
... | ... | @@ -24,6 +24,8 @@ import { |
24 | 24 | NG_VALUE_ACCESSOR, |
25 | 25 | Validators |
26 | 26 | } from '@angular/forms'; |
27 | +import { Store } from '@ngrx/store'; | |
28 | +import { AppState } from '@core/core.state'; | |
27 | 29 | import { coerceBooleanProperty } from '@angular/cdk/coercion'; |
28 | 30 | import { |
29 | 31 | ATTRIBUTE, |
... | ... | @@ -38,6 +40,7 @@ import { |
38 | 40 | } from './lwm2m-profile-config.models'; |
39 | 41 | import { deepClone, isDefinedAndNotNull, isEqual, isUndefined } from '@core/utils'; |
40 | 42 | import { MatDialog } from '@angular/material/dialog'; |
43 | +import { TranslateService } from '@ngx-translate/core'; | |
41 | 44 | import { |
42 | 45 | Lwm2mObjectAddInstancesData, |
43 | 46 | Lwm2mObjectAddInstancesDialogComponent |
... | ... | @@ -80,8 +83,10 @@ export class Lwm2mObserveAttrTelemetryComponent implements ControlValueAccessor |
80 | 83 | @Input() |
81 | 84 | disabled: boolean; |
82 | 85 | |
83 | - constructor(private fb: FormBuilder, | |
84 | - private dialog: MatDialog) { | |
86 | + constructor(private store: Store<AppState>, | |
87 | + private fb: FormBuilder, | |
88 | + private dialog: MatDialog, | |
89 | + public translate: TranslateService) { | |
85 | 90 | this.observeAttrTelemetryFormGroup = this.fb.group({ |
86 | 91 | [CLIENT_LWM2M]: this.fb.array([]) |
87 | 92 | }); |
... | ... | @@ -93,7 +98,7 @@ export class Lwm2mObserveAttrTelemetryComponent implements ControlValueAccessor |
93 | 98 | } |
94 | 99 | |
95 | 100 | private propagateChange = (v: any) => { |
96 | - } | |
101 | + }; | |
97 | 102 | |
98 | 103 | registerOnChange(fn: any): void { |
99 | 104 | this.propagateChange = fn; |
... | ... | @@ -184,7 +189,7 @@ export class Lwm2mObserveAttrTelemetryComponent implements ControlValueAccessor |
184 | 189 | this.observeAttrTelemetryFormGroup.get(CLIENT_LWM2M).updateValueAndValidity(); |
185 | 190 | } |
186 | 191 | |
187 | - trackByParams = (index: number): number => { | |
192 | + trackByParams = (index: number, element: any): number => { | |
188 | 193 | return index; |
189 | 194 | } |
190 | 195 | |
... | ... | @@ -312,7 +317,7 @@ export class Lwm2mObserveAttrTelemetryComponent implements ControlValueAccessor |
312 | 317 | return objectName + ' <' + idVerObj + '>'; |
313 | 318 | } |
314 | 319 | getNameInstanceLwm2m = (instance: Instance, idVerObj: string): string => { |
315 | - return ` instance <${idVerObj}/${instance.id}>`; | |
320 | + return ' instance <' + idVerObj + '/' + instance.id +'>'; | |
316 | 321 | } |
317 | 322 | |
318 | 323 | updateAttributeLwm2mObject = (event: Event, objectKeyId: number): void => { | ... | ... |
... | ... | @@ -1205,7 +1205,7 @@ |
1205 | 1205 | "telemetry-label": "Telemetry", |
1206 | 1206 | "key-name-label": "Key Name", |
1207 | 1207 | "attribute-lwm2m-label": "AttrLwm2m", |
1208 | - "resource-tip": "ID & Original Name of the Resource", | |
1208 | + "resource-tip": "ID & Original Name of the Resource (only Operations isReadable)", | |
1209 | 1209 | "is-observe-tip": "Is Observe", |
1210 | 1210 | "not-observe-tip": "To observe select telemetry or attributes first", |
1211 | 1211 | "is-attr-tip": "Is Attribute", | ... | ... |