Browse Source

Refactoring of the Firmware Update

pull/4752/head
Andrii Shvaika 5 years ago
parent
commit
08939e23e7
  1. 2
      common/data/src/main/java/org/thingsboard/server/common/data/device/data/lwm2m/OtherConfiguration.java
  2. 48
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MFirmwareUpdateStrategy.java
  3. 48
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MSoftwareUpdateStrategy.java
  4. 5
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mServerListener.java
  5. 3
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mSessionMsgListener.java
  6. 6
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportServerHelper.java
  7. 215
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportUtil.java
  8. 70
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/UpdateResultFw.java
  9. 56
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/UpdateStateFw.java
  10. 183
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/attributes/DefaultLwM2MAttributesService.java
  11. 4
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/attributes/LwM2MAttributesService.java
  12. 9
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java
  13. 5
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContext.java
  14. 41
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContextImpl.java
  15. 65
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mFwSwUpdate.java
  16. 6
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MWriteReplaceRequest.java
  17. 248
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ota/DefaultLwM2MOtaUpdateService.java
  18. 99
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ota/LwM2MClientOtaInfo.java
  19. 5
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ota/LwM2MClientOtaState.java
  20. 13
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ota/LwM2MOtaUpdateService.java
  21. 2
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/DefaultLwM2MRpcRequestHandler.java
  22. 159
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/DefaultLwM2MUplinkMsgHandler.java
  23. 4
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/LwM2mUplinkMsgHandler.java

2
common/data/src/main/java/org/thingsboard/server/common/data/device/data/lwm2m/OtherConfiguration.java

@ -23,5 +23,7 @@ public class OtherConfiguration {
private Integer fwUpdateStrategy;
private Integer swUpdateStrategy;
private Integer clientOnlyObserveAfterConnect;
private String fwUpdateRecourse;
private String swUpdateRecourse;
}

48
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MFirmwareUpdateStrategy.java

@ -0,0 +1,48 @@
/**
* Copyright © 2016-2021 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.transport.lwm2m.server;
public enum LwM2MFirmwareUpdateStrategy {
OBJ_5_BINARY(1, "ObjectId 5, Binary"),
OBJ_5_TEMP_URL(2, "ObjectId 5, URI"),
OBJ_19_BINARY(3, "ObjectId 19, Binary");
public int code;
public String type;
LwM2MFirmwareUpdateStrategy(int code, String type) {
this.code = code;
this.type = type;
}
public static LwM2MFirmwareUpdateStrategy fromStrategyFwByType(String type) {
for (LwM2MFirmwareUpdateStrategy to : LwM2MFirmwareUpdateStrategy.values()) {
if (to.type.equals(type)) {
return to;
}
}
throw new IllegalArgumentException(String.format("Unsupported FW State type : %s", type));
}
public static LwM2MFirmwareUpdateStrategy fromStrategyFwByCode(int code) {
for (LwM2MFirmwareUpdateStrategy to : LwM2MFirmwareUpdateStrategy.values()) {
if (to.code == code) {
return to;
}
}
throw new IllegalArgumentException(String.format("Unsupported FW Strategy code : %s", code));
}
}

48
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MSoftwareUpdateStrategy.java

@ -0,0 +1,48 @@
/**
* Copyright © 2016-2021 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.transport.lwm2m.server;
public enum LwM2MSoftwareUpdateStrategy {
BINARY(1, "ObjectId 9, Binary"),
TEMP_URL(2, "ObjectId 9, URI");
public int code;
public String type;
LwM2MSoftwareUpdateStrategy(int code, String type) {
this.code = code;
this.type = type;
}
public static LwM2MSoftwareUpdateStrategy fromStrategySwByType(String type) {
for (LwM2MSoftwareUpdateStrategy to : LwM2MSoftwareUpdateStrategy.values()) {
if (to.type.equals(type)) {
return to;
}
}
throw new IllegalArgumentException(String.format("Unsupported SW Strategy type : %s", type));
}
public static LwM2MSoftwareUpdateStrategy fromStrategySwByCode(int code) {
for (LwM2MSoftwareUpdateStrategy to : LwM2MSoftwareUpdateStrategy.values()) {
if (to.code == code) {
return to;
}
}
throw new IllegalArgumentException(String.format("Unsupported SW Strategy code : %s", code));
}
}

5
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mServerListener.java

@ -27,8 +27,7 @@ import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mUplinkMsgHandle
import java.util.Collection;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LWM2M_INFO;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertPathFromObjectIdToIdVer;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertObjectIdToVersionedId;
@Slf4j
public class LwM2mServerListener {
@ -93,7 +92,7 @@ public class LwM2mServerListener {
@Override
public void onResponse(Observation observation, Registration registration, ObserveResponse response) {
if (registration != null) {
service.onUpdateValueAfterReadResponse(registration, convertPathFromObjectIdToIdVer(observation.getPath().toString(), registration), response);
service.onUpdateValueAfterReadResponse(registration, convertObjectIdToVersionedId(observation.getPath().toString(), registration), response);
}
}

3
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mSessionMsgListener.java

@ -33,7 +33,6 @@ import org.thingsboard.server.gen.transport.TransportProtos.ToServerRpcResponseM
import org.thingsboard.server.gen.transport.TransportProtos.ToTransportUpdateCredentialsProto;
import org.thingsboard.server.transport.lwm2m.server.attributes.LwM2MAttributesService;
import org.thingsboard.server.transport.lwm2m.server.rpc.LwM2MRpcRequestHandler;
import org.thingsboard.server.transport.lwm2m.server.uplink.DefaultLwM2MUplinkMsgHandler;
import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mUplinkMsgHandler;
import java.util.Optional;
@ -54,7 +53,7 @@ public class LwM2mSessionMsgListener implements GenericFutureListener<Future<? s
@Override
public void onAttributeUpdate(AttributeUpdateNotificationMsg attributeUpdateNotification) {
this.attributesService.onAttributeUpdate(attributeUpdateNotification, this.sessionInfo);
this.attributesService.onAttributesUpdate(attributeUpdateNotification, this.sessionInfo);
}
@Override

6
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportServerHelper.java

@ -37,6 +37,8 @@ import org.eclipse.leshan.core.model.DefaultDDFFileValidator;
import org.eclipse.leshan.core.model.InvalidDDFFileException;
import org.eclipse.leshan.core.model.ObjectModel;
import org.eclipse.leshan.core.model.ResourceModel;
import org.eclipse.leshan.core.node.LwM2mPath;
import org.eclipse.leshan.core.node.LwM2mResource;
import org.eclipse.leshan.core.node.codec.CodecException;
import org.eclipse.leshan.core.request.ContentFormat;
import org.springframework.stereotype.Component;
@ -49,6 +51,7 @@ import org.thingsboard.server.gen.transport.TransportProtos.SessionInfoProto;
import org.thingsboard.server.queue.util.TbLwM2mTransportComponent;
import org.thingsboard.server.transport.lwm2m.server.adaptors.LwM2MJsonAdaptor;
import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient;
import org.thingsboard.server.transport.lwm2m.server.client.ResourceValue;
import java.io.ByteArrayInputStream;
import java.io.IOException;
@ -58,6 +61,7 @@ import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import static org.thingsboard.server.gen.transport.TransportProtos.KeyValueType.BOOLEAN_V;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.fromVersionedIdToObjectId;
@Slf4j
@Component
@ -68,7 +72,6 @@ public class LwM2mTransportServerHelper {
private final LwM2mTransportContext context;
private final AtomicInteger atomicTs = new AtomicInteger(0);
public long getTS() {
return TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis()) * 1000L + (atomicTs.getAndIncrement() % 1000);
}
@ -226,4 +229,5 @@ public class LwM2mTransportServerHelper {
}
return null;
}
}

215
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportUtil.java

@ -30,6 +30,7 @@ import org.eclipse.leshan.core.node.LwM2mNode;
import org.eclipse.leshan.core.node.LwM2mObject;
import org.eclipse.leshan.core.node.LwM2mObjectInstance;
import org.eclipse.leshan.core.node.LwM2mPath;
import org.eclipse.leshan.core.node.LwM2mResource;
import org.eclipse.leshan.core.node.LwM2mSingleResource;
import org.eclipse.leshan.core.node.codec.CodecException;
import org.eclipse.leshan.core.request.SimpleDownlinkRequest;
@ -48,6 +49,7 @@ import org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus;
import org.thingsboard.server.common.data.ota.OtaPackageUtil;
import org.thingsboard.server.common.transport.TransportServiceCallback;
import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient;
import org.thingsboard.server.transport.lwm2m.server.client.ResourceValue;
import org.thingsboard.server.transport.lwm2m.server.uplink.DefaultLwM2MUplinkMsgHandler;
import java.util.ArrayList;
@ -120,24 +122,8 @@ public class LwM2mTransportUtil {
public static final String CLIENT_NOT_AUTHORIZED = "Client not authorized";
public static final String LWM2M_VERSION_DEFAULT = "1.0";
// RPC
public static final String TYPE_OPER_KEY = "typeOper";
public static final String TARGET_ID_VER_KEY = "targetIdVer";
public static final String KEY_NAME_KEY = "key";
public static final String VALUE_KEY = "value";
public static final String PARAMS_KEY = "params";
public static final String SEPARATOR_KEY = ":";
public static final String FINISH_VALUE_KEY = ",";
public static final String START_JSON_KEY = "{";
public static final String FINISH_JSON_KEY = "}";
public static final String INFO_KEY = "info";
public static final String RESULT_KEY = "result";
public static final String ERROR_KEY = "error";
public static final String METHOD_KEY = "methodName";
// Firmware
public static final String FIRMWARE_UPDATE_COAP_RECOURSE = "firmwareUpdateCoapRecourse";
public static final String FIRMWARE_UPDATE_COAP_RECOURSE = "tbfw";
public static final String FW_UPDATE = "Firmware update";
public static final Integer FW_5_ID = 5;
public static final Integer FW_19_ID = 19;
@ -155,6 +141,7 @@ public class LwM2mTransportUtil {
public static final String FW_NAME_ID = "/5/0/6";
// PkgVersion R
public static final String FW_5_VER_ID = "/5/0/7";
/**
* Quectel@Hi15RM1-HLB_V1.0@BC68JAR01A10,V150R100C20B300SP7,V150R100C20B300SP7@8
* BC68JAR01A10
@ -211,108 +198,14 @@ public class LwM2mTransportUtil {
}
}
/**
* /** State R
* 0: Idle (before downloading or after successful updating)
* 1: Downloading (The data sequence is on the way)
* 2: Downloaded
* 3: Updating
*/
public enum StateFw {
IDLE(0, "Idle"),
DOWNLOADING(1, "Downloading"),
DOWNLOADED(2, "Downloaded"),
UPDATING(3, "Updating");
public int code;
public String type;
StateFw(int code, String type) {
this.code = code;
this.type = type;
}
public static StateFw fromStateFwByType(String type) {
for (StateFw to : StateFw.values()) {
if (to.type.equals(type)) {
return to;
}
}
throw new IllegalArgumentException(String.format("Unsupported FW State type : %s", type));
}
public static StateFw fromStateFwByCode(int code) {
for (StateFw to : StateFw.values()) {
if (to.code == code) {
return to;
}
}
throw new IllegalArgumentException(String.format("Unsupported FW State code : %s", code));
}
}
/**
* FW Update Result
* 0: Initial value. Once the updating process is initiated (Download /Update), this Resource MUST be reset to Initial value.
* 1: Firmware updated successfully.
* 2: Not enough flash memory for the new firmware package.
* 3: Out of RAM during downloading process.
* 4: Connection lost during downloading process.
* 5: Integrity check failure for new downloaded package.
* 6: Unsupported package type.
* 7: Invalid URI.
* 8: Firmware update failed.
* 9: Unsupported protocol.
*/
public enum UpdateResultFw {
INITIAL(0, "Initial value", false),
UPDATE_SUCCESSFULLY(1, "Firmware updated successfully", false),
NOT_ENOUGH(2, "Not enough flash memory for the new firmware package", false),
OUT_OFF_MEMORY(3, "Out of RAM during downloading process", false),
CONNECTION_LOST(4, "Connection lost during downloading process", true),
INTEGRITY_CHECK_FAILURE(5, "Integrity check failure for new downloaded package", true),
UNSUPPORTED_TYPE(6, "Unsupported package type", false),
INVALID_URI(7, "Invalid URI", false),
UPDATE_FAILED(8, "Firmware update failed", false),
UNSUPPORTED_PROTOCOL(9, "Unsupported protocol", false);
public int code;
public String type;
public boolean isAgain;
UpdateResultFw(int code, String type, boolean isAgain) {
this.code = code;
this.type = type;
this.isAgain = isAgain;
}
public static UpdateResultFw fromUpdateResultFwByType(String type) {
for (UpdateResultFw to : UpdateResultFw.values()) {
if (to.type.equals(type)) {
return to;
}
}
throw new IllegalArgumentException(String.format("Unsupported FW Update Result type : %s", type));
}
public static UpdateResultFw fromUpdateResultFwByCode(int code) {
for (UpdateResultFw to : UpdateResultFw.values()) {
if (to.code == code) {
return to;
}
}
throw new IllegalArgumentException(String.format("Unsupported FW Update Result code : %s", code));
}
}
/**
* FirmwareUpdateStatus {
* DOWNLOADING, DOWNLOADED, VERIFIED, UPDATING, UPDATED, FAILED
*/
public static OtaPackageUpdateStatus equalsFwSateFwResultToFirmwareUpdateStatus(StateFw stateFw, UpdateResultFw updateResultFw) {
public static OtaPackageUpdateStatus equalsFwSateFwResultToFirmwareUpdateStatus(UpdateStateFw updateStateFw, UpdateResultFw updateResultFw) {
switch (updateResultFw) {
case INITIAL:
return equalsFwSateToFirmwareUpdateStatus(stateFw);
return toOtaPackageUpdateStatus(updateStateFw);
case UPDATE_SUCCESSFULLY:
return UPDATED;
case NOT_ENOUGH:
@ -325,11 +218,11 @@ public class LwM2mTransportUtil {
case UNSUPPORTED_PROTOCOL:
return FAILED;
default:
throw new CodecException("Invalid value stateFw %s %s for FirmwareUpdateStatus.", stateFw.name(), updateResultFw.name());
throw new CodecException("Invalid value stateFw %s %s for FirmwareUpdateStatus.", updateStateFw.name(), updateResultFw.name());
}
}
public static OtaPackageUpdateStatus equalsFwResultToFirmwareUpdateStatus(UpdateResultFw updateResultFw) {
public static OtaPackageUpdateStatus toOtaPackageUpdateStatus(UpdateResultFw updateResultFw) {
switch (updateResultFw) {
case INITIAL:
return VERIFIED;
@ -349,8 +242,8 @@ public class LwM2mTransportUtil {
}
}
public static OtaPackageUpdateStatus equalsFwSateToFirmwareUpdateStatus(StateFw stateFw) {
switch (stateFw) {
public static OtaPackageUpdateStatus toOtaPackageUpdateStatus(UpdateStateFw updateStateFw) {
switch (updateStateFw) {
case IDLE:
return VERIFIED;
case DOWNLOADING:
@ -360,7 +253,7 @@ public class LwM2mTransportUtil {
case UPDATING:
return UPDATING;
default:
throw new CodecException("Invalid value stateFw %d for FirmwareUpdateStatus.", stateFw);
throw new CodecException("Invalid value stateFw %d for FirmwareUpdateStatus.", updateStateFw);
}
}
@ -508,70 +401,6 @@ public class LwM2mTransportUtil {
}
}
public enum LwM2MFirmwareUpdateStrategy {
OBJ_5_BINARY(1, "ObjectId 5, Binary"),
OBJ_5_TEMP_URL(2, "ObjectId 5, URI"),
OBJ_19_BINARY(3, "ObjectId 19, Binary");
public int code;
public String type;
LwM2MFirmwareUpdateStrategy(int code, String type) {
this.code = code;
this.type = type;
}
public static LwM2MFirmwareUpdateStrategy fromStrategyFwByType(String type) {
for (LwM2MFirmwareUpdateStrategy to : LwM2MFirmwareUpdateStrategy.values()) {
if (to.type.equals(type)) {
return to;
}
}
throw new IllegalArgumentException(String.format("Unsupported FW State type : %s", type));
}
public static LwM2MFirmwareUpdateStrategy fromStrategyFwByCode(int code) {
for (LwM2MFirmwareUpdateStrategy to : LwM2MFirmwareUpdateStrategy.values()) {
if (to.code == code) {
return to;
}
}
throw new IllegalArgumentException(String.format("Unsupported FW Strategy code : %s", code));
}
}
public enum LwM2MSoftwareUpdateStrategy {
BINARY(1, "ObjectId 9, Binary"),
TEMP_URL(2, "ObjectId 9, URI");
public int code;
public String type;
LwM2MSoftwareUpdateStrategy(int code, String type) {
this.code = code;
this.type = type;
}
public static LwM2MSoftwareUpdateStrategy fromStrategySwByType(String type) {
for (LwM2MSoftwareUpdateStrategy to : LwM2MSoftwareUpdateStrategy.values()) {
if (to.type.equals(type)) {
return to;
}
}
throw new IllegalArgumentException(String.format("Unsupported SW Strategy type : %s", type));
}
public static LwM2MSoftwareUpdateStrategy fromStrategySwByCode(int code) {
for (LwM2MSoftwareUpdateStrategy to : LwM2MSoftwareUpdateStrategy.values()) {
if (to.code == code) {
return to;
}
}
throw new IllegalArgumentException(String.format("Unsupported SW Strategy code : %s", code));
}
}
/**
* FirmwareUpdateStatus {
* DOWNLOADING, DOWNLOADED, VERIFIED, UPDATING, UPDATED, FAILED
@ -635,7 +464,7 @@ public class LwM2mTransportUtil {
if (path != null) {
if (FW_STATE_ID.equals(path)) {
lwM2mOtaConvert.setCurrentType(STRING);
lwM2mOtaConvert.setValue(StateFw.fromStateFwByCode(((Long) value).intValue()).type);
lwM2mOtaConvert.setValue(UpdateStateFw.fromStateFwByCode(((Long) value).intValue()).type);
return lwM2mOtaConvert;
} else if (FW_RESULT_ID.equals(path)) {
lwM2mOtaConvert.setCurrentType(STRING);
@ -796,12 +625,12 @@ public class LwM2mTransportUtil {
return pathIdVer;
} else {
LwM2mPath pathObjId = new LwM2mPath(pathIdVer);
return convertPathFromObjectIdToIdVer(pathIdVer, registration);
return convertObjectIdToVersionedId(pathIdVer, registration);
}
}
}
public static String convertPathFromObjectIdToIdVer(String path, Registration registration) {
public static String convertObjectIdToVersionedId(String path, Registration registration) {
String ver = registration.getSupportedObject().get(new LwM2mPath(path).getObjectId());
ver = ver != null ? ver : LWM2M_VERSION_DEFAULT;
try {
@ -947,4 +776,20 @@ public class LwM2mTransportUtil {
|| OtaPackageUtil.getAttributeKey(OtaPackageType.SOFTWARE, OtaPackageKey.CHECKSUM_ALGORITHM).equals(pathName)
|| OtaPackageUtil.getAttributeKey(OtaPackageType.SOFTWARE, OtaPackageKey.SIZE).equals(pathName);
}
/**
* @param lwM2MClient -
* @param path -
* @return - return value of Resource by idPath
*/
public static LwM2mResource getResourceValueFromLwM2MClient(LwM2mClient lwM2MClient, String path) {
LwM2mResource lwm2mResourceValue = null;
ResourceValue resourceValue = lwM2MClient.getResources().get(path);
if (resourceValue != null) {
if (new LwM2mPath(fromVersionedIdToObjectId(path)).isResource()) {
lwm2mResourceValue = lwM2MClient.getResources().get(path).getLwM2mResource();
}
}
return lwm2mResourceValue;
}
}

70
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/UpdateResultFw.java

@ -0,0 +1,70 @@
/**
* Copyright © 2016-2021 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.transport.lwm2m.server;
/**
* FW Update Result
* 0: Initial value. Once the updating process is initiated (Download /Update), this Resource MUST be reset to Initial value.
* 1: Firmware updated successfully.
* 2: Not enough flash memory for the new firmware package.
* 3: Out of RAM during downloading process.
* 4: Connection lost during downloading process.
* 5: Integrity check failure for new downloaded package.
* 6: Unsupported package type.
* 7: Invalid URI.
* 8: Firmware update failed.
* 9: Unsupported protocol.
*/
public enum UpdateResultFw {
INITIAL(0, "Initial value", false),
UPDATE_SUCCESSFULLY(1, "Firmware updated successfully", false),
NOT_ENOUGH(2, "Not enough flash memory for the new firmware package", false),
OUT_OFF_MEMORY(3, "Out of RAM during downloading process", false),
CONNECTION_LOST(4, "Connection lost during downloading process", true),
INTEGRITY_CHECK_FAILURE(5, "Integrity check failure for new downloaded package", true),
UNSUPPORTED_TYPE(6, "Unsupported package type", false),
INVALID_URI(7, "Invalid URI", false),
UPDATE_FAILED(8, "Firmware update failed", false),
UNSUPPORTED_PROTOCOL(9, "Unsupported protocol", false);
public int code;
public String type;
public boolean isAgain;
UpdateResultFw(int code, String type, boolean isAgain) {
this.code = code;
this.type = type;
this.isAgain = isAgain;
}
public static UpdateResultFw fromUpdateResultFwByType(String type) {
for (UpdateResultFw to : UpdateResultFw.values()) {
if (to.type.equals(type)) {
return to;
}
}
throw new IllegalArgumentException(String.format("Unsupported FW Update Result type : %s", type));
}
public static UpdateResultFw fromUpdateResultFwByCode(int code) {
for (UpdateResultFw to : UpdateResultFw.values()) {
if (to.code == code) {
return to;
}
}
throw new IllegalArgumentException(String.format("Unsupported FW Update Result code : %s", code));
}
}

56
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/UpdateStateFw.java

@ -0,0 +1,56 @@
/**
* Copyright © 2016-2021 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.transport.lwm2m.server;
/**
* /** State R
* 0: Idle (before downloading or after successful updating)
* 1: Downloading (The data sequence is on the way)
* 2: Downloaded
* 3: Updating
*/
public enum UpdateStateFw {
IDLE(0, "Idle"),
DOWNLOADING(1, "Downloading"),
DOWNLOADED(2, "Downloaded"),
UPDATING(3, "Updating");
public int code;
public String type;
UpdateStateFw(int code, String type) {
this.code = code;
this.type = type;
}
public static UpdateStateFw fromStateFwByType(String type) {
for (UpdateStateFw to : UpdateStateFw.values()) {
if (to.type.equals(type)) {
return to;
}
}
throw new IllegalArgumentException(String.format("Unsupported FW State type : %s", type));
}
public static UpdateStateFw fromStateFwByCode(int code) {
for (UpdateStateFw to : UpdateStateFw.values()) {
if (to.code == code) {
return to;
}
}
throw new IllegalArgumentException(String.format("Unsupported FW State code : %s", code));
}
}

183
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/attributes/DefaultLwM2MAttributesService.java

@ -20,6 +20,8 @@ import com.google.common.util.concurrent.SettableFuture;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.leshan.core.model.ResourceModel;
import org.eclipse.leshan.core.node.LwM2mPath;
import org.eclipse.leshan.core.node.LwM2mResource;
import org.springframework.stereotype.Service;
import org.thingsboard.server.common.data.ota.OtaPackageKey;
import org.thingsboard.server.common.data.ota.OtaPackageType;
@ -29,17 +31,29 @@ import org.thingsboard.server.common.transport.TransportServiceCallback;
import org.thingsboard.server.gen.transport.TransportProtos;
import org.thingsboard.server.gen.transport.TransportProtos.GetAttributeResponseMsg;
import org.thingsboard.server.queue.util.TbLwM2mTransportComponent;
import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig;
import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportServerHelper;
import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil;
import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient;
import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientContext;
import org.thingsboard.server.transport.lwm2m.server.downlink.LwM2mDownlinkMsgHandler;
import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MWriteReplaceRequest;
import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MWriteResponseCallback;
import org.thingsboard.server.transport.lwm2m.server.ota.DefaultLwM2MOtaUpdateService;
import org.thingsboard.server.transport.lwm2m.server.ota.LwM2MOtaUpdateService;
import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mUplinkMsgHandler;
import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicInteger;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportServerHelper.getValueFromKvProto;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LWM2M_ERROR;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.isFwSwWords;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.fromVersionedIdToObjectId;
@Slf4j
@Service
@ -52,6 +66,12 @@ public class DefaultLwM2MAttributesService implements LwM2MAttributesService {
private final Map<Integer, SettableFuture<List<TransportProtos.TsKvProto>>> futures;
private final TransportService transportService;
private final LwM2mTransportServerHelper helper;
private final LwM2mClientContext clientContext;
private final LwM2MTransportServerConfig config;
private final LwM2mUplinkMsgHandler uplinkHandler;
private final LwM2mDownlinkMsgHandler downlinkHandler;
private final LwM2MOtaUpdateService otaUpdateService;
@Override
public ListenableFuture<List<TransportProtos.TsKvProto>> getSharedAttributes(LwM2mClient client, Collection<String> keys) {
@ -96,55 +116,114 @@ public class DefaultLwM2MAttributesService implements LwM2MAttributesService {
* @param msg -
*/
@Override
public void onAttributeUpdate(TransportProtos.AttributeUpdateNotificationMsg msg, TransportProtos.SessionInfoProto sessionInfo) {
// LwM2mClient lwM2MClient = clientContext.getClientBySessionInfo(sessionInfo);
// if (msg.getSharedUpdatedCount() > 0 && lwM2MClient != null) {
// log.warn("2) OnAttributeUpdate, SharedUpdatedList() [{}]", msg.getSharedUpdatedList());
// msg.getSharedUpdatedList().forEach(tsKvProto -> {
// String pathName = tsKvProto.getKv().getKey();
// String pathIdVer = this.getObjectIdByKeyNameFromProfile(sessionInfo, pathName);
// Object valueNew = getValueFromKvProto(tsKvProto.getKv());
// if ((OtaPackageUtil.getAttributeKey(OtaPackageType.FIRMWARE, OtaPackageKey.VERSION).equals(pathName)
// && (!valueNew.equals(lwM2MClient.getFwUpdate().getCurrentVersion())))
// || (OtaPackageUtil.getAttributeKey(OtaPackageType.FIRMWARE, OtaPackageKey.TITLE).equals(pathName)
// && (!valueNew.equals(lwM2MClient.getFwUpdate().getCurrentTitle())))) {
// this.getInfoFirmwareUpdate(lwM2MClient, null);
// } else if ((OtaPackageUtil.getAttributeKey(OtaPackageType.SOFTWARE, OtaPackageKey.VERSION).equals(pathName)
// && (!valueNew.equals(lwM2MClient.getSwUpdate().getCurrentVersion())))
// || (OtaPackageUtil.getAttributeKey(OtaPackageType.SOFTWARE, OtaPackageKey.TITLE).equals(pathName)
// && (!valueNew.equals(lwM2MClient.getSwUpdate().getCurrentTitle())))) {
// this.getInfoSoftwareUpdate(lwM2MClient, null);
// }
// if (pathIdVer != null) {
// ResourceModel resourceModel = lwM2MClient.getResourceModel(pathIdVer, this.config
// .getModelProvider());
// if (resourceModel != null && resourceModel.operations.isWritable()) {
// this.updateResourcesValueToClient(lwM2MClient, this.getResourceValueFormatKv(lwM2MClient, pathIdVer), valueNew, pathIdVer);
// } else {
// log.error("Resource path - [{}] value - [{}] is not Writable and cannot be updated", pathIdVer, valueNew);
// String logMsg = String.format("%s: attributeUpdate: Resource path - %s value - %s is not Writable and cannot be updated",
// LOG_LWM2M_ERROR, pathIdVer, valueNew);
// this.logToTelemetry(lwM2MClient, logMsg);
// }
// } else if (!isFwSwWords(pathName)) {
// log.error("Resource name name - [{}] value - [{}] is not present as attribute/telemetry in profile and cannot be updated", pathName, valueNew);
// String logMsg = String.format("%s: attributeUpdate: attribute name - %s value - %s is not present as attribute in profile and cannot be updated",
// LOG_LWM2M_ERROR, pathName, valueNew);
// this.logToTelemetry(lwM2MClient, logMsg);
// }
//
// });
// } else if (msg.getSharedDeletedCount() > 0 && lwM2MClient != null) {
// msg.getSharedUpdatedList().forEach(tsKvProto -> {
// String pathName = tsKvProto.getKv().getKey();
// Object valueNew = getValueFromKvProto(tsKvProto.getKv());
// if (OtaPackageUtil.getAttributeKey(OtaPackageType.FIRMWARE, OtaPackageKey.VERSION).equals(pathName) && !valueNew.equals(lwM2MClient.getFwUpdate().getCurrentVersion())) {
// lwM2MClient.getFwUpdate().setCurrentVersion((String) valueNew);
// }
// });
// log.info("[{}] delete [{}] onAttributeUpdate", msg.getSharedDeletedList(), sessionInfo);
// } else if (lwM2MClient == null) {
// log.error("OnAttributeUpdate, lwM2MClient is null");
// }
public void onAttributesUpdate(TransportProtos.AttributeUpdateNotificationMsg msg, TransportProtos.SessionInfoProto sessionInfo) {
LwM2mClient lwM2MClient = clientContext.getClientBySessionInfo(sessionInfo);
if (msg.getSharedUpdatedCount() > 0 && lwM2MClient != null) {
String newFirmwareTitle = null;
String newFirmwareVersion = null;
String newFirmwareUrl = null;
String newSoftwareTitle = null;
String newSoftwareVersion = null;
List<TransportProtos.TsKvProto> otherAttributes = new ArrayList<>();
for (TransportProtos.TsKvProto tsKvProto : msg.getSharedUpdatedList()) {
String attrName = tsKvProto.getKv().getKey();
if (DefaultLwM2MOtaUpdateService.FIRMWARE_TITLE.equals(attrName)) {
newFirmwareTitle = getStrValue(tsKvProto);
} else if (DefaultLwM2MOtaUpdateService.FIRMWARE_VERSION.equals(attrName)) {
newFirmwareVersion = getStrValue(tsKvProto);
} else if (DefaultLwM2MOtaUpdateService.FIRMWARE_URL.equals(attrName)) {
newFirmwareUrl = getStrValue(tsKvProto);
} else if (DefaultLwM2MOtaUpdateService.SOFTWARE_TITLE.equals(attrName)) {
newSoftwareTitle = getStrValue(tsKvProto);
} else if (DefaultLwM2MOtaUpdateService.SOFTWARE_VERSION.equals(attrName)) {
newSoftwareVersion = getStrValue(tsKvProto);
} else {
otherAttributes.add(tsKvProto);
}
}
if (newFirmwareTitle != null || newFirmwareVersion != null) {
otaUpdateService.onTargetFirmwareUpdate(lwM2MClient, newFirmwareTitle, newFirmwareVersion, Optional.ofNullable(newFirmwareUrl));
}
if (newSoftwareTitle != null || newSoftwareVersion != null) {
otaUpdateService.onTargetSoftwareUpdate(lwM2MClient, newSoftwareTitle, newSoftwareVersion);
}
if (!otherAttributes.isEmpty()) {
onAttributesUpdate(lwM2MClient, otherAttributes);
}
} else if (msg.getSharedDeletedCount() > 0 && lwM2MClient != null) {
msg.getSharedUpdatedList().forEach(tsKvProto -> {
String pathName = tsKvProto.getKv().getKey();
Object valueNew = getValueFromKvProto(tsKvProto.getKv());
if (OtaPackageUtil.getAttributeKey(OtaPackageType.FIRMWARE, OtaPackageKey.VERSION).equals(pathName) && !valueNew.equals(lwM2MClient.getFwUpdate().getCurrentVersion())) {
lwM2MClient.getFwUpdate().setCurrentVersion((String) valueNew);
}
});
} else if (lwM2MClient == null) {
log.error("OnAttributeUpdate, lwM2MClient is null");
}
}
/**
* #1.1 If two names have equal path => last time attribute
* #2.1 if there is a difference in values between the current resource values and the shared attribute values
* => send to client Request Update of value (new value from shared attribute)
* and LwM2MClient.delayedRequests.add(path)
* #2.1 if there is not a difference in values between the current resource values and the shared attribute values
*
*/
@Override
public void onAttributesUpdate(LwM2mClient lwM2MClient, List<TransportProtos.TsKvProto> tsKvProtos) {
log.trace("[{}] onAttributesUpdate [{}]", lwM2MClient.getEndpoint(), tsKvProtos);
tsKvProtos.forEach(tsKvProto -> {
String pathIdVer = clientContext.getObjectIdByKeyNameFromProfile(lwM2MClient, tsKvProto.getKv().getKey());
if (pathIdVer != null) {
// #1.1
if (lwM2MClient.getSharedAttributes().containsKey(pathIdVer)) {
if (tsKvProto.getTs() > lwM2MClient.getSharedAttributes().get(pathIdVer).getTs()) {
lwM2MClient.getSharedAttributes().put(pathIdVer, tsKvProto);
}
} else {
lwM2MClient.getSharedAttributes().put(pathIdVer, tsKvProto);
}
}
});
// #2.1
lwM2MClient.getSharedAttributes().forEach((pathIdVer, tsKvProto) -> {
this.pushUpdateToClientIfNeeded(lwM2MClient, this.getResourceValueFormatKv(lwM2MClient, pathIdVer),
getValueFromKvProto(tsKvProto.getKv()), pathIdVer);
});
}
private void pushUpdateToClientIfNeeded(LwM2mClient lwM2MClient, Object valueOld, Object newValue, String versionedId) {
if (newValue != null && (valueOld == null || !newValue.toString().equals(valueOld.toString()))) {
TbLwM2MWriteReplaceRequest request = TbLwM2MWriteReplaceRequest.builder().versionedId(versionedId).value(newValue).timeout(this.config.getTimeout()).build();
downlinkHandler.sendWriteReplaceRequest(lwM2MClient, request, new TbLwM2MWriteResponseCallback(uplinkHandler, lwM2MClient, versionedId));
} else {
log.error("Failed update resource [{}] [{}]", versionedId, newValue);
String logMsg = String.format("%s: Failed update resource versionedId - %s value - %s. Value is not changed or bad",
LOG_LWM2M_ERROR, versionedId, newValue);
uplinkHandler.logToTelemetry(lwM2MClient, logMsg);
log.info("Failed update resource [{}] [{}]", versionedId, newValue);
}
}
/**
* @param pathIdVer - path resource
* @return - value of Resource into format KvProto or null
*/
private Object getResourceValueFormatKv(LwM2mClient lwM2MClient, String pathIdVer) {
LwM2mResource resourceValue = LwM2mTransportUtil.getResourceValueFromLwM2MClient(lwM2MClient, pathIdVer);
if (resourceValue != null) {
ResourceModel.Type currentType = resourceValue.getType();
ResourceModel.Type expectedType = helper.getResourceModelTypeEqualsKvProtoValueType(currentType, pathIdVer);
return LwM2mValueConverterImpl.getInstance().convertValue(resourceValue.getValue(), currentType, expectedType,
new LwM2mPath(fromVersionedIdToObjectId(pathIdVer)));
} else {
return null;
}
}
private String getStrValue(TransportProtos.TsKvProto tsKvProto) {
return tsKvProto.getKv().getStringV();
}
}

4
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/attributes/LwM2MAttributesService.java

@ -28,5 +28,7 @@ public interface LwM2MAttributesService {
void onGetAttributesResponse(TransportProtos.GetAttributeResponseMsg getAttributesResponse, TransportProtos.SessionInfoProto sessionInfo);
void onAttributeUpdate(TransportProtos.AttributeUpdateNotificationMsg attributeUpdateNotification, TransportProtos.SessionInfoProto sessionInfo);
void onAttributesUpdate(TransportProtos.AttributeUpdateNotificationMsg attributeUpdateNotification, TransportProtos.SessionInfoProto sessionInfo);
void onAttributesUpdate(LwM2mClient lwM2MClient, List<TransportProtos.TsKvProto> tsKvProtos);
}

9
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java

@ -38,11 +38,9 @@ import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsRes
import org.thingsboard.server.gen.transport.TransportProtos.SessionInfoProto;
import org.thingsboard.server.gen.transport.TransportProtos.TsKvProto;
import org.thingsboard.server.transport.lwm2m.server.LwM2mQueuedRequest;
import org.thingsboard.server.transport.lwm2m.server.uplink.DefaultLwM2MUplinkMsgHandler;
import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mUplinkMsgHandler;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Queue;
@ -50,14 +48,13 @@ import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.Collectors;
import static org.thingsboard.server.common.data.lwm2m.LwM2mConstants.LWM2M_SEPARATOR_PATH;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.TRANSPORT_DEFAULT_LWM2M_VERSION;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertPathFromObjectIdToIdVer;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertObjectIdToVersionedId;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.equalsResourceTypeGetSimpleName;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.fromVersionedIdToObjectId;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.getVerFromPathIdVerOrId;
@ -202,7 +199,7 @@ public class LwM2mClient implements Cloneable {
}
public Object getResourceValue(String pathRezIdVer, String pathRezId) {
String pathRez = pathRezIdVer == null ? convertPathFromObjectIdToIdVer(pathRezId, this.registration) : pathRezIdVer;
String pathRez = pathRezIdVer == null ? convertObjectIdToVersionedId(pathRezId, this.registration) : pathRezIdVer;
if (this.resources.get(pathRez) != null) {
return this.resources.get(pathRez).getLwM2mResource().getValue();
}
@ -210,7 +207,7 @@ public class LwM2mClient implements Cloneable {
}
public Object getResourceNameByRezId(String pathRezIdVer, String pathRezId) {
String pathRez = pathRezIdVer == null ? convertPathFromObjectIdToIdVer(pathRezId, this.registration) : pathRezIdVer;
String pathRez = pathRezIdVer == null ? convertObjectIdToVersionedId(pathRezId, this.registration) : pathRezIdVer;
if (this.resources.get(pathRez) != null) {
return this.resources.get(pathRez).getResourceModel().name;
}

5
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContext.java

@ -53,7 +53,10 @@ public interface LwM2mClientContext {
LwM2mClient getClientByDeviceId(UUID deviceId);
void registerClient(Registration registration, ValidateDeviceCredentialsResponse credentials);
String getObjectIdByKeyNameFromProfile(TransportProtos.SessionInfoProto sessionInfo, String keyName);
String getObjectIdByKeyNameFromProfile(LwM2mClient lwM2mClient, String keyName);
void registerClient(Registration registration, ValidateDeviceCredentialsResponse credentials);
}

41
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContextImpl.java

@ -17,6 +17,7 @@ package org.thingsboard.server.transport.lwm2m.server.client;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.leshan.core.model.ResourceModel;
import org.eclipse.leshan.core.node.LwM2mPath;
import org.eclipse.leshan.server.registration.Registration;
import org.springframework.stereotype.Service;
@ -25,6 +26,7 @@ import org.thingsboard.server.common.data.device.profile.Lwm2mDeviceProfileTrans
import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse;
import org.thingsboard.server.gen.transport.TransportProtos;
import org.thingsboard.server.queue.util.TbLwM2mTransportComponent;
import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig;
import org.thingsboard.server.transport.lwm2m.secure.TbLwM2MSecurityInfo;
import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportContext;
import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil;
@ -40,7 +42,9 @@ import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Predicate;
import static org.eclipse.leshan.core.SecurityMode.NO_SEC;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertPathFromObjectIdToIdVer;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertObjectIdToVersionedId;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.fromVersionedIdToObjectId;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.validateObjectVerFromKey;
@Slf4j
@Service
@ -49,6 +53,7 @@ import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.c
public class LwM2mClientContextImpl implements LwM2mClientContext {
private final LwM2mTransportContext context;
private final LwM2MTransportServerConfig config;
private final TbEditableSecurityStore securityStore;
private final Map<String, LwM2mClient> lwM2mClientsByEndpoint = new ConcurrentHashMap<>();
private final Map<String, LwM2mClient> lwM2mClientsByRegistrationId = new ConcurrentHashMap<>();
@ -160,6 +165,28 @@ public class LwM2mClientContextImpl implements LwM2mClientContext {
return lwM2mClient;
}
/**
* Get path to resource from profile equal keyName
*
* @param sessionInfo -
* @param keyName -
* @return -
*/
@Override
public String getObjectIdByKeyNameFromProfile(TransportProtos.SessionInfoProto sessionInfo, String keyName) {
return getObjectIdByKeyNameFromProfile(getClientBySessionInfo(sessionInfo), keyName);
}
@Override
public String getObjectIdByKeyNameFromProfile(LwM2mClient lwM2mClient, String keyName) {
Lwm2mDeviceProfileTransportConfiguration profile = getProfile(lwM2mClient.getProfileId());
return profile.getObserveAttr().getKeyName().entrySet().stream()
.filter(e -> e.getValue().equals(keyName) && validateResourceInModel(lwM2mClient, e.getKey(), false)).findFirst().orElseThrow(
() -> new IllegalArgumentException(keyName + " is not configured in the device profile!")
).getKey();
}
public Registration getRegistration(String registrationId) {
return this.lwM2mClientsByRegistrationId.get(registrationId).getRegistration();
}
@ -200,7 +227,7 @@ public class LwM2mClientContextImpl implements LwM2mClientContext {
Arrays.stream(client.getRegistration().getObjectLinks()).forEach(link -> {
LwM2mPath pathIds = new LwM2mPath(link.getUrl());
if (!pathIds.isRoot()) {
clientObjects.add(convertPathFromObjectIdToIdVer(link.getUrl(), client.getRegistration()));
clientObjects.add(convertObjectIdToVersionedId(link.getUrl(), client.getRegistration()));
}
});
return (clientObjects.size() > 0) ? clientObjects : null;
@ -211,4 +238,14 @@ public class LwM2mClientContextImpl implements LwM2mClientContext {
return lwM2mClientsByRegistrationId.values().stream().filter(e -> deviceId.equals(e.getDeviceId())).findFirst().orElse(null);
}
private boolean validateResourceInModel(LwM2mClient lwM2mClient, String pathIdVer, boolean isWritableNotOptional) {
ResourceModel resourceModel = lwM2mClient.getResourceModel(pathIdVer, this.config
.getModelProvider());
Integer objectId = new LwM2mPath(fromVersionedIdToObjectId(pathIdVer)).getObjectId();
String objectVer = validateObjectVerFromKey(pathIdVer);
return resourceModel != null && (isWritableNotOptional ?
objectId != null && objectVer != null && objectVer.equals(lwM2mClient.getRegistration().getSupportedVersion(objectId)) && resourceModel.operations.isWritable() :
objectId != null && objectVer != null && objectVer.equals(lwM2mClient.getRegistration().getSupportedVersion(objectId)));
}
}

65
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mFwSwUpdate.java

@ -23,7 +23,10 @@ import org.eclipse.leshan.server.registration.Registration;
import org.thingsboard.server.common.data.ota.OtaPackageType;
import org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus;
import org.thingsboard.server.gen.transport.TransportProtos;
import org.thingsboard.server.transport.lwm2m.server.LwM2MFirmwareUpdateStrategy;
import org.thingsboard.server.transport.lwm2m.server.LwM2mOperationType;
import org.thingsboard.server.transport.lwm2m.server.UpdateStateFw;
import org.thingsboard.server.transport.lwm2m.server.UpdateResultFw;
import org.thingsboard.server.transport.lwm2m.server.uplink.DefaultLwM2MUplinkMsgHandler;
import org.thingsboard.server.transport.lwm2m.server.downlink.LwM2mDownlinkMsgHandler;
import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil;
@ -62,9 +65,9 @@ import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.F
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.FW_UPDATE_ID;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LWM2M_ERROR;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LWM2M_INFO;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2MFirmwareUpdateStrategy.OBJ_19_BINARY;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2MFirmwareUpdateStrategy.OBJ_5_BINARY;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2MFirmwareUpdateStrategy.OBJ_5_TEMP_URL;
import static org.thingsboard.server.transport.lwm2m.server.LwM2MFirmwareUpdateStrategy.OBJ_19_BINARY;
import static org.thingsboard.server.transport.lwm2m.server.LwM2MFirmwareUpdateStrategy.OBJ_5_BINARY;
import static org.thingsboard.server.transport.lwm2m.server.LwM2MFirmwareUpdateStrategy.OBJ_5_TEMP_URL;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mOperationType.EXECUTE;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mOperationType.WRITE_REPLACE;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.SW_INSTALL_ID;
@ -75,8 +78,8 @@ import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.S
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.SW_UPDATE;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.SW_UPDATE_STATE_ID;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.SW_VER_ID;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertPathFromObjectIdToIdVer;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.equalsFwSateToFirmwareUpdateStatus;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertObjectIdToVersionedId;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.toOtaPackageUpdateStatus;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.splitCamelCaseString;
@Slf4j
@ -140,8 +143,8 @@ public class LwM2mFwSwUpdate {
private void initPathId() {
if (FIRMWARE.equals(this.type)) {
this.pathPackageId = LwM2mTransportUtil.LwM2MFirmwareUpdateStrategy.OBJ_5_BINARY.code == this.updateStrategy ?
FW_PACKAGE_5_ID : LwM2mTransportUtil.LwM2MFirmwareUpdateStrategy.OBJ_5_TEMP_URL.code == this.updateStrategy ?
this.pathPackageId = LwM2MFirmwareUpdateStrategy.OBJ_5_BINARY.code == this.updateStrategy ?
FW_PACKAGE_5_ID : LwM2MFirmwareUpdateStrategy.OBJ_5_TEMP_URL.code == this.updateStrategy ?
FW_PACKAGE_URI_ID : FW_PACKAGE_19_ID;
this.pathStateId = FW_STATE_ID;
this.pathResultId = FW_RESULT_ID;
@ -185,26 +188,26 @@ public class LwM2mFwSwUpdate {
if (this.currentId != null) {
this.stateUpdate = OtaPackageUpdateStatus.INITIATED.name();
this.sendLogs(handler, WRITE_REPLACE.name(), LOG_LWM2M_INFO, null);
String targetIdVer = convertPathFromObjectIdToIdVer(this.pathPackageId, this.lwM2MClient.getRegistration());
String targetIdVer = convertObjectIdToVersionedId(this.pathPackageId, this.lwM2MClient.getRegistration());
String fwMsg = String.format("%s: Start type operation %s paths: %s", LOG_LWM2M_INFO,
LwM2mOperationType.FW_UPDATE.name(), this.pathPackageId);
handler.logToTelemetry(fwMsg, lwM2MClient.getRegistration().getId());
log.warn("8) Start firmware Update. Send save to: [{}] ver: [{}] path: [{}]", this.lwM2MClient.getDeviceName(), this.currentVersion, targetIdVer);
if (LwM2mTransportUtil.LwM2MFirmwareUpdateStrategy.OBJ_5_BINARY.code == this.updateStrategy) {
if (LwM2MFirmwareUpdateStrategy.OBJ_5_BINARY.code == this.updateStrategy) {
int chunkSize = 0;
int chunk = 0;
byte[] firmwareChunk = handler.otaPackageDataCache.get(this.currentId.toString(), chunkSize, chunk);
TbLwM2MWriteReplaceRequest downlink = TbLwM2MWriteReplaceRequest.builder().versionedId(targetIdVer).value(firmwareChunk).timeout(handler.config.getTimeout()).build();
request.sendWriteReplaceRequest(lwM2MClient, downlink, new TbLwM2MWriteResponseCallback(handler, lwM2MClient, targetIdVer));
} else if (LwM2mTransportUtil.LwM2MFirmwareUpdateStrategy.OBJ_5_TEMP_URL.code == this.updateStrategy) {
} else if (LwM2MFirmwareUpdateStrategy.OBJ_5_TEMP_URL.code == this.updateStrategy) {
String apiFont = "coap://176.36.143.9:5685";
String uri = apiFont + "/" + FIRMWARE_UPDATE_COAP_RECOURSE + "/" + this.currentId.toString();
log.warn("89) coapUri: [{}]", uri);
//TODO: user this.rpcRequest???
TbLwM2MWriteReplaceRequest downlink = TbLwM2MWriteReplaceRequest.builder().versionedId(targetIdVer).value(uri).timeout(handler.config.getTimeout()).build();
request.sendWriteReplaceRequest(lwM2MClient, downlink, new TbLwM2MWriteResponseCallback(handler, lwM2MClient, targetIdVer));
} else if (LwM2mTransportUtil.LwM2MFirmwareUpdateStrategy.OBJ_19_BINARY.code == this.updateStrategy) {
} else if (LwM2MFirmwareUpdateStrategy.OBJ_19_BINARY.code == this.updateStrategy) {
}
} else {
@ -269,7 +272,7 @@ public class LwM2mFwSwUpdate {
(this.currentTitle != null && pathName != null && this.currentTitle.equals(pathName))) {
fwMsg = String.format("%s: The update was interrupted. The device has the same version: %s.", LOG_LWM2M_ERROR,
this.currentVersion);
} else if (updateResultFw != null && updateResultFw > LwM2mTransportUtil.UpdateResultFw.UPDATE_SUCCESSFULLY.code) {
} else if (updateResultFw != null && updateResultFw > UpdateResultFw.UPDATE_SUCCESSFULLY.code) {
fwMsg = String.format("%s: The update was interrupted. The device has the status UpdateResult: error (%d).", LOG_LWM2M_ERROR,
updateResultFw);
}
@ -288,7 +291,7 @@ public class LwM2mFwSwUpdate {
*/
public boolean conditionalFwExecuteStart() {
Long updateResult = (Long) this.lwM2MClient.getResourceValue(null, this.pathResultId);
return LwM2mTransportUtil.UpdateResultFw.INITIAL.code == updateResult;
return UpdateResultFw.INITIAL.code == updateResult;
}
/**
@ -297,7 +300,7 @@ public class LwM2mFwSwUpdate {
*/
public boolean conditionalFwExecuteAfterSuccess() {
Long updateResult = (Long) this.lwM2MClient.getResourceValue(null, this.pathResultId);
return LwM2mTransportUtil.UpdateResultFw.UPDATE_SUCCESSFULLY.code == updateResult;
return UpdateResultFw.UPDATE_SUCCESSFULLY.code == updateResult;
}
/**
@ -306,7 +309,7 @@ public class LwM2mFwSwUpdate {
*/
public boolean conditionalFwExecuteAfterError() {
Long updateResult = (Long) this.lwM2MClient.getResourceValue(null, this.pathResultId);
return LwM2mTransportUtil.UpdateResultFw.UPDATE_SUCCESSFULLY.code < updateResult;
return UpdateResultFw.UPDATE_SUCCESSFULLY.code < updateResult;
}
/**
@ -354,7 +357,7 @@ public class LwM2mFwSwUpdate {
*/
public void finishFwSwUpdate(DefaultLwM2MUplinkMsgHandler handler, boolean success) {
Long updateResult = (Long) this.lwM2MClient.getResourceValue(null, this.pathResultId);
String value = FIRMWARE.equals(this.type) ? LwM2mTransportUtil.UpdateResultFw.fromUpdateResultFwByCode(updateResult.intValue()).type :
String value = FIRMWARE.equals(this.type) ? UpdateResultFw.fromUpdateResultFwByCode(updateResult.intValue()).type :
LwM2mTransportUtil.UpdateResultSw.fromUpdateResultSwByCode(updateResult.intValue()).type;
String key = splitCamelCaseString((String) this.lwM2MClient.getResourceNameByRezId(null, this.pathResultId));
if (success) {
@ -408,18 +411,18 @@ public class LwM2mFwSwUpdate {
public void sendReadObserveInfo(LwM2mDownlinkMsgHandler request) {
this.infoFwSwUpdate = true;
this.pendingInfoRequestsStart.add(convertPathFromObjectIdToIdVer(
this.pendingInfoRequestsStart.add(convertObjectIdToVersionedId(
this.pathStateId, this.lwM2MClient.getRegistration()));
this.pendingInfoRequestsStart.add(convertPathFromObjectIdToIdVer(
this.pendingInfoRequestsStart.add(convertObjectIdToVersionedId(
this.pathResultId, this.lwM2MClient.getRegistration()));
this.pendingInfoRequestsStart.add(convertPathFromObjectIdToIdVer(
this.pendingInfoRequestsStart.add(convertObjectIdToVersionedId(
FW_3_VER_ID, this.lwM2MClient.getRegistration()));
if (LwM2mTransportUtil.LwM2MFirmwareUpdateStrategy.OBJ_5_BINARY.code == this.updateStrategy ||
LwM2mTransportUtil.LwM2MFirmwareUpdateStrategy.OBJ_19_BINARY.code == this.updateStrategy ||
if (LwM2MFirmwareUpdateStrategy.OBJ_5_BINARY.code == this.updateStrategy ||
LwM2MFirmwareUpdateStrategy.OBJ_19_BINARY.code == this.updateStrategy ||
SOFTWARE.equals(this.type)) {
this.pendingInfoRequestsStart.add(convertPathFromObjectIdToIdVer(
this.pendingInfoRequestsStart.add(convertObjectIdToVersionedId(
this.pathVerId, this.lwM2MClient.getRegistration()));
this.pendingInfoRequestsStart.add(convertPathFromObjectIdToIdVer(
this.pendingInfoRequestsStart.add(convertObjectIdToVersionedId(
this.pathNameId, this.lwM2MClient.getRegistration()));
}
this.pendingInfoRequestsStart.forEach(versionedId -> {
@ -442,7 +445,7 @@ public class LwM2mFwSwUpdate {
public void updateStateOta(DefaultLwM2MUplinkMsgHandler handler, LwM2mDownlinkMsgHandler request,
Registration registration, String path, int value) {
if (OBJ_5_BINARY.code == this.getUpdateStrategy()) {
if ((convertPathFromObjectIdToIdVer(FW_RESULT_ID, registration).equals(path))) {
if ((convertObjectIdToVersionedId(FW_RESULT_ID, registration).equals(path))) {
if (DOWNLOADED.name().equals(this.getStateUpdate())
&& this.conditionalFwExecuteStart()) {
this.executeFwSwWare(handler, request);
@ -455,23 +458,23 @@ public class LwM2mFwSwUpdate {
}
}
} else if (OBJ_5_TEMP_URL.code == this.getUpdateStrategy()) {
if (this.currentId != null && (convertPathFromObjectIdToIdVer(FW_STATE_ID, registration).equals(path))) {
String state = equalsFwSateToFirmwareUpdateStatus(LwM2mTransportUtil.StateFw.fromStateFwByCode(value)).name();
if (this.currentId != null && (convertObjectIdToVersionedId(FW_STATE_ID, registration).equals(path))) {
String state = toOtaPackageUpdateStatus(UpdateStateFw.fromStateFwByCode(value)).name();
if (StringUtils.isNotEmpty(state) && !FAILED.name().equals(this.stateUpdate) && !state.equals(this.stateUpdate)) {
this.stateUpdate = state;
this.sendSateOnThingsBoard(handler);
}
if (value == LwM2mTransportUtil.StateFw.DOWNLOADED.code) {
if (value == UpdateStateFw.DOWNLOADED.code) {
this.executeFwSwWare(handler, request);
}
handler.firmwareUpdateState.put(lwM2MClient.getEndpoint(), value);
}
if ((convertPathFromObjectIdToIdVer(FW_RESULT_ID, registration).equals(path))) {
if (this.currentId != null && value == LwM2mTransportUtil.UpdateResultFw.INITIAL.code) {
if ((convertObjectIdToVersionedId(FW_RESULT_ID, registration).equals(path))) {
if (this.currentId != null && value == UpdateResultFw.INITIAL.code) {
this.setStateUpdate(INITIATED.name());
} else if (this.currentId != null && value == LwM2mTransportUtil.UpdateResultFw.UPDATE_SUCCESSFULLY.code) {
} else if (this.currentId != null && value == UpdateResultFw.UPDATE_SUCCESSFULLY.code) {
this.setStateUpdate(UPDATED.name());
} else if (value > LwM2mTransportUtil.UpdateResultFw.UPDATE_SUCCESSFULLY.code) {
} else if (value > UpdateResultFw.UPDATE_SUCCESSFULLY.code) {
this.setStateUpdate(FAILED.name());
}
this.sendSateOnThingsBoard(handler);

6
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MWriteReplaceRequest.java

@ -17,17 +17,21 @@ package org.thingsboard.server.transport.lwm2m.server.downlink;
import lombok.Builder;
import lombok.Getter;
import org.eclipse.leshan.core.request.ContentFormat;
import org.eclipse.leshan.core.response.WriteResponse;
import org.thingsboard.server.transport.lwm2m.server.LwM2mOperationType;
public class TbLwM2MWriteReplaceRequest extends AbstractTbLwM2MTargetedDownlinkRequest<WriteResponse> {
@Getter
private final ContentFormat contentFormat;
@Getter
private final Object value;
@Builder
private TbLwM2MWriteReplaceRequest(String versionedId, long timeout, Object value) {
private TbLwM2MWriteReplaceRequest(String versionedId, long timeout, ContentFormat contentFormat, Object value) {
super(versionedId, timeout);
this.contentFormat = contentFormat;
this.value = value;
}

248
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ota/DefaultLwM2MOtaUpdateService.java

@ -17,21 +17,50 @@ package org.thingsboard.server.transport.lwm2m.server.ota;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.leshan.core.request.ContentFormat;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.thingsboard.common.util.DonAsynchron;
import org.thingsboard.common.util.ThingsBoardExecutors;
import org.thingsboard.server.cache.ota.OtaPackageDataCache;
import org.thingsboard.server.common.data.StringUtils;
import org.thingsboard.server.common.data.ota.OtaPackageKey;
import org.thingsboard.server.common.data.ota.OtaPackageType;
import org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus;
import org.thingsboard.server.common.transport.TransportService;
import org.thingsboard.server.common.transport.TransportServiceCallback;
import org.thingsboard.server.gen.transport.TransportProtos;
import org.thingsboard.server.queue.util.TbLwM2mTransportComponent;
import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig;
import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportServerHelper;
import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil;
import org.thingsboard.server.transport.lwm2m.server.UpdateStateFw;
import org.thingsboard.server.transport.lwm2m.server.UpdateResultFw;
import org.thingsboard.server.transport.lwm2m.server.attributes.LwM2MAttributesService;
import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient;
import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientContext;
import org.thingsboard.server.transport.lwm2m.server.downlink.LwM2mDownlinkMsgHandler;
import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MExecuteCallback;
import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MExecuteRequest;
import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MWriteReplaceRequest;
import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MWriteResponseCallback;
import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MWriteUpdateRequest;
import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mUplinkMsgHandler;
import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import static org.thingsboard.server.common.data.ota.OtaPackageKey.STATE;
import static org.thingsboard.server.common.data.ota.OtaPackageUtil.getAttributeKey;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.FIRMWARE_UPDATE_COAP_RECOURSE;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertObjectIdToVersionedId;
@Slf4j
@Service
@ -39,45 +68,228 @@ import static org.thingsboard.server.common.data.ota.OtaPackageUtil.getAttribute
@RequiredArgsConstructor
public class DefaultLwM2MOtaUpdateService implements LwM2MOtaUpdateService {
public static final String FIRMWARE_VERSION = getAttributeKey(OtaPackageType.FIRMWARE, OtaPackageKey.VERSION);
public static final String FIRMWARE_TITLE = getAttributeKey(OtaPackageType.FIRMWARE, OtaPackageKey.TITLE);
public static final String FIRMWARE_URL = getAttributeKey(OtaPackageType.FIRMWARE, OtaPackageKey.URL);
public static final String SOFTWARE_VERSION = getAttributeKey(OtaPackageType.SOFTWARE, OtaPackageKey.VERSION);
public static final String SOFTWARE_TITLE = getAttributeKey(OtaPackageType.SOFTWARE, OtaPackageKey.TITLE);
public static final String SOFTWARE_URL = getAttributeKey(OtaPackageType.SOFTWARE, OtaPackageKey.URL);
private static final String FW_PACKAGE_5_ID = "/5/0/0";
private static final String FW_URL_ID = "/5/0/1";
private static final String FW_EXECUTE_ID = "/5/0/2";
private static final String FW_NAME_ID = "/5/0/6";
private static final String FW_VER_ID = "/5/0/7";
private static final String SW_NAME_ID = "/9/0/0";
private static final String SW_VER_ID = "/9/0/1";
private final Map<String, LwM2MClientOtaState> fwStates = new ConcurrentHashMap<>();
private final Map<String, LwM2MClientOtaState> swStates = new ConcurrentHashMap<>();
private final Map<String, LwM2MClientOtaInfo> fwStates = new ConcurrentHashMap<>();
private final Map<String, LwM2MClientOtaInfo> swStates = new ConcurrentHashMap<>();
private final LwM2MAttributesService attributesService;
private final TransportService transportService;
private final LwM2mClientContext clientContext;
private final LwM2MTransportServerConfig config;
private final LwM2mUplinkMsgHandler uplinkHandler;
private final LwM2mDownlinkMsgHandler downlinkHandler;
private final OtaPackageDataCache otaPackageDataCache;
private final LwM2mTransportServerHelper helper;
private ExecutorService executor;
@Autowired
@Lazy
private LwM2MAttributesService attributesService;
@PostConstruct
public void init() {
//TODO: define parallelism in constant
executor = ThingsBoardExecutors.newWorkStealingPool(4, "LwM2M OTA Updates");
}
@Override
public void init(LwM2mClient client) {
//TODO: add locks by client fwInfo.
//TODO: check that the client supports FW and SW by checking the supported objects in the model.
List<String> attributesToFetch = new ArrayList<>();
if (client.isValidObjectVersion(FW_NAME_ID) || client.isValidObjectVersion(FW_VER_ID)) {
LwM2MClientOtaState fwState = getOrInitFwSate(client);
attributesToFetch.add(getAttributeKey(OtaPackageType.FIRMWARE, OtaPackageKey.TITLE));
attributesToFetch.add(getAttributeKey(OtaPackageType.FIRMWARE, OtaPackageKey.VERSION));
LwM2MClientOtaInfo fwInfo = getOrInitFwInfo(client);
fwInfo.setSupported(client.isValidObjectVersion(FW_NAME_ID) || client.isValidObjectVersion(FW_VER_ID));
if (fwInfo.isSupported()) {
attributesToFetch.add(FIRMWARE_TITLE);
attributesToFetch.add(FIRMWARE_VERSION);
attributesToFetch.add(FIRMWARE_URL);
}
if (!attributesToFetch.isEmpty()) {
var future = attributesService.getSharedAttributes(client, attributesToFetch);
DonAsynchron.withCallback(future, attrs -> {
if (fwInfo.isSupported()) {
Optional<String> newFirmwareTitle = getAttributeValue(attrs, FIRMWARE_TITLE);
Optional<String> newFirmwareVersion = getAttributeValue(attrs, FIRMWARE_VERSION);
Optional<String> newFirmwareUrl = getAttributeValue(attrs, FIRMWARE_URL);
if (newFirmwareTitle.isPresent() && newFirmwareVersion.isPresent()) {
onTargetFirmwareUpdate(client, newFirmwareTitle.get(), newFirmwareVersion.get(), newFirmwareUrl);
}
}
}, throwable -> {
if (fwInfo.isSupported()) {
fwInfo.setTargetFetchFailure(true);
}
}, executor);
}
}
@Override
public void onTargetFirmwareUpdate(LwM2mClient client, String newFirmwareTitle, String newFirmwareVersion, Optional<String> newFirmwareUrl) {
LwM2MClientOtaInfo fwInfo = getOrInitFwInfo(client);
fwInfo.updateTarget(newFirmwareTitle, newFirmwareVersion, newFirmwareUrl);
startFirmwareUpdateIfNeeded(client, fwInfo);
}
@Override
public void onCurrentFirmwareNameUpdate(LwM2mClient client, String name) {
LwM2MClientOtaInfo fwInfo = getOrInitFwInfo(client);
fwInfo.setCurrentName(name);
}
@Override
public void onCurrentFirmwareVersionUpdate(LwM2mClient client, String version) {
LwM2MClientOtaInfo fwInfo = getOrInitFwInfo(client);
fwInfo.setCurrentVersion(version);
}
@Override
public void onCurrentFirmwareStateUpdate(LwM2mClient client, Long state) {
LwM2MClientOtaInfo fwInfo = getOrInitFwInfo(client);
UpdateStateFw newState = UpdateStateFw.fromStateFwByCode(state.intValue());
if (UpdateStateFw.DOWNLOADED.equals(newState)) {
executeFwUpdate(client);
}
fwInfo.setUpdateState(newState);
sendStateUpdateToTelemetry(client, fwInfo, LwM2mTransportUtil.toOtaPackageUpdateStatus(newState));
}
@Override
public void onCurrentFirmwareResultUpdate(LwM2mClient client, Long code) {
LwM2MClientOtaInfo fwInfo = getOrInitFwInfo(client);
UpdateResultFw result = UpdateResultFw.fromUpdateResultFwByCode(code.intValue());
sendStateUpdateToTelemetry(client, fwInfo, LwM2mTransportUtil.toOtaPackageUpdateStatus(result));
if (result.isAgain && fwInfo.getRetryAttempts() <= 2) {
fwInfo.setRetryAttempts(fwInfo.getRetryAttempts() + 1);
startFirmwareUpdateIfNeeded(client, fwInfo);
} else {
fwInfo.setUpdateResult(result);
}
}
if (client.isValidObjectVersion(SW_NAME_ID) || client.isValidObjectVersion(SW_VER_ID)) {
LwM2MClientOtaState swState = getOrInitSwSate(client);
attributesToFetch.add(getAttributeKey(OtaPackageType.SOFTWARE, OtaPackageKey.TITLE));
attributesToFetch.add(getAttributeKey(OtaPackageType.SOFTWARE, OtaPackageKey.VERSION));
@Override
public void onTargetSoftwareUpdate(LwM2mClient client, String newSoftwareTitle, String newSoftwareVersion) {
}
private void startFirmwareUpdateIfNeeded(LwM2mClient client, LwM2MClientOtaInfo fwInfo) {
if (fwInfo.isUpdateRequired()) {
if (StringUtils.isNotEmpty(fwInfo.getTargetUrl())) {
log.info("[{}] Starting update to [{}{}] using URL: {}", client.getEndpoint(), fwInfo.getTargetName(), fwInfo.getTargetVersion(), fwInfo.getTargetUrl());
startFirmwareUpdateUsingUrl(client, fwInfo.getTargetUrl());
} else {
startFirmwareUpdateUsingBinary(client, fwInfo);
}
}
}
private void startFirmwareUpdateUsingUrl(LwM2mClient client, String url) {
String targetIdVer = convertObjectIdToVersionedId(FW_URL_ID, client.getRegistration());
TbLwM2MWriteUpdateRequest request = TbLwM2MWriteUpdateRequest.builder().versionedId(targetIdVer).value(url).timeout(config.getTimeout()).build();
downlinkHandler.sendWriteUpdateRequest(client, request, new TbLwM2MWriteResponseCallback(uplinkHandler, client, targetIdVer));
}
public void startFirmwareUpdateUsingBinary(LwM2mClient client, LwM2MClientOtaInfo fwInfo) {
String versionedId = convertObjectIdToVersionedId(FW_PACKAGE_5_ID, client.getRegistration());
this.transportService.process(client.getSession(), createOtaPackageRequestMsg(client.getSession(), OtaPackageType.FIRMWARE.name()),
new TransportServiceCallback<>() {
@Override
public void onSuccess(TransportProtos.GetOtaPackageResponseMsg response) {
if (TransportProtos.ResponseStatus.SUCCESS.equals(response.getResponseStatus())
&& response.getType().equals(OtaPackageType.FIRMWARE.name())) {
UUID otaPackageId = new UUID(response.getOtaPackageIdMSB(), response.getOtaPackageIdLSB());
var strategy = fwInfo.getStrategy();
switch (strategy) {
case OBJ_5_BINARY:
byte[] firmwareChunk = otaPackageDataCache.get(otaPackageId.toString(), 0, 0);
TbLwM2MWriteReplaceRequest writeRequest = TbLwM2MWriteReplaceRequest.builder().versionedId(versionedId)
.value(firmwareChunk).contentFormat(ContentFormat.OPAQUE)
.timeout(config.getTimeout()).build();
downlinkHandler.sendWriteReplaceRequest(client, writeRequest, new TbLwM2MWriteResponseCallback(uplinkHandler, client, versionedId));
break;
case OBJ_5_TEMP_URL:
startFirmwareUpdateUsingUrl(client, fwInfo.getBaseUrl() + "/" + FIRMWARE_UPDATE_COAP_RECOURSE + "/" + otaPackageId.toString());
break;
default:
//TODO: send log to telemetry
}
} else {
//TODO: send log to telemetry
}
}
var future = attributesService.getSharedAttributes(client, attributesToFetch);
@Override
public void onError(Throwable e) {
log.trace("Failed to process firmwareUpdate ", e);
}
});
}
private LwM2MClientOtaState getOrInitFwSate(LwM2mClient client) {
//TODO: fetch state from the cache.
return fwStates.computeIfAbsent(client.getEndpoint(), endpoint -> new LwM2MClientOtaState());
private TransportProtos.GetOtaPackageRequestMsg createOtaPackageRequestMsg(TransportProtos.SessionInfoProto sessionInfo, String nameFwSW) {
return TransportProtos.GetOtaPackageRequestMsg.newBuilder()
.setDeviceIdMSB(sessionInfo.getDeviceIdMSB())
.setDeviceIdLSB(sessionInfo.getDeviceIdLSB())
.setTenantIdMSB(sessionInfo.getTenantIdMSB())
.setTenantIdLSB(sessionInfo.getTenantIdLSB())
.setType(nameFwSW)
.build();
}
private void executeFwUpdate(LwM2mClient client) {
TbLwM2MExecuteRequest request = TbLwM2MExecuteRequest.builder().versionedId(FW_EXECUTE_ID).timeout(config.getTimeout()).build();
downlinkHandler.sendExecuteRequest(client, request, new TbLwM2MExecuteCallback(uplinkHandler, client, FW_EXECUTE_ID));
}
private Optional<String> getAttributeValue(List<TransportProtos.TsKvProto> attrs, String keyName) {
for (TransportProtos.TsKvProto attr : attrs) {
if (keyName.equals(attr.getKv().getKey())) {
if (attr.getKv().getType().equals(TransportProtos.KeyValueType.STRING_V)) {
return Optional.of(attr.getKv().getStringV());
} else {
return Optional.empty();
}
}
}
return Optional.empty();
}
private LwM2MClientOtaInfo getOrInitFwInfo(LwM2mClient client) {
//TODO: fetch state from the cache or DB.
return fwStates.computeIfAbsent(client.getEndpoint(), endpoint -> {
var profile = clientContext.getProfile(client.getProfileId());
return new LwM2MClientOtaInfo(endpoint, OtaPackageType.FIRMWARE, profile.getClientLwM2mSettings().getFwUpdateStrategy(),
profile.getClientLwM2mSettings().getFwUpdateRecourse());
});
}
private LwM2MClientOtaInfo getOrInitSwInfo(LwM2mClient client) {
//TODO: fetch state from the cache or DB.
return swStates.computeIfAbsent(client.getEndpoint(), endpoint -> {
var profile = clientContext.getProfile(client.getProfileId());
return new LwM2MClientOtaInfo(endpoint, OtaPackageType.SOFTWARE, profile.getClientLwM2mSettings().getSwUpdateStrategy(), profile.getClientLwM2mSettings().getSwUpdateRecourse());
});
}
private LwM2MClientOtaState getOrInitSwSate(LwM2mClient client) {
//TODO: fetch state from the cache.
return swStates.computeIfAbsent(client.getEndpoint(), endpoint -> new LwM2MClientOtaState());
private void sendStateUpdateToTelemetry(LwM2mClient client, LwM2MClientOtaInfo fwInfo, OtaPackageUpdateStatus status) {
List<TransportProtos.KeyValueProto> result = new ArrayList<>();
TransportProtos.KeyValueProto.Builder kvProto = TransportProtos.KeyValueProto.newBuilder().setKey(getAttributeKey(fwInfo.getType(), STATE));
kvProto.setType(TransportProtos.KeyValueType.STRING_V).setStringV(status.name());
result.add(kvProto.build());
helper.sendParametersOnThingsboardTelemetry(result, client.getSession());
}
}

99
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ota/LwM2MClientOtaInfo.java

@ -0,0 +1,99 @@
/**
* Copyright © 2016-2021 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.transport.lwm2m.server.ota;
import lombok.Data;
import org.thingsboard.server.common.data.StringUtils;
import org.thingsboard.server.common.data.ota.OtaPackageType;
import org.thingsboard.server.transport.lwm2m.server.LwM2MFirmwareUpdateStrategy;
import org.thingsboard.server.transport.lwm2m.server.UpdateStateFw;
import org.thingsboard.server.transport.lwm2m.server.UpdateResultFw;
import java.util.Optional;
@Data
public class LwM2MClientOtaInfo {
private final String endpoint;
private final OtaPackageType type;
private String baseUrl;
private boolean supported;
private boolean targetFetchFailure;
private String targetName;
private String targetVersion;
private String targetUrl;
private boolean currentFetchFailure;
private String currentName;
private String currentVersion;
//TODO: use value from device if applicable;
private LwM2MFirmwareUpdateStrategy strategy;
private UpdateStateFw updateState;
private UpdateResultFw updateResult;
private String failedPackageId;
private int retryAttempts;
public LwM2MClientOtaInfo(String endpoint, OtaPackageType type, Integer strategyCode, String baseUrl) {
this.endpoint = endpoint;
this.type = type;
this.strategy = LwM2MFirmwareUpdateStrategy.fromStrategyFwByCode(strategyCode);
this.baseUrl = baseUrl;
}
public void updateTarget(String targetName, String targetVersion, Optional<String> newFirmwareUrl) {
this.targetName = targetName;
this.targetVersion = targetVersion;
this.targetUrl = newFirmwareUrl.orElse(null);
}
public boolean isUpdateRequired() {
if (StringUtils.isEmpty(targetName) ||
StringUtils.isEmpty(targetVersion) ||
(StringUtils.isEmpty(currentName) && StringUtils.isEmpty(currentVersion))) {
return false;
} else {
String targetPackageId = getPackageId(targetName, targetVersion);
String currentPackageId = getPackageId(currentName, currentVersion);
if (StringUtils.isNotEmpty(failedPackageId) && failedPackageId.equals(targetPackageId)) {
return false;
} else {
return !targetPackageId.equals(currentPackageId);
}
}
}
public void setUpdateResult(UpdateResultFw updateResult) {
this.updateResult = updateResult;
switch (updateResult) {
case INITIAL:
break;
case UPDATE_SUCCESSFULLY:
retryAttempts = 0;
break;
default:
failedPackageId = getPackageId(targetName, targetVersion);
break;
}
}
private static String getPackageId(String name, String version) {
return (StringUtils.isNotEmpty(name) ? name : "") + (StringUtils.isNotEmpty(version) ? version : "");
}
}

5
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ota/LwM2MClientOtaState.java

@ -15,5 +15,8 @@
*/
package org.thingsboard.server.transport.lwm2m.server.ota;
public class LwM2MClientOtaState {
public enum LwM2MClientOtaState {
IDLE, IN_PROGRESS, SUCCESS, FAILED
}

13
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ota/LwM2MOtaUpdateService.java

@ -17,8 +17,21 @@ package org.thingsboard.server.transport.lwm2m.server.ota;
import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient;
import java.util.Optional;
public interface LwM2MOtaUpdateService {
void init(LwM2mClient client);
void onTargetFirmwareUpdate(LwM2mClient client, String newFirmwareTitle, String newFirmwareVersion, Optional<String> newFirmwareUrl);
void onTargetSoftwareUpdate(LwM2mClient client, String newSoftwareTitle, String newSoftwareVersion);
void onCurrentFirmwareNameUpdate(LwM2mClient client, String name);
void onCurrentFirmwareVersionUpdate(LwM2mClient client, String version);
void onCurrentFirmwareStateUpdate(LwM2mClient client, Long state);
void onCurrentFirmwareResultUpdate(LwM2mClient client, Long result);
}

2
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/DefaultLwM2MRpcRequestHandler.java

@ -238,7 +238,7 @@ public class DefaultLwM2MRpcRequestHandler implements LwM2MRpcRequestHandler {
IdOrKeyRequest requestParams = JacksonUtil.fromString(rpcRequst.getParams(), IdOrKeyRequest.class);
String targetId;
if (StringUtils.isNotEmpty(requestParams.getKey())) {
targetId = uplinkHandler.getObjectIdByKeyNameFromProfile(client, requestParams.getKey());
targetId = clientContext.getObjectIdByKeyNameFromProfile(client, requestParams.getKey());
} else if (StringUtils.isNotEmpty(requestParams.getId())) {
targetId = requestParams.getId();
} else {

159
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/DefaultLwM2MUplinkMsgHandler.java

@ -68,23 +68,20 @@ import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient;
import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientContext;
import org.thingsboard.server.transport.lwm2m.server.client.LwM2mFwSwUpdate;
import org.thingsboard.server.transport.lwm2m.server.client.ParametersAnalyzeResult;
import org.thingsboard.server.transport.lwm2m.server.client.ResourceValue;
import org.thingsboard.server.transport.lwm2m.server.client.ResultsAddKeyValueProto;
import org.thingsboard.server.transport.lwm2m.server.downlink.DownlinkRequestCallback;
import org.thingsboard.server.transport.lwm2m.server.downlink.LwM2mDownlinkMsgHandler;
import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MLatchCallback;
import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MCancelObserveCallback;
import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MCancelObserveRequest;
import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MDiscoverCallback;
import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MDiscoverRequest;
import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MLatchCallback;
import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MObserveCallback;
import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MObserveRequest;
import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MReadCallback;
import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MReadRequest;
import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MWriteAttributesCallback;
import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MWriteAttributesRequest;
import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MWriteResponseCallback;
import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MWriteReplaceRequest;
import org.thingsboard.server.transport.lwm2m.server.ota.LwM2MOtaUpdateService;
import org.thingsboard.server.transport.lwm2m.server.rpc.LwM2MRpcRequestHandler;
import org.thingsboard.server.transport.lwm2m.server.store.TbLwM2MDtlsSessionStore;
@ -109,8 +106,10 @@ import java.util.stream.Collectors;
import static org.thingsboard.server.common.data.lwm2m.LwM2mConstants.LWM2M_SEPARATOR_PATH;
import static org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus.FAILED;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportServerHelper.getValueFromKvProto;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.FW_3_VER_ID;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.FW_5_ID;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.FW_5_VER_ID;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.FW_NAME_ID;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.FW_RESULT_ID;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.FW_STATE_ID;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LWM2M_ERROR;
@ -119,9 +118,8 @@ import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.L
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LWM2M_WARN;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.SW_ID;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertOtaUpdateValueToString;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertPathFromObjectIdToIdVer;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertObjectIdToVersionedId;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.fromVersionedIdToObjectId;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.validateObjectVerFromKey;
@Slf4j
@ -148,9 +146,11 @@ public class DefaultLwM2MUplinkMsgHandler implements LwM2mUplinkMsgHandler {
public final Map<String, Integer> firmwareUpdateState;
public DefaultLwM2MUplinkMsgHandler(TransportService transportService, LwM2MAttributesService attributesService, LwM2MOtaUpdateService otaService,
public DefaultLwM2MUplinkMsgHandler(TransportService transportService,
LwM2MTransportServerConfig config, LwM2mTransportServerHelper helper,
LwM2mClientContext clientContext,
@Lazy LwM2MOtaUpdateService otaService,
@Lazy LwM2MAttributesService attributesService,
@Lazy LwM2MRpcRequestHandler rpcHandler,
@Lazy LwM2mDownlinkMsgHandler defaultLwM2MDownlinkMsgHandler,
OtaPackageDataCache otaPackageDataCache,
@ -561,21 +561,16 @@ public class DefaultLwM2MUplinkMsgHandler implements LwM2mUplinkMsgHandler {
private void updateResourcesValue(LwM2mClient lwM2MClient, LwM2mResource lwM2mResource, String path) {
Registration registration = lwM2MClient.getRegistration();
if (lwM2MClient.saveResourceValue(path, lwM2mResource, this.config.getModelProvider())) {
/** version != null
* set setClient_fw_info... = value
**/
if (lwM2MClient.getFwUpdate() != null && lwM2MClient.getFwUpdate().isInfoFwSwUpdate()) {
lwM2MClient.getFwUpdate().initReadValue(this, this.defaultLwM2MDownlinkMsgHandler, path);
}
if (lwM2MClient.getSwUpdate() != null && lwM2MClient.getSwUpdate().isInfoFwSwUpdate()) {
lwM2MClient.getSwUpdate().initReadValue(this, this.defaultLwM2MDownlinkMsgHandler, path);
}
if ((convertPathFromObjectIdToIdVer(FW_RESULT_ID, registration).equals(path)) ||
(convertPathFromObjectIdToIdVer(FW_STATE_ID, registration).equals(path))) {
LwM2mFwSwUpdate fwUpdate = lwM2MClient.getFwUpdate(this, clientContext);
log.warn("93) path: [{}] value: [{}]", path, lwM2mResource.getValue());
fwUpdate.updateStateOta(this, defaultLwM2MDownlinkMsgHandler, registration, path, ((Long) lwM2mResource.getValue()).intValue());
if (path.equals(convertObjectIdToVersionedId(FW_NAME_ID, registration))) {
otaService.onCurrentFirmwareNameUpdate(lwM2MClient, (String) lwM2mResource.getValue());
} else if (path.equals(convertObjectIdToVersionedId(FW_3_VER_ID, registration))) {
otaService.onCurrentFirmwareVersionUpdate(lwM2MClient, (String) lwM2mResource.getValue());
} else if (path.equals(convertObjectIdToVersionedId(FW_5_VER_ID, registration))) {
otaService.onCurrentFirmwareVersionUpdate(lwM2MClient, (String) lwM2mResource.getValue());
} else if (path.equals(convertObjectIdToVersionedId(FW_STATE_ID, registration))) {
otaService.onCurrentFirmwareStateUpdate(lwM2MClient, (Long) lwM2mResource.getValue());
} else if (path.equals(convertObjectIdToVersionedId(FW_RESULT_ID, registration))) {
otaService.onCurrentFirmwareResultUpdate(lwM2MClient, (Long) lwM2mResource.getValue());
}
this.updateAttrTelemetry(registration, Collections.singleton(path));
} else {
@ -684,7 +679,7 @@ public class DefaultLwM2MUplinkMsgHandler implements LwM2mUplinkMsgHandler {
String resourceName = names.get(pathIdVer);
if (resourceName != null && !resourceName.isEmpty()) {
try {
LwM2mResource resourceValue = getResourceValueFromLwM2MClient(lwM2MClient, pathIdVer);
LwM2mResource resourceValue = LwM2mTransportUtil.getResourceValueFromLwM2MClient(lwM2MClient, pathIdVer);
if (resourceValue != null) {
ResourceModel.Type currentType = resourceValue.getType();
ResourceModel.Type expectedType = this.helper.getResourceModelTypeEqualsKvProtoValueType(currentType, pathIdVer);
@ -720,38 +715,6 @@ public class DefaultLwM2MUplinkMsgHandler implements LwM2mUplinkMsgHandler {
return null;
}
/**
* @param pathIdVer - path resource
* @return - value of Resource into format KvProto or null
*/
private Object getResourceValueFormatKv(LwM2mClient lwM2MClient, String pathIdVer) {
LwM2mResource resourceValue = this.getResourceValueFromLwM2MClient(lwM2MClient, pathIdVer);
if (resourceValue != null) {
ResourceModel.Type currentType = resourceValue.getType();
ResourceModel.Type expectedType = this.helper.getResourceModelTypeEqualsKvProtoValueType(currentType, pathIdVer);
return this.converter.convertValue(resourceValue.getValue(), currentType, expectedType,
new LwM2mPath(fromVersionedIdToObjectId(pathIdVer)));
} else {
return null;
}
}
/**
* @param lwM2MClient -
* @param path -
* @return - return value of Resource by idPath
*/
private LwM2mResource getResourceValueFromLwM2MClient(LwM2mClient lwM2MClient, String path) {
LwM2mResource lwm2mResourceValue = null;
ResourceValue resourceValue = lwM2MClient.getResources().get(path);
if (resourceValue != null) {
if (new LwM2mPath(fromVersionedIdToObjectId(path)).isResource()) {
lwm2mResourceValue = lwM2MClient.getResources().get(path).getLwM2mResource();
}
}
return lwm2mResourceValue;
}
@Override
public void onWriteResponseOk(LwM2mClient client, String path, WriteRequest request) {
if (request.getNode() instanceof LwM2mResource) {
@ -890,19 +853,6 @@ public class DefaultLwM2MUplinkMsgHandler implements LwM2mUplinkMsgHandler {
}
}
private void pushUpdateToClientIfNeeded(LwM2mClient lwM2MClient, Object valueOld, Object newValue, String versionedId) {
if (newValue != null && (valueOld == null || !newValue.toString().equals(valueOld.toString()))) {
TbLwM2MWriteReplaceRequest request = TbLwM2MWriteReplaceRequest.builder().versionedId(versionedId).value(newValue).timeout(this.config.getTimeout()).build();
defaultLwM2MDownlinkMsgHandler.sendWriteReplaceRequest(lwM2MClient, request, new TbLwM2MWriteResponseCallback(this, lwM2MClient, versionedId));
} else {
log.error("Failed update resource [{}] [{}]", versionedId, newValue);
String logMsg = String.format("%s: Failed update resource versionedId - %s value - %s. Value is not changed or bad",
LOG_LWM2M_ERROR, versionedId, newValue);
this.logToTelemetry(lwM2MClient, logMsg);
log.info("Failed update resource [{}] [{}]", versionedId, newValue);
}
}
/**
* @param updateCredentials - Credentials include config only security Client (without config attr/telemetry...)
* config attr/telemetry... in profile
@ -912,59 +862,6 @@ public class DefaultLwM2MUplinkMsgHandler implements LwM2mUplinkMsgHandler {
log.info("[{}] idList [{}] valueList updateCredentials", updateCredentials.getCredentialsIdList(), updateCredentials.getCredentialsValueList());
}
/**
* Get path to resource from profile equal keyName
*
* @param sessionInfo -
* @param keyName -
* @return -
*/
@Override
public String getObjectIdByKeyNameFromProfile(TransportProtos.SessionInfoProto sessionInfo, String keyName) {
return getObjectIdByKeyNameFromProfile(clientContext.getClientBySessionInfo(sessionInfo), keyName);
}
@Override
public String getObjectIdByKeyNameFromProfile(LwM2mClient lwM2mClient, String keyName) {
Lwm2mDeviceProfileTransportConfiguration profile = clientContext.getProfile(lwM2mClient.getProfileId());
return profile.getObserveAttr().getKeyName().entrySet().stream()
.filter(e -> e.getValue().equals(keyName) && validateResourceInModel(lwM2mClient, e.getKey(), false)).findFirst().orElseThrow(
() -> new IllegalArgumentException(keyName + " is not configured in the device profile!")
).getKey();
}
/**
* #1.1 If two names have equal path => last time attribute
* #2.1 if there is a difference in values between the current resource values and the shared attribute values
* => send to client Request Update of value (new value from shared attribute)
* and LwM2MClient.delayedRequests.add(path)
* #2.1 if there is not a difference in values between the current resource values and the shared attribute values
*
* @param tsKvProtos
*/
public void onAttributesUpdate(LwM2mClient lwM2MClient, List<TransportProtos.TsKvProto> tsKvProtos) {
log.trace("[{}] onAttributesUpdate [{}]", lwM2MClient.getEndpoint(), tsKvProtos);
tsKvProtos.forEach(tsKvProto -> {
String pathIdVer = this.getObjectIdByKeyNameFromProfile(lwM2MClient, tsKvProto.getKv().getKey());
if (pathIdVer != null) {
// #1.1
if (lwM2MClient.getSharedAttributes().containsKey(pathIdVer)) {
if (tsKvProto.getTs() > lwM2MClient.getSharedAttributes().get(pathIdVer).getTs()) {
lwM2MClient.getSharedAttributes().put(pathIdVer, tsKvProto);
}
} else {
lwM2MClient.getSharedAttributes().put(pathIdVer, tsKvProto);
}
}
});
// #2.1
lwM2MClient.getSharedAttributes().forEach((pathIdVer, tsKvProto) -> {
this.pushUpdateToClientIfNeeded(lwM2MClient, this.getResourceValueFormatKv(lwM2MClient, pathIdVer),
getValueFromKvProto(tsKvProto.getKv()), pathIdVer);
});
}
/**
* @param lwM2MClient -
* @return SessionInfoProto -
@ -1017,7 +914,7 @@ public class DefaultLwM2MUplinkMsgHandler implements LwM2mUplinkMsgHandler {
keysToFetch.removeAll(OtaPackageUtil.ALL_FW_ATTRIBUTE_KEYS);
keysToFetch.removeAll(OtaPackageUtil.ALL_SW_ATTRIBUTE_KEYS);
DonAsynchron.withCallback(attributesService.getSharedAttributes(lwM2MClient, keysToFetch),
v -> onAttributesUpdate(lwM2MClient, v),
v -> attributesService.onAttributesUpdate(lwM2MClient, v),
t -> log.error("[{}] Failed to get attributes", lwM2MClient.getEndpoint(), t),
registrationExecutor);
}
@ -1045,7 +942,7 @@ public class DefaultLwM2MUplinkMsgHandler implements LwM2mUplinkMsgHandler {
fwUpdate.setCurrentTitle(response.getTitle());
fwUpdate.setCurrentId(new UUID(response.getOtaPackageIdMSB(), response.getOtaPackageIdLSB()));
// if (rpcRequest == null) {
fwUpdate.sendReadObserveInfo(defaultLwM2MDownlinkMsgHandler);
fwUpdate.sendReadObserveInfo(defaultLwM2MDownlinkMsgHandler);
// } else {
// fwUpdate.writeFwSwWare(handler, defaultLwM2MDownlinkMsgHandler);
// }
@ -1059,7 +956,7 @@ public class DefaultLwM2MUplinkMsgHandler implements LwM2mUplinkMsgHandler {
lwM2MClient.getDeviceName(), response.getResponseStatus().toString());
log.trace(msgError);
// if (rpcRequest != null) {
//TODO: refactor
//TODO: refactor
// sendErrorRpcResponse(rpcRequest, msgError, sessionInfo);
// }
}
@ -1091,7 +988,7 @@ public class DefaultLwM2MUplinkMsgHandler implements LwM2mUplinkMsgHandler {
lwM2MClient.getSwUpdate().setCurrentId(new OtaPackageId(new UUID(response.getOtaPackageIdMSB(), response.getOtaPackageIdLSB())).getId());
lwM2MClient.getSwUpdate().sendReadObserveInfo(defaultLwM2MDownlinkMsgHandler);
// if (rpcRequest == null) {
lwM2MClient.getSwUpdate().sendReadObserveInfo(defaultLwM2MDownlinkMsgHandler);
lwM2MClient.getSwUpdate().sendReadObserveInfo(defaultLwM2MDownlinkMsgHandler);
// } else {
// lwM2MClient.getSwUpdate().writeFwSwWare(handler, defaultLwM2MDownlinkMsgHandler);
// }
@ -1124,16 +1021,6 @@ public class DefaultLwM2MUplinkMsgHandler implements LwM2mUplinkMsgHandler {
return profile.getObserveAttr().getKeyName();
}
private boolean validateResourceInModel(LwM2mClient lwM2mClient, String pathIdVer, boolean isWritableNotOptional) {
ResourceModel resourceModel = lwM2mClient.getResourceModel(pathIdVer, this.config
.getModelProvider());
Integer objectId = new LwM2mPath(fromVersionedIdToObjectId(pathIdVer)).getObjectId();
String objectVer = validateObjectVerFromKey(pathIdVer);
return resourceModel != null && (isWritableNotOptional ?
objectId != null && objectVer != null && objectVer.equals(lwM2mClient.getRegistration().getSupportedVersion(objectId)) && resourceModel.operations.isWritable() :
objectId != null && objectVer != null && objectVer.equals(lwM2mClient.getRegistration().getSupportedVersion(objectId)));
}
public LwM2MTransportServerConfig getConfig() {
return this.config;
}

4
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/LwM2mUplinkMsgHandler.java

@ -60,9 +60,5 @@ public interface LwM2mUplinkMsgHandler {
void onToTransportUpdateCredentials(TransportProtos.ToTransportUpdateCredentialsProto updateCredentials);
String getObjectIdByKeyNameFromProfile(TransportProtos.SessionInfoProto sessionInfo, String name);
String getObjectIdByKeyNameFromProfile(LwM2mClient lwM2mClient, String keyName);
LwM2MTransportServerConfig getConfig();
}

Loading…
Cancel
Save