Browse Source

Implementation of software management

pull/4840/head
Andrii Shvaika 5 years ago
parent
commit
eb9b0f8433
  1. 1
      application/src/main/resources/logback.xml
  2. 2
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MAuthorizer.java
  3. 18
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportCoapResource.java
  4. 8
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportUtil.java
  5. 7
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/attributes/DefaultLwM2MAttributesService.java
  6. 313
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ota/DefaultLwM2MOtaUpdateService.java
  7. 72
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ota/LwM2MClientOtaInfo.java
  8. 16
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ota/LwM2MOtaUpdateService.java
  9. 56
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ota/firmware/LwM2MClientFwOtaInfo.java
  10. 57
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ota/software/LwM2MClientSwOtaInfo.java
  11. 3
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ota/software/SoftwareUpdateResult.java
  12. 11
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/DefaultLwM2MRpcRequestHandler.java
  13. 18
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbDummyLwM2MClientOtaInfoStore.java
  14. 10
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2MClientOtaInfoStore.java
  15. 34
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mRedisClientOtaInfoStore.java
  16. 40
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/DefaultLwM2MUplinkMsgHandler.java

1
application/src/main/resources/logback.xml

@ -26,7 +26,6 @@
</appender>
<logger name="org.thingsboard.server" level="INFO" />
<logger name="org.thingsboard.server.transport.snmp" level="DEBUG" />
<!-- <logger name="org.thingsboard.server.service.queue" level="TRACE" />-->
<!-- <logger name="org.thingsboard.server.service.transport" level="TRACE" />-->

2
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MAuthorizer.java

@ -62,7 +62,7 @@ public class TbLwM2MAuthorizer implements Authorizer {
try {
expectedSecurityInfo = securityStore.getByEndpoint(registration.getEndpoint());
} catch (LwM2MAuthException e) {
log.warn("Registration failed: FORBIDDEN, endpointId: [{}]", registration.getEndpoint());
log.info("Registration failed: FORBIDDEN, endpointId: [{}]", registration.getEndpoint());
return null;
}
}

18
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportCoapResource.java

@ -26,6 +26,7 @@ import org.eclipse.californium.core.server.resources.Resource;
import org.eclipse.californium.core.server.resources.ResourceObserver;
import org.thingsboard.server.cache.ota.OtaPackageDataCache;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
@ -69,17 +70,18 @@ public class LwM2mTransportCoapResource extends AbstractLwM2mTransportResource {
@Override
protected void processHandleGet(CoapExchange exchange) {
log.warn("90) processHandleGet [{}]", exchange);
if (exchange.getRequestOptions().getUriPath().size() >= 2 &&
(FIRMWARE_UPDATE_COAP_RESOURCE.equals(exchange.getRequestOptions().getUriPath().get(exchange.getRequestOptions().getUriPath().size() - 2)) ||
SOFTWARE_UPDATE_COAP_RESOURCE.equals(exchange.getRequestOptions().getUriPath().get(exchange.getRequestOptions().getUriPath().size() - 2)))) {
log.debug("processHandleGet [{}]", exchange);
List<String> uriPath = exchange.getRequestOptions().getUriPath();
if (uriPath.size() >= 2 &&
(FIRMWARE_UPDATE_COAP_RESOURCE.equals(uriPath.get(uriPath.size() - 2)) ||
SOFTWARE_UPDATE_COAP_RESOURCE.equals(uriPath.get(uriPath.size() - 2)))) {
this.sendOtaData(exchange);
}
}
@Override
protected void processHandlePost(CoapExchange exchange) {
log.warn("2) processHandleGet [{}]", exchange);
log.debug("processHandlePost [{}]", exchange);
}
/**
@ -136,16 +138,16 @@ public class LwM2mTransportCoapResource extends AbstractLwM2mTransportResource {
UUID currentId = UUID.fromString(idStr);
Response response = new Response(CoAP.ResponseCode.CONTENT);
byte[] fwData = this.getOtaData(currentId);
log.warn("91) read softWare data (length): [{}]", fwData.length);
log.debug("Read softWare data (length): [{}]", fwData.length);
if (fwData != null && fwData.length > 0) {
response.setPayload(fwData);
if (exchange.getRequestOptions().getBlock2() != null) {
int chunkSize = exchange.getRequestOptions().getBlock2().getSzx();
boolean lastFlag = fwData.length <= chunkSize;
response.getOptions().setBlock2(chunkSize, lastFlag, 0);
log.warn("92) with blokc2 Send currentId: [{}], length: [{}], chunkSize [{}], moreFlag [{}]", currentId.toString(), fwData.length, chunkSize, lastFlag);
log.trace("With block2 Send currentId: [{}], length: [{}], chunkSize [{}], moreFlag [{}]", currentId.toString(), fwData.length, chunkSize, lastFlag);
} else {
log.warn("92) with block1 Send currentId: [{}], length: [{}], ", currentId.toString(), fwData.length);
log.trace("With block1 Send currentId: [{}], length: [{}], ", currentId.toString(), fwData.length);
}
exchange.respond(response);
}

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

@ -69,7 +69,7 @@ import static org.thingsboard.server.common.data.lwm2m.LwM2mConstants.LWM2M_SEPA
import static org.thingsboard.server.transport.lwm2m.server.ota.DefaultLwM2MOtaUpdateService.FW_RESULT_ID;
import static org.thingsboard.server.transport.lwm2m.server.ota.DefaultLwM2MOtaUpdateService.FW_STATE_ID;
import static org.thingsboard.server.transport.lwm2m.server.ota.DefaultLwM2MOtaUpdateService.SW_RESULT_ID;
import static org.thingsboard.server.transport.lwm2m.server.ota.DefaultLwM2MOtaUpdateService.SW_UPDATE_STATE_ID;
import static org.thingsboard.server.transport.lwm2m.server.ota.DefaultLwM2MOtaUpdateService.SW_STATE_ID;
@Slf4j
public class LwM2mTransportUtil {
@ -143,7 +143,7 @@ public class LwM2mTransportUtil {
lwM2mOtaConvert.setCurrentType(STRING);
lwM2mOtaConvert.setValue(FirmwareUpdateResult.fromUpdateResultFwByCode(((Long) value).intValue()).getType());
return lwM2mOtaConvert;
} else if (SW_UPDATE_STATE_ID.equals(path)) {
} else if (SW_STATE_ID.equals(path)) {
lwM2mOtaConvert.setCurrentType(STRING);
lwM2mOtaConvert.setValue(SoftwareUpdateState.fromUpdateStateSwByCode(((Long) value).intValue()).type);
return lwM2mOtaConvert;
@ -163,7 +163,7 @@ public class LwM2mTransportUtil {
if (transportConfiguration.getType().equals(DeviceTransportType.LWM2M)) {
return (Lwm2mDeviceProfileTransportConfiguration) transportConfiguration;
} else {
log.warn("[{}] Received profile with invalid transport configuration: {}", deviceProfile.getId(), deviceProfile.getProfileData().getTransportConfiguration());
log.info("[{}] Received profile with invalid transport configuration: {}", deviceProfile.getId(), deviceProfile.getProfileData().getTransportConfiguration());
throw new IllegalArgumentException("Received profile with invalid transport configuration: " + transportConfiguration.getType());
}
}
@ -185,7 +185,7 @@ public class LwM2mTransportUtil {
return pathIdVer;
}
} catch (Exception e) {
log.warn("Issue converting path with version [{}] to path without version: ", pathIdVer, e);
log.debug("Issue converting path with version [{}] to path without version: ", pathIdVer, e);
throw new RuntimeException(e);
}
}

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

@ -123,6 +123,7 @@ public class DefaultLwM2MAttributesService implements LwM2MAttributesService {
String newFirmwareUrl = null;
String newSoftwareTitle = null;
String newSoftwareVersion = null;
String newSoftwareUrl = null;
List<TransportProtos.TsKvProto> otherAttributes = new ArrayList<>();
for (TransportProtos.TsKvProto tsKvProto : msg.getSharedUpdatedList()) {
String attrName = tsKvProto.getKv().getKey();
@ -136,7 +137,9 @@ public class DefaultLwM2MAttributesService implements LwM2MAttributesService {
newSoftwareTitle = getStrValue(tsKvProto);
} else if (DefaultLwM2MOtaUpdateService.SOFTWARE_VERSION.equals(attrName)) {
newSoftwareVersion = getStrValue(tsKvProto);
} else {
} else if (DefaultLwM2MOtaUpdateService.SOFTWARE_URL.equals(attrName)) {
newSoftwareUrl = getStrValue(tsKvProto);
}else {
otherAttributes.add(tsKvProto);
}
}
@ -144,7 +147,7 @@ public class DefaultLwM2MAttributesService implements LwM2MAttributesService {
otaUpdateService.onTargetFirmwareUpdate(lwM2MClient, newFirmwareTitle, newFirmwareVersion, Optional.ofNullable(newFirmwareUrl));
}
if (newSoftwareTitle != null || newSoftwareVersion != null) {
otaUpdateService.onTargetSoftwareUpdate(lwM2MClient, newSoftwareTitle, newSoftwareVersion);
otaUpdateService.onTargetSoftwareUpdate(lwM2MClient, newSoftwareTitle, newSoftwareVersion, Optional.ofNullable(newSoftwareUrl));
}
if (!otherAttributes.isEmpty()) {
onAttributesUpdate(lwM2MClient, otherAttributes);

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

@ -45,10 +45,12 @@ import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MExecuteRequ
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.log.LwM2MTelemetryLogService;
import org.thingsboard.server.transport.lwm2m.server.ota.firmware.LwM2MClientFwOtaInfo;
import org.thingsboard.server.transport.lwm2m.server.ota.firmware.LwM2MFirmwareUpdateStrategy;
import org.thingsboard.server.transport.lwm2m.server.ota.firmware.FirmwareDeliveryMethod;
import org.thingsboard.server.transport.lwm2m.server.ota.firmware.FirmwareUpdateResult;
import org.thingsboard.server.transport.lwm2m.server.ota.firmware.FirmwareUpdateState;
import org.thingsboard.server.transport.lwm2m.server.ota.software.LwM2MClientSwOtaInfo;
import org.thingsboard.server.transport.lwm2m.server.ota.software.LwM2MSoftwareUpdateStrategy;
import org.thingsboard.server.transport.lwm2m.server.ota.software.SoftwareUpdateResult;
import org.thingsboard.server.transport.lwm2m.server.ota.software.SoftwareUpdateState;
@ -91,12 +93,13 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl
public static final String FIRMWARE_UPDATE_COAP_RESOURCE = "tbfw";
public static final String SOFTWARE_UPDATE_COAP_RESOURCE = "tbsw";
private static final String FW_PACKAGE_5_ID = "/5/0/0";
private static final String FW_PACKAGE_19_ID = "/19/0/0";
private static final String FW_URL_ID = "/5/0/1";
private static final String FW_EXECUTE_ID = "/5/0/2";
public static final String FW_STATE_ID = "/5/0/3";
public static final String FW_RESULT_ID = "/5/0/5";
public static final String FW_NAME_ID = "/5/0/6";
public static final String FW_5_VER_ID = "/5/0/7";
public static final String FW_VER_ID = "/5/0/7";
/**
* Quectel@Hi15RM1-HLB_V1.0@BC68JAR01A10,V150R100C20B300SP7,V150R100C20B300SP7@8
* Revision:BC68JAR01A10
@ -104,17 +107,19 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl
public static final String FW_3_VER_ID = "/3/0/3";
public static final String FW_DELIVERY_METHOD = "/5/0/9";
private static final String SW_NAME_ID = "/9/0/0";
private static final String SW_VER_ID = "/9/0/1";
public static final String SW_3_VER_ID = "/3/0/19";
public static final String SW_NAME_ID = "/9/0/0";
public static final String SW_VER_ID = "/9/0/1";
public static final String SW_PACKAGE_ID = "/9/0/2";
public static final String SW_PACKAGE_URI_ID = "/9/0/3";
public static final String SW_INSTALL_ID = "/9/0/4";
public static final String SW_UPDATE_STATE_ID = "/9/0/7";
public static final String SW_STATE_ID = "/9/0/7";
public static final String SW_RESULT_ID = "/9/0/9";
public static final String SW_UN_INSTALL_ID = "/9/0/6";
private final Map<String, LwM2MClientOtaInfo> fwStates = new ConcurrentHashMap<>();
private final Map<String, LwM2MClientOtaInfo> swStates = new ConcurrentHashMap<>();
private final Map<String, LwM2MClientFwOtaInfo> fwStates = new ConcurrentHashMap<>();
private final Map<String, LwM2MClientSwOtaInfo> swStates = new ConcurrentHashMap<>();
private final TransportService transportService;
private final LwM2mClientContext clientContext;
@ -155,27 +160,41 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl
//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<>();
LwM2MClientOtaInfo fwInfo = getOrInitFwInfo(client);
LwM2MClientFwOtaInfo fwInfo = getOrInitFwInfo(client);
if (fwInfo.isSupported()) {
attributesToFetch.add(FIRMWARE_TITLE);
attributesToFetch.add(FIRMWARE_VERSION);
attributesToFetch.add(FIRMWARE_URL);
}
LwM2MClientSwOtaInfo swInfo = getOrInitSwInfo(client);
if (swInfo.isSupported()) {
attributesToFetch.add(SOFTWARE_TITLE);
attributesToFetch.add(SOFTWARE_VERSION);
attributesToFetch.add(SOFTWARE_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);
Optional<String> newFwTitle = getAttributeValue(attrs, FIRMWARE_TITLE);
Optional<String> newFwVersion = getAttributeValue(attrs, FIRMWARE_VERSION);
Optional<String> newFwUrl = getAttributeValue(attrs, FIRMWARE_URL);
if (newFwTitle.isPresent() && newFwVersion.isPresent()) {
onTargetFirmwareUpdate(client, newFwTitle.get(), newFwVersion.get(), newFwUrl);
}
}
if (swInfo.isSupported()) {
Optional<String> newSwTitle = getAttributeValue(attrs, SOFTWARE_TITLE);
Optional<String> newSwVersion = getAttributeValue(attrs, SOFTWARE_VERSION);
Optional<String> newSwUrl = getAttributeValue(attrs, SOFTWARE_URL);
if (newSwTitle.isPresent() && newSwVersion.isPresent()) {
onTargetSoftwareUpdate(client, newSwTitle.get(), newSwVersion.get(), newSwUrl);
}
}
}, throwable -> {
if (fwInfo.isSupported()) {
fwInfo.setTargetFetchFailure(true);
update(fwInfo);
}
}, executor);
@ -184,7 +203,7 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl
@Override
public void forceFirmwareUpdate(LwM2mClient client) {
LwM2MClientOtaInfo fwInfo = getOrInitFwInfo(client);
LwM2MClientFwOtaInfo fwInfo = getOrInitFwInfo(client);
fwInfo.setRetryAttempts(0);
fwInfo.setFailedPackageId(null);
startFirmwareUpdateIfNeeded(client, fwInfo);
@ -192,7 +211,7 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl
@Override
public void onTargetFirmwareUpdate(LwM2mClient client, String newFirmwareTitle, String newFirmwareVersion, Optional<String> newFirmwareUrl) {
LwM2MClientOtaInfo fwInfo = getOrInitFwInfo(client);
LwM2MClientFwOtaInfo fwInfo = getOrInitFwInfo(client);
fwInfo.updateTarget(newFirmwareTitle, newFirmwareVersion, newFirmwareUrl);
update(fwInfo);
startFirmwareUpdateIfNeeded(client, fwInfo);
@ -201,15 +220,20 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl
@Override
public void onCurrentFirmwareNameUpdate(LwM2mClient client, String name) {
log.debug("[{}] Current fw name: {}", client.getEndpoint(), name);
LwM2MClientOtaInfo fwInfo = getOrInitFwInfo(client);
fwInfo.setCurrentName(name);
getOrInitFwInfo(client).setCurrentName(name);
}
@Override
public void onCurrentSoftwareNameUpdate(LwM2mClient client, String name) {
log.debug("[{}] Current sw name: {}", client.getEndpoint(), name);
getOrInitSwInfo(client).setCurrentName(name);
}
@Override
public void onFirmwareStrategyUpdate(LwM2mClient client, OtherConfiguration configuration) {
log.debug("[{}] Current fw strategy: {}", client.getEndpoint(), configuration.getFwUpdateStrategy());
LwM2MClientOtaInfo fwInfo = getOrInitFwInfo(client);
fwInfo.setFwStrategy(LwM2MFirmwareUpdateStrategy.fromStrategyFwByCode(configuration.getFwUpdateStrategy()));
LwM2MClientFwOtaInfo fwInfo = getOrInitFwInfo(client);
fwInfo.setStrategy(LwM2MFirmwareUpdateStrategy.fromStrategyFwByCode(configuration.getFwUpdateStrategy()));
fwInfo.setBaseUrl(configuration.getFwUpdateResource());
startFirmwareUpdateIfNeeded(client, fwInfo);
}
@ -217,30 +241,30 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl
@Override
public void onCurrentSoftwareStrategyUpdate(LwM2mClient client, OtherConfiguration configuration) {
log.debug("[{}] Current sw strategy: {}", client.getEndpoint(), configuration.getSwUpdateStrategy());
LwM2MClientOtaInfo swInfo = getOrInitSwInfo(client);
swInfo.setSwStrategy(LwM2MSoftwareUpdateStrategy.fromStrategySwByCode(configuration.getSwUpdateStrategy()));
LwM2MClientSwOtaInfo swInfo = getOrInitSwInfo(client);
swInfo.setStrategy(LwM2MSoftwareUpdateStrategy.fromStrategySwByCode(configuration.getSwUpdateStrategy()));
swInfo.setBaseUrl(configuration.getSwUpdateResource());
startSoftwareUpdateIfNeeded(client, swInfo);
}
@Override
public void onCurrentFirmwareVersion3Update(LwM2mClient client, String version) {
log.debug("[{}] Current fw version: {}", client.getEndpoint(), version);
LwM2MClientOtaInfo fwInfo = getOrInitFwInfo(client);
log.debug("[{}] Current fw version(3): {}", client.getEndpoint(), version);
LwM2MClientFwOtaInfo fwInfo = getOrInitFwInfo(client);
fwInfo.setCurrentVersion3(version);
}
@Override
public void onCurrentFirmwareVersion5Update(LwM2mClient client, String version) {
log.debug("[{}] Current fw version: {}", client.getEndpoint(), version);
LwM2MClientOtaInfo fwInfo = getOrInitFwInfo(client);
fwInfo.setCurrentVersion5(version);
public void onCurrentFirmwareVersionUpdate(LwM2mClient client, String version) {
log.debug("[{}] Current fw version(5): {}", client.getEndpoint(), version);
LwM2MClientFwOtaInfo fwInfo = getOrInitFwInfo(client);
fwInfo.setCurrentVersion(version);
}
@Override
public void onCurrentFirmwareStateUpdate(LwM2mClient client, Long stateCode) {
log.debug("[{}] Current fw state: {}", client.getEndpoint(), stateCode);
LwM2MClientOtaInfo fwInfo = getOrInitFwInfo(client);
LwM2MClientFwOtaInfo fwInfo = getOrInitFwInfo(client);
FirmwareUpdateState state = FirmwareUpdateState.fromStateFwByCode(stateCode.intValue());
if (FirmwareUpdateState.DOWNLOADED.equals(state)) {
executeFwUpdate(client);
@ -255,7 +279,7 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl
@Override
public void onCurrentFirmwareResultUpdate(LwM2mClient client, Long code) {
log.debug("[{}] Current fw result: {}", client.getEndpoint(), code);
LwM2MClientOtaInfo fwInfo = getOrInitFwInfo(client);
LwM2MClientFwOtaInfo fwInfo = getOrInitFwInfo(client);
FirmwareUpdateResult result = FirmwareUpdateResult.fromUpdateResultFwByCode(code.intValue());
Optional<OtaPackageUpdateStatus> status = toOtaPackageUpdateStatus(result);
status.ifPresent(otaStatus -> sendStateUpdateToTelemetry(client, fwInfo,
@ -272,16 +296,66 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl
@Override
public void onCurrentFirmwareDeliveryMethodUpdate(LwM2mClient client, Long value) {
log.debug("[{}] Current fw delivery method: {}", client.getEndpoint(), value);
LwM2MClientOtaInfo fwInfo = getOrInitFwInfo(client);
LwM2MClientFwOtaInfo fwInfo = getOrInitFwInfo(client);
fwInfo.setDeliveryMethod(value.intValue());
}
@Override
public void onTargetSoftwareUpdate(LwM2mClient client, String newSoftwareTitle, String newSoftwareVersion) {
public void onCurrentSoftwareVersion3Update(LwM2mClient client, String version) {
log.debug("[{}] Current sw version(3): {}", client.getEndpoint(), version);
getOrInitSwInfo(client).setCurrentVersion3(version);
}
@Override
public void onCurrentSoftwareVersionUpdate(LwM2mClient client, String version) {
log.debug("[{}] Current sw version(9): {}", client.getEndpoint(), version);
getOrInitSwInfo(client).setCurrentVersion(version);
}
@Override
public void onCurrentSoftwareStateUpdate(LwM2mClient client, Long stateCode) {
log.debug("[{}] Current sw state: {}", client.getEndpoint(), stateCode);
LwM2MClientSwOtaInfo swInfo = getOrInitSwInfo(client);
SoftwareUpdateState state = SoftwareUpdateState.fromUpdateStateSwByCode(stateCode.intValue());
if (SoftwareUpdateState.INITIAL.equals(state)) {
startSoftwareUpdateIfNeeded(client, swInfo);
} else if (SoftwareUpdateState.DELIVERED.equals(state)) {
executeSwInstall(client);
}
swInfo.setUpdateState(state);
Optional<OtaPackageUpdateStatus> status = toOtaPackageUpdateStatus(state);
status.ifPresent(otaStatus -> sendStateUpdateToTelemetry(client, swInfo,
otaStatus, "Firmware Update State: " + state.name()));
update(swInfo);
}
private void startFirmwareUpdateIfNeeded(LwM2mClient client, LwM2MClientOtaInfo fwInfo) {
@Override
public void onCurrentSoftwareResultUpdate(LwM2mClient client, Long code) {
log.debug("[{}] Current sw result: {}", client.getEndpoint(), code);
LwM2MClientSwOtaInfo swInfo = getOrInitSwInfo(client);
SoftwareUpdateResult result = SoftwareUpdateResult.fromUpdateResultSwByCode(code.intValue());
Optional<OtaPackageUpdateStatus> status = toOtaPackageUpdateStatus(result);
status.ifPresent(otaStatus -> sendStateUpdateToTelemetry(client, swInfo,
otaStatus, "Firmware Update Result: " + result.name()));
if (result.isAgain() && swInfo.getRetryAttempts() <= 2) {
swInfo.setRetryAttempts(swInfo.getRetryAttempts() + 1);
startSoftwareUpdateIfNeeded(client, swInfo);
} else {
swInfo.update(result);
}
update(swInfo);
}
@Override
public void onTargetSoftwareUpdate(LwM2mClient client, String newSoftwareTitle, String newSoftwareVersion, Optional<String> newFirmwareUrl) {
LwM2MClientSwOtaInfo fwInfo = getOrInitSwInfo(client);
fwInfo.updateTarget(newSoftwareTitle, newSoftwareVersion, newFirmwareUrl);
update(fwInfo);
startSoftwareUpdateIfNeeded(client, fwInfo);
}
private void startFirmwareUpdateIfNeeded(LwM2mClient client, LwM2MClientFwOtaInfo fwInfo) {
try {
if (!fwInfo.isSupported()) {
log.debug("[{}] Fw update is not supported: {}", client.getEndpoint(), fwInfo);
@ -289,35 +363,70 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl
} else if (fwInfo.isUpdateRequired()) {
if (StringUtils.isNotEmpty(fwInfo.getTargetUrl())) {
log.debug("[{}] Starting update to [{}{}] using URL: {}", client.getEndpoint(), fwInfo.getTargetName(), fwInfo.getTargetVersion(), fwInfo.getTargetUrl());
startFirmwareUpdateUsingUrl(client, fwInfo.getTargetUrl());
startUpdateUsingUrl(client, FW_URL_ID, fwInfo.getTargetUrl());
} else {
log.debug("[{}] Starting update to [{}{}] using binary", client.getEndpoint(), fwInfo.getTargetName(), fwInfo.getTargetVersion());
startFirmwareUpdateUsingBinary(client, fwInfo);
startUpdateUsingBinary(client, fwInfo);
}
}
} catch (Exception e) {
log.warn("[{}] failed to update client: {}", client.getEndpoint(), fwInfo, e);
log.info("[{}] failed to update client: {}", client.getEndpoint(), fwInfo, e);
sendStateUpdateToTelemetry(client, fwInfo, OtaPackageUpdateStatus.FAILED, "Internal server error: " + e.getMessage());
}
}
private void startSoftwareUpdateIfNeeded(LwM2mClient client, LwM2MClientOtaInfo swInfo) {
private void startSoftwareUpdateIfNeeded(LwM2mClient client, LwM2MClientSwOtaInfo swInfo) {
try {
if (!swInfo.isSupported()) {
log.debug("[{}] Sw update is not supported: {}", client.getEndpoint(), swInfo);
sendStateUpdateToTelemetry(client, swInfo, OtaPackageUpdateStatus.FAILED, "Client does not support software update or profile misconfiguration!");
} else if (swInfo.isUpdateRequired()) {
if (SoftwareUpdateState.INSTALLED.equals(swInfo.getUpdateState())) {
log.debug("[{}] Attempt to restore the update state: {}", client.getEndpoint(), swInfo.getUpdateState());
executeSwUninstallForUpdate(client);
} else {
if (StringUtils.isNotEmpty(swInfo.getTargetUrl())) {
log.debug("[{}] Starting update to [{}{}] using URL: {}", client.getEndpoint(), swInfo.getTargetName(), swInfo.getTargetVersion(), swInfo.getTargetUrl());
startUpdateUsingUrl(client, SW_PACKAGE_URI_ID, swInfo.getTargetUrl());
} else {
log.debug("[{}] Starting update to [{}{}] using binary", client.getEndpoint(), swInfo.getTargetName(), swInfo.getTargetVersion());
startUpdateUsingBinary(client, swInfo);
}
}
}
} catch (Exception e) {
log.info("[{}] failed to update client: {}", client.getEndpoint(), swInfo, e);
sendStateUpdateToTelemetry(client, swInfo, OtaPackageUpdateStatus.FAILED, "Internal server error: " + e.getMessage());
}
}
public void startUpdateUsingBinary(LwM2mClient client, LwM2MClientSwOtaInfo swInfo) {
this.transportService.process(client.getSession(), createOtaPackageRequestMsg(client.getSession(), swInfo.getType().name()),
new TransportServiceCallback<>() {
@Override
public void onSuccess(TransportProtos.GetOtaPackageResponseMsg response) {
executor.submit(() -> doUpdateSoftwareUsingBinary(response, swInfo, client));
}
@Override
public void onError(Throwable e) {
logService.log(client, "Failed to process software update: " + e.getMessage());
}
});
}
private void startFirmwareUpdateUsingUrl(LwM2mClient client, String url) {
String targetIdVer = convertObjectIdToVersionedId(FW_URL_ID, client.getRegistration());
private void startUpdateUsingUrl(LwM2mClient client, String id, String url) {
String targetIdVer = convertObjectIdToVersionedId(id, client.getRegistration());
TbLwM2MWriteReplaceRequest request = TbLwM2MWriteReplaceRequest.builder().versionedId(targetIdVer).value(url).timeout(config.getTimeout()).build();
downlinkHandler.sendWriteReplaceRequest(client, request, new TbLwM2MWriteResponseCallback(uplinkHandler, logService, 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()),
public void startUpdateUsingBinary(LwM2mClient client, LwM2MClientFwOtaInfo fwInfo) {
this.transportService.process(client.getSession(), createOtaPackageRequestMsg(client.getSession(), fwInfo.getType().name()),
new TransportServiceCallback<>() {
@Override
public void onSuccess(TransportProtos.GetOtaPackageResponseMsg response) {
executor.submit(() -> doUpdateFirmwareUsingBinary(response, fwInfo, versionedId, client));
executor.submit(() -> doUpdateFirmwareUsingBinary(response, fwInfo, client));
}
@Override
@ -327,34 +436,60 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl
});
}
private void doUpdateFirmwareUsingBinary(TransportProtos.GetOtaPackageResponseMsg response, LwM2MClientOtaInfo fwInfo, String versionedId, LwM2mClient client) {
private void doUpdateFirmwareUsingBinary(TransportProtos.GetOtaPackageResponseMsg response, LwM2MClientFwOtaInfo info, LwM2mClient client) {
if (TransportProtos.ResponseStatus.SUCCESS.equals(response.getResponseStatus())) {
UUID otaPackageId = new UUID(response.getOtaPackageIdMSB(), response.getOtaPackageIdLSB());
LwM2MFirmwareUpdateStrategy strategy;
if (fwInfo.getDeliveryMethod() == null || fwInfo.getDeliveryMethod() == FirmwareDeliveryMethod.BOTH.code) {
strategy = fwInfo.getFwStrategy();
if (info.getDeliveryMethod() == null || info.getDeliveryMethod() == FirmwareDeliveryMethod.BOTH.code) {
strategy = info.getStrategy();
} else {
strategy = fwInfo.getDeliveryMethod() == FirmwareDeliveryMethod.PULL.code ? LwM2MFirmwareUpdateStrategy.OBJ_5_TEMP_URL : LwM2MFirmwareUpdateStrategy.OBJ_5_BINARY;
strategy = info.getDeliveryMethod() == FirmwareDeliveryMethod.PULL.code ? LwM2MFirmwareUpdateStrategy.OBJ_5_TEMP_URL : LwM2MFirmwareUpdateStrategy.OBJ_5_BINARY;
}
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, logService, client, versionedId));
startUpdateUsingBinary(client, convertObjectIdToVersionedId(FW_PACKAGE_5_ID, client.getRegistration()), otaPackageId);
break;
case OBJ_19_BINARY:
startUpdateUsingBinary(client, convertObjectIdToVersionedId(FW_PACKAGE_19_ID, client.getRegistration()), otaPackageId);
break;
case OBJ_5_TEMP_URL:
startFirmwareUpdateUsingUrl(client, fwInfo.getBaseUrl() + "/" + FIRMWARE_UPDATE_COAP_RESOURCE + "/" + otaPackageId.toString());
startUpdateUsingUrl(client, FW_URL_ID, info.getBaseUrl() + "/" + FIRMWARE_UPDATE_COAP_RESOURCE + "/" + otaPackageId.toString());
break;
default:
sendStateUpdateToTelemetry(client, info, OtaPackageUpdateStatus.FAILED, "Unsupported strategy: " + strategy.name());
}
} else {
sendStateUpdateToTelemetry(client, info, OtaPackageUpdateStatus.FAILED, "Failed to fetch OTA package: " + response.getResponseStatus());
}
}
private void doUpdateSoftwareUsingBinary(TransportProtos.GetOtaPackageResponseMsg response, LwM2MClientSwOtaInfo info, LwM2mClient client) {
if (TransportProtos.ResponseStatus.SUCCESS.equals(response.getResponseStatus())) {
UUID otaPackageId = new UUID(response.getOtaPackageIdMSB(), response.getOtaPackageIdLSB());
LwM2MSoftwareUpdateStrategy strategy = info.getStrategy();
switch (strategy) {
case BINARY:
startUpdateUsingBinary(client, convertObjectIdToVersionedId(SW_PACKAGE_ID, client.getRegistration()), otaPackageId);
break;
case TEMP_URL:
startUpdateUsingUrl(client, SW_PACKAGE_URI_ID, info.getBaseUrl() + "/" + FIRMWARE_UPDATE_COAP_RESOURCE + "/" + otaPackageId.toString());
break;
default:
sendStateUpdateToTelemetry(client, fwInfo, OtaPackageUpdateStatus.FAILED, "Unsupported strategy: " + strategy.name());
sendStateUpdateToTelemetry(client, info, OtaPackageUpdateStatus.FAILED, "Unsupported strategy: " + strategy.name());
}
} else {
sendStateUpdateToTelemetry(client, fwInfo, OtaPackageUpdateStatus.FAILED, "Failed to fetch OTA package: " + response.getResponseStatus());
sendStateUpdateToTelemetry(client, info, OtaPackageUpdateStatus.FAILED, "Failed to fetch OTA package: " + response.getResponseStatus());
}
}
private void startUpdateUsingBinary(LwM2mClient client, String versionedId, UUID otaPackageId) {
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, logService, client, versionedId));
}
private TransportProtos.GetOtaPackageRequestMsg createOtaPackageRequestMsg(TransportProtos.SessionInfoProto sessionInfo, String nameFwSW) {
return TransportProtos.GetOtaPackageRequestMsg.newBuilder()
.setDeviceIdMSB(sessionInfo.getDeviceIdMSB())
@ -370,6 +505,16 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl
downlinkHandler.sendExecuteRequest(client, request, new TbLwM2MExecuteCallback(logService, client, FW_EXECUTE_ID));
}
private void executeSwInstall(LwM2mClient client) {
TbLwM2MExecuteRequest request = TbLwM2MExecuteRequest.builder().versionedId(SW_INSTALL_ID).timeout(config.getTimeout()).build();
downlinkHandler.sendExecuteRequest(client, request, new TbLwM2MExecuteCallback(logService, client, SW_INSTALL_ID));
}
private void executeSwUninstallForUpdate(LwM2mClient client) {
TbLwM2MExecuteRequest request = TbLwM2MExecuteRequest.builder().versionedId(SW_UN_INSTALL_ID).params("1").timeout(config.getTimeout()).build();
downlinkHandler.sendExecuteRequest(client, request, new TbLwM2MExecuteCallback(logService, client, SW_INSTALL_ID));
}
private Optional<String> getAttributeValue(List<TransportProtos.TsKvProto> attrs, String keyName) {
for (TransportProtos.TsKvProto attr : attrs) {
if (keyName.equals(attr.getKv().getKey())) {
@ -383,40 +528,41 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl
return Optional.empty();
}
public LwM2MClientOtaInfo getOrInitFwInfo(LwM2mClient client) {
private LwM2MClientFwOtaInfo getOrInitFwInfo(LwM2mClient client) {
return this.fwStates.computeIfAbsent(client.getEndpoint(), endpoint -> {
LwM2MClientOtaInfo info = otaInfoStore.get(OtaPackageType.FIRMWARE, endpoint);
LwM2MClientFwOtaInfo info = otaInfoStore.getFw(endpoint);
if (info == null) {
var profile = clientContext.getProfile(client.getProfileId());
info = new LwM2MClientOtaInfo(endpoint, OtaPackageType.FIRMWARE,
LwM2MFirmwareUpdateStrategy.fromStrategyFwByCode(profile.getClientLwM2mSettings().getFwUpdateStrategy()),
profile.getClientLwM2mSettings().getFwUpdateResource());
info = new LwM2MClientFwOtaInfo(endpoint, profile.getClientLwM2mSettings().getFwUpdateResource(),
LwM2MFirmwareUpdateStrategy.fromStrategyFwByCode(profile.getClientLwM2mSettings().getFwUpdateStrategy()));
update(info);
}
return info;
});
}
private LwM2MClientOtaInfo getOrInitSwInfo(LwM2mClient client) {
return this.fwStates.computeIfAbsent(client.getEndpoint(), endpoint -> {
LwM2MClientOtaInfo info = otaInfoStore.get(OtaPackageType.SOFTWARE, endpoint);
private LwM2MClientSwOtaInfo getOrInitSwInfo(LwM2mClient client) {
return this.swStates.computeIfAbsent(client.getEndpoint(), endpoint -> {
LwM2MClientSwOtaInfo info = otaInfoStore.getSw(endpoint);
if (info == null) {
var profile = clientContext.getProfile(client.getProfileId());
info = new LwM2MClientOtaInfo(endpoint, OtaPackageType.SOFTWARE,
LwM2MSoftwareUpdateStrategy.fromStrategySwByCode(profile.getClientLwM2mSettings().getFwUpdateStrategy()),
profile.getClientLwM2mSettings().getSwUpdateResource());
info = new LwM2MClientSwOtaInfo(endpoint, profile.getClientLwM2mSettings().getSwUpdateResource(),
LwM2MSoftwareUpdateStrategy.fromStrategySwByCode(profile.getClientLwM2mSettings().getFwUpdateStrategy()));
update(info);
}
return info;
});
}
private void update(LwM2MClientFwOtaInfo info) {
otaInfoStore.putFw(info);
}
private void update(LwM2MClientOtaInfo info) {
otaInfoStore.put(info);
private void update(LwM2MClientSwOtaInfo info) {
otaInfoStore.putSw(info);
}
private void sendStateUpdateToTelemetry(LwM2mClient client, LwM2MClientOtaInfo fwInfo, OtaPackageUpdateStatus status, String log) {
private void sendStateUpdateToTelemetry(LwM2mClient client, LwM2MClientOtaInfo<?, ?, ?> fwInfo, OtaPackageUpdateStatus status, String log) {
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());
@ -462,22 +608,31 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl
}
}
private static Optional<OtaPackageUpdateStatus> toOtaPackageUpdateStatus(SoftwareUpdateState swUpdateState) {
switch (swUpdateState) {
case INITIAL:
return Optional.empty();
case DOWNLOAD_STARTED:
return Optional.of(DOWNLOADING);
case DOWNLOADED:
return Optional.of(DOWNLOADING);
case DELIVERED:
return Optional.of(DOWNLOADED);
case INSTALLED:
return Optional.empty();
default:
throw new CodecException("Invalid value stateSw %d for SoftwareUpdateState.", swUpdateState);
}
}
/**
* FirmwareUpdateStatus {
* DOWNLOADING, DOWNLOADED, VERIFIED, UPDATING, UPDATED, FAILED
*/
public static Optional<OtaPackageUpdateStatus> toSwSateResultUpdateStatus(SoftwareUpdateState softwareUpdateState, SoftwareUpdateResult softwareUpdateResult) {
public static Optional<OtaPackageUpdateStatus> toOtaPackageUpdateStatus(SoftwareUpdateResult softwareUpdateResult) {
switch (softwareUpdateResult) {
case INITIAL:
switch (softwareUpdateState) {
case INITIAL:
case DOWNLOAD_STARTED:
return Optional.of(DOWNLOADING);
case DOWNLOADED:
return Optional.of(DOWNLOADED);
case DELIVERED:
return Optional.of(VERIFIED);
}
return Optional.empty();
case DOWNLOADING:
return Optional.of(DOWNLOADING);
case SUCCESSFULLY_INSTALLED:
@ -495,7 +650,7 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl
case UN_INSTALL_FAILURE:
return Optional.of(FAILED);
default:
throw new CodecException("Invalid value stateFw %s %s for FirmwareUpdateStatus.", softwareUpdateState.name(), softwareUpdateResult.name());
throw new CodecException("Invalid value stateFw %s for FirmwareUpdateStatus.", softwareUpdateResult.name());
}
}

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

@ -20,60 +20,42 @@ import lombok.Data;
import lombok.NoArgsConstructor;
import org.thingsboard.server.common.data.StringUtils;
import org.thingsboard.server.common.data.ota.OtaPackageType;
import org.thingsboard.server.transport.lwm2m.server.ota.firmware.LwM2MFirmwareUpdateStrategy;
import org.thingsboard.server.transport.lwm2m.server.ota.firmware.FirmwareUpdateResult;
import org.thingsboard.server.transport.lwm2m.server.ota.firmware.FirmwareUpdateState;
import org.thingsboard.server.transport.lwm2m.server.ota.software.LwM2MSoftwareUpdateStrategy;
import java.util.Optional;
@Data
@NoArgsConstructor
public class LwM2MClientOtaInfo {
public abstract class LwM2MClientOtaInfo<Strategy, State, Result> {
private String endpoint;
private OtaPackageType type;
private String baseUrl;
private boolean targetFetchFailure;
private String targetName;
private String targetVersion;
private String targetUrl;
private boolean currentFetchFailure;
private String currentName;
private String currentVersion3;
private String currentVersion5;
private Integer deliveryMethod;
protected String targetName;
protected String targetVersion;
protected String targetUrl;
//TODO: use value from device if applicable;
private LwM2MFirmwareUpdateStrategy fwStrategy;
private LwM2MSoftwareUpdateStrategy swStrategy;
private FirmwareUpdateState updateState;
private FirmwareUpdateResult updateResult;
protected Strategy strategy;
protected State updateState;
protected Result result;
private String failedPackageId;
private int retryAttempts;
protected String failedPackageId;
protected int retryAttempts;
public LwM2MClientOtaInfo(String endpoint, OtaPackageType type, LwM2MFirmwareUpdateStrategy fwStrategy, String baseUrl) {
this.endpoint = endpoint;
this.type = type;
this.fwStrategy = fwStrategy;
this.baseUrl = baseUrl;
}
protected String currentName;
protected String currentVersion3;
protected String currentVersion;
public LwM2MClientOtaInfo(String endpoint, OtaPackageType type, LwM2MSoftwareUpdateStrategy swStrategy, String baseUrl) {
public LwM2MClientOtaInfo(String endpoint, String baseUrl, Strategy strategy) {
this.endpoint = endpoint;
this.type = type;
this.swStrategy = swStrategy;
this.baseUrl = baseUrl;
this.strategy = strategy;
}
public void updateTarget(String targetName, String targetVersion, Optional<String> newFirmwareUrl) {
public void updateTarget(String targetName, String targetVersion, Optional<String> newTargetUrl) {
this.targetName = targetName;
this.targetVersion = targetVersion;
this.targetUrl = newFirmwareUrl.orElse(null);
this.targetUrl = newTargetUrl.orElse(null);
}
@JsonIgnore
@ -82,7 +64,7 @@ public class LwM2MClientOtaInfo {
return false;
} else {
String targetPackageId = getPackageId(targetName, targetVersion);
String currentPackageIdUsingObject5 = getPackageId(currentName, currentVersion5);
String currentPackageIdUsingObject5 = getPackageId(currentName, currentVersion);
if (StringUtils.isNotEmpty(failedPackageId) && failedPackageId.equals(targetPackageId)) {
return false;
} else {
@ -99,25 +81,15 @@ public class LwM2MClientOtaInfo {
@JsonIgnore
public boolean isSupported() {
return StringUtils.isNotEmpty(currentName) || StringUtils.isNotEmpty(currentVersion5) || StringUtils.isNotEmpty(currentVersion3);
return StringUtils.isNotEmpty(currentName) || StringUtils.isNotEmpty(currentVersion) || StringUtils.isNotEmpty(currentVersion3);
}
public void update(FirmwareUpdateResult updateResult) {
this.updateResult = updateResult;
switch (updateResult) {
case INITIAL:
break;
case UPDATE_SUCCESSFULLY:
retryAttempts = 0;
break;
default:
failedPackageId = getPackageId(targetName, targetVersion);
break;
}
}
public abstract void update(Result result);
private static String getPackageId(String name, String version) {
protected static String getPackageId(String name, String version) {
return (StringUtils.isNotEmpty(name) ? name : "") + (StringUtils.isNotEmpty(version) ? version : "");
}
public abstract OtaPackageType getType();
}

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

@ -26,9 +26,9 @@ public interface LwM2MOtaUpdateService {
void forceFirmwareUpdate(LwM2mClient client);
void onTargetFirmwareUpdate(LwM2mClient client, String newFirmwareTitle, String newFirmwareVersion, Optional<String> newFirmwareUrl);
void onTargetFirmwareUpdate(LwM2mClient client, String newFwTitle, String newFwVersion, Optional<String> newFwUrl);
void onTargetSoftwareUpdate(LwM2mClient client, String newSoftwareTitle, String newSoftwareVersion);
void onTargetSoftwareUpdate(LwM2mClient client, String newSwTitle, String newSwVersion, Optional<String> newSwUrl);
void onCurrentFirmwareNameUpdate(LwM2mClient client, String name);
@ -38,11 +38,21 @@ public interface LwM2MOtaUpdateService {
void onCurrentFirmwareVersion3Update(LwM2mClient client, String version);
void onCurrentFirmwareVersion5Update(LwM2mClient client, String version);
void onCurrentFirmwareVersionUpdate(LwM2mClient client, String version);
void onCurrentFirmwareStateUpdate(LwM2mClient client, Long state);
void onCurrentFirmwareResultUpdate(LwM2mClient client, Long result);
void onCurrentFirmwareDeliveryMethodUpdate(LwM2mClient lwM2MClient, Long value);
void onCurrentSoftwareNameUpdate(LwM2mClient lwM2MClient, String name);
void onCurrentSoftwareVersion3Update(LwM2mClient lwM2MClient, String version);
void onCurrentSoftwareVersionUpdate(LwM2mClient client, String version);
void onCurrentSoftwareStateUpdate(LwM2mClient lwM2MClient, Long value);
void onCurrentSoftwareResultUpdate(LwM2mClient client, Long result);
}

56
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ota/firmware/LwM2MClientFwOtaInfo.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.ota.firmware;
import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import org.thingsboard.server.common.data.ota.OtaPackageType;
import org.thingsboard.server.transport.lwm2m.server.ota.LwM2MClientOtaInfo;
@Data
@EqualsAndHashCode(callSuper = true)
@NoArgsConstructor
public class LwM2MClientFwOtaInfo extends LwM2MClientOtaInfo<LwM2MFirmwareUpdateStrategy, FirmwareUpdateState, FirmwareUpdateResult> {
private Integer deliveryMethod;
public LwM2MClientFwOtaInfo(String endpoint, String baseUrl, LwM2MFirmwareUpdateStrategy strategy) {
super(endpoint, baseUrl, strategy);
}
@JsonIgnore
@Override
public OtaPackageType getType() {
return OtaPackageType.FIRMWARE;
}
public void update(FirmwareUpdateResult result) {
this.result = result;
switch (result) {
case INITIAL:
break;
case UPDATE_SUCCESSFULLY:
retryAttempts = 0;
break;
default:
failedPackageId = getPackageId(targetName, targetVersion);
break;
}
}
}

57
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ota/software/LwM2MClientSwOtaInfo.java

@ -0,0 +1,57 @@
/**
* 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.software;
import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import org.thingsboard.server.common.data.StringUtils;
import org.thingsboard.server.common.data.ota.OtaPackageType;
import org.thingsboard.server.transport.lwm2m.server.ota.LwM2MClientOtaInfo;
import org.thingsboard.server.transport.lwm2m.server.ota.firmware.FirmwareUpdateResult;
import org.thingsboard.server.transport.lwm2m.server.ota.firmware.FirmwareUpdateState;
import org.thingsboard.server.transport.lwm2m.server.ota.firmware.LwM2MFirmwareUpdateStrategy;
@Data
@EqualsAndHashCode(callSuper = true)
@NoArgsConstructor
public class LwM2MClientSwOtaInfo extends LwM2MClientOtaInfo<LwM2MSoftwareUpdateStrategy, SoftwareUpdateState, SoftwareUpdateResult> {
public LwM2MClientSwOtaInfo(String endpoint, String baseUrl, LwM2MSoftwareUpdateStrategy strategy) {
super(endpoint, baseUrl, strategy);
}
@JsonIgnore
@Override
public OtaPackageType getType() {
return OtaPackageType.SOFTWARE;
}
public void update(SoftwareUpdateResult result) {
this.result = result;
switch (result) {
case INITIAL:
break;
//TODO: implement
default:
failedPackageId = getPackageId(targetName, targetVersion);
break;
}
}
}

3
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ota/software/SoftwareUpdateResult.java

@ -15,6 +15,8 @@
*/
package org.thingsboard.server.transport.lwm2m.server.ota.software;
import lombok.Getter;
/**
* SW Update Result
* Contains the result of downloading or installing/uninstalling the software
@ -56,6 +58,7 @@ public enum SoftwareUpdateResult {
public int code;
public String type;
@Getter
public boolean isAgain;
SoftwareUpdateResult(int code, String type, boolean isAgain) {

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

@ -82,7 +82,7 @@ public class DefaultLwM2MRpcRequestHandler implements LwM2MRpcRequestHandler {
public void onToDeviceRpcRequest(TransportProtos.ToDeviceRpcRequestMsg rpcRequst, TransportProtos.SessionInfoProto sessionInfo) {
this.cleanupOldSessions();
UUID requestUUID = new UUID(rpcRequst.getRequestIdMSB(), rpcRequst.getRequestIdLSB());
log.warn("Received params: {}", rpcRequst.getParams());
log.debug("Received params: {}", rpcRequst.getParams());
// We use this map to protect from browser issue that the same command is sent twice.
// TODO: This is probably not the best place and should be moved to DeviceActor
if (!this.rpcSubscriptions.containsKey(requestUUID)) {
@ -308,20 +308,19 @@ public class DefaultLwM2MRpcRequestHandler implements LwM2MRpcRequestHandler {
}
private void cleanupOldSessions() {
log.warn("4.1) before rpcSubscriptions.size(): [{}]", rpcSubscriptions.size());
log.debug("Before rpcSubscriptions.size(): [{}]", rpcSubscriptions.size());
if (rpcSubscriptions.size() > 0) {
long currentTime = System.currentTimeMillis();
Set<UUID> rpcSubscriptionsToRemove = rpcSubscriptions.entrySet().stream().filter(kv -> currentTime > kv.getValue()).map(Map.Entry::getKey).collect(Collectors.toSet());
log.warn("4.2) System.currentTimeMillis(): [{}]", System.currentTimeMillis());
log.warn("4.3) rpcSubscriptionsToRemove: [{}]", rpcSubscriptionsToRemove);
log.debug("RpcSubscriptionsToRemove: [{}]", rpcSubscriptionsToRemove);
rpcSubscriptionsToRemove.forEach(rpcSubscriptions::remove);
}
log.warn("4.4) after rpcSubscriptions.size(): [{}]", rpcSubscriptions.size());
log.debug("After rpcSubscriptions.size(): [{}]", rpcSubscriptions.size());
}
@Override
public void onToDeviceRpcResponse(TransportProtos.ToDeviceRpcResponseMsg toDeviceResponse, TransportProtos.SessionInfoProto sessionInfo) {
log.warn("5) onToDeviceRpcResponse: [{}], sessionUUID: [{}]", toDeviceResponse, new UUID(sessionInfo.getSessionIdMSB(), sessionInfo.getSessionIdLSB()));
log.debug("OnToDeviceRpcResponse: [{}], sessionUUID: [{}]", toDeviceResponse, new UUID(sessionInfo.getSessionIdMSB(), sessionInfo.getSessionIdLSB()));
transportService.process(sessionInfo, toDeviceResponse, null);
}

18
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbDummyLwM2MClientOtaInfoStore.java

@ -15,18 +15,28 @@
*/
package org.thingsboard.server.transport.lwm2m.server.store;
import org.thingsboard.server.common.data.ota.OtaPackageType;
import org.thingsboard.server.transport.lwm2m.server.ota.LwM2MClientOtaInfo;
import org.thingsboard.server.transport.lwm2m.server.ota.firmware.LwM2MClientFwOtaInfo;
import org.thingsboard.server.transport.lwm2m.server.ota.software.LwM2MClientSwOtaInfo;
public class TbDummyLwM2MClientOtaInfoStore implements TbLwM2MClientOtaInfoStore {
@Override
public LwM2MClientOtaInfo get(OtaPackageType type, String endpoint) {
public LwM2MClientFwOtaInfo getFw(String endpoint) {
return null;
}
@Override
public void put(LwM2MClientOtaInfo info) {
public LwM2MClientSwOtaInfo getSw(String endpoint) {
return null;
}
@Override
public void putFw(LwM2MClientFwOtaInfo info) {
}
@Override
public void putSw(LwM2MClientSwOtaInfo info) {
}
}

10
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2MClientOtaInfoStore.java

@ -17,10 +17,16 @@ package org.thingsboard.server.transport.lwm2m.server.store;
import org.thingsboard.server.common.data.ota.OtaPackageType;
import org.thingsboard.server.transport.lwm2m.server.ota.LwM2MClientOtaInfo;
import org.thingsboard.server.transport.lwm2m.server.ota.firmware.LwM2MClientFwOtaInfo;
import org.thingsboard.server.transport.lwm2m.server.ota.software.LwM2MClientSwOtaInfo;
public interface TbLwM2MClientOtaInfoStore {
LwM2MClientOtaInfo get(OtaPackageType type, String endpoint);
LwM2MClientFwOtaInfo getFw(String endpoint);
void put(LwM2MClientOtaInfo info);
LwM2MClientSwOtaInfo getSw(String endpoint);
void putFw(LwM2MClientFwOtaInfo info);
void putSw(LwM2MClientSwOtaInfo info);
}

34
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mRedisClientOtaInfoStore.java

@ -17,6 +17,7 @@ package org.thingsboard.server.transport.lwm2m.server.store;
import org.eclipse.leshan.server.security.NonUniqueSecurityInfoException;
import org.eclipse.leshan.server.security.SecurityInfo;
import org.jetbrains.annotations.Nullable;
import org.nustaq.serialization.FSTConfiguration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.integration.redis.util.RedisLockRegistry;
@ -24,6 +25,8 @@ import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.server.common.data.ota.OtaPackageType;
import org.thingsboard.server.transport.lwm2m.secure.TbLwM2MSecurityInfo;
import org.thingsboard.server.transport.lwm2m.server.ota.LwM2MClientOtaInfo;
import org.thingsboard.server.transport.lwm2m.server.ota.firmware.LwM2MClientFwOtaInfo;
import org.thingsboard.server.transport.lwm2m.server.ota.software.LwM2MClientSwOtaInfo;
import java.util.concurrent.locks.Lock;
@ -36,19 +39,36 @@ public class TbLwM2mRedisClientOtaInfoStore implements TbLwM2MClientOtaInfoStore
this.connectionFactory = connectionFactory;
}
@Override
public LwM2MClientOtaInfo get(OtaPackageType type, String endpoint) {
private void put(OtaPackageType type, LwM2MClientOtaInfo<?, ?, ?> info) {
try (var connection = connectionFactory.getConnection()) {
byte[] data = connection.get((OTA_EP + type + endpoint).getBytes());
return JacksonUtil.fromBytes(data, LwM2MClientOtaInfo.class);
connection.set((OTA_EP + type + info.getEndpoint()).getBytes(), JacksonUtil.toString(info).getBytes());
}
}
@Override
public void put(LwM2MClientOtaInfo info) {
public LwM2MClientFwOtaInfo getFw(String endpoint) {
return getLwM2MClientOtaInfo(OtaPackageType.FIRMWARE, endpoint, LwM2MClientFwOtaInfo.class);
}
@Override
public void putFw(LwM2MClientFwOtaInfo info) {
put(OtaPackageType.FIRMWARE, info);
}
@Override
public LwM2MClientSwOtaInfo getSw(String endpoint) {
return getLwM2MClientOtaInfo(OtaPackageType.SOFTWARE, endpoint, LwM2MClientSwOtaInfo.class);
}
@Override
public void putSw(LwM2MClientSwOtaInfo info) {
put(OtaPackageType.SOFTWARE, info);
}
private <T extends LwM2MClientOtaInfo<?, ?, ?>> T getLwM2MClientOtaInfo(OtaPackageType type, String endpoint, Class<T> clazz) {
try (var connection = connectionFactory.getConnection()) {
connection.set((OTA_EP + info.getType() + info.getEndpoint()).getBytes(), JacksonUtil.toString(info).getBytes());
byte[] data = connection.get((OTA_EP + type + endpoint).getBytes());
return JacksonUtil.fromBytes(data, clazz);
}
}
}

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

@ -90,7 +90,6 @@ import javax.annotation.PreDestroy;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
@ -111,11 +110,16 @@ import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.c
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertOtaUpdateValueToString;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.fromVersionedIdToObjectId;
import static org.thingsboard.server.transport.lwm2m.server.ota.DefaultLwM2MOtaUpdateService.FW_3_VER_ID;
import static org.thingsboard.server.transport.lwm2m.server.ota.DefaultLwM2MOtaUpdateService.FW_5_VER_ID;
import static org.thingsboard.server.transport.lwm2m.server.ota.DefaultLwM2MOtaUpdateService.FW_VER_ID;
import static org.thingsboard.server.transport.lwm2m.server.ota.DefaultLwM2MOtaUpdateService.FW_DELIVERY_METHOD;
import static org.thingsboard.server.transport.lwm2m.server.ota.DefaultLwM2MOtaUpdateService.FW_NAME_ID;
import static org.thingsboard.server.transport.lwm2m.server.ota.DefaultLwM2MOtaUpdateService.FW_RESULT_ID;
import static org.thingsboard.server.transport.lwm2m.server.ota.DefaultLwM2MOtaUpdateService.FW_STATE_ID;
import static org.thingsboard.server.transport.lwm2m.server.ota.DefaultLwM2MOtaUpdateService.SW_3_VER_ID;
import static org.thingsboard.server.transport.lwm2m.server.ota.DefaultLwM2MOtaUpdateService.SW_NAME_ID;
import static org.thingsboard.server.transport.lwm2m.server.ota.DefaultLwM2MOtaUpdateService.SW_RESULT_ID;
import static org.thingsboard.server.transport.lwm2m.server.ota.DefaultLwM2MOtaUpdateService.SW_STATE_ID;
import static org.thingsboard.server.transport.lwm2m.server.ota.DefaultLwM2MOtaUpdateService.SW_VER_ID;
@Slf4j
@ -238,7 +242,7 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl
executor.submit(() -> {
LwM2mClient lwM2MClient = clientContext.getClientByEndpoint(registration.getEndpoint());
try {
log.warn("[{}] [{{}] Client: update after Registration", registration.getEndpoint(), registration.getId());
log.info("[{}] [{{}] Client: update after Registration", registration.getEndpoint(), registration.getId());
logService.log(lwM2MClient, String.format("[%s][%s] Updated registration.", registration.getId(), registration.getSocketAddress()));
clientContext.updateRegistration(lwM2MClient, registration);
this.reportActivityAndRegister(lwM2MClient.getSession());
@ -318,7 +322,7 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl
}
public void onUpdateValueAfterReadCompositeResponse(Registration registration, ReadCompositeResponse response) {
log.warn("201) ReadCompositeResponse: [{}]", response);
log.trace("ReadCompositeResponse: [{}]", response);
if (response.getContent() != null) {
LwM2mClient lwM2MClient = clientContext.getClientByEndpoint(registration.getEndpoint());
response.getContent().forEach((k, v) -> {
@ -407,19 +411,7 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl
Lwm2mDeviceProfileTransportConfiguration profile = clientContext.getProfile(lwM2MClient.getProfileId());
Set<String> supportedObjects = clientContext.getSupportedIdVerInClient(lwM2MClient);
if (supportedObjects != null && supportedObjects.size() > 0) {
// #1
this.sendReadRequests(lwM2MClient, profile, supportedObjects);
// test composite
String[] paths = new String[]{"/3/0", "/1/0", "/5/0"};
// String [] paths = new String[] {"/5"};
// String [] paths = new String[] {"/"};
// String [] paths = new String[] {"/9"};
// defaultLwM2MDownlinkMsgHandler.sendReadCompositeRequest(lwM2MClient, paths, this);
Map<String, Object> nodes = new HashMap<>();
nodes.put("/3/0/14", "+02");
nodes.put("/1/0/2", 100);
nodes.put("/5/0/1", "coap://localhost:5685");
// defaultLwM2MDownlinkMsgHandler.sendWriteCompositeRequest(lwM2MClient, nodes, this);
this.sendObserveRequests(lwM2MClient, profile, supportedObjects);
this.sendWriteAttributeRequests(lwM2MClient, profile, supportedObjects);
// Removed. Used only for debug.
@ -531,14 +523,24 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl
otaService.onCurrentFirmwareNameUpdate(lwM2MClient, (String) lwM2mResource.getValue());
} else if (path.equals(convertObjectIdToVersionedId(FW_3_VER_ID, registration))) {
otaService.onCurrentFirmwareVersion3Update(lwM2MClient, (String) lwM2mResource.getValue());
} else if (path.equals(convertObjectIdToVersionedId(FW_5_VER_ID, registration))) {
otaService.onCurrentFirmwareVersion5Update(lwM2MClient, (String) lwM2mResource.getValue());
} else if (path.equals(convertObjectIdToVersionedId(FW_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());
} else if (path.equals(convertObjectIdToVersionedId(FW_DELIVERY_METHOD, registration))) {
otaService.onCurrentFirmwareDeliveryMethodUpdate(lwM2MClient, (Long) lwM2mResource.getValue());
} else if (path.equals(convertObjectIdToVersionedId(SW_NAME_ID, registration))) {
otaService.onCurrentSoftwareNameUpdate(lwM2MClient, (String) lwM2mResource.getValue());
} else if (path.equals(convertObjectIdToVersionedId(SW_VER_ID, registration))) {
otaService.onCurrentSoftwareVersionUpdate(lwM2MClient, (String) lwM2mResource.getValue());
} else if (path.equals(convertObjectIdToVersionedId(SW_3_VER_ID, registration))) {
otaService.onCurrentSoftwareVersion3Update(lwM2MClient, (String) lwM2mResource.getValue());
} else if (path.equals(convertObjectIdToVersionedId(SW_STATE_ID, registration))) {
otaService.onCurrentSoftwareStateUpdate(lwM2MClient, (Long) lwM2mResource.getValue());
} else if (path.equals(convertObjectIdToVersionedId(SW_RESULT_ID, registration))) {
otaService.onCurrentSoftwareResultUpdate(lwM2MClient, (Long) lwM2mResource.getValue());
}
this.updateAttrTelemetry(registration, Collections.singleton(path));
} else {
@ -698,7 +700,7 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl
@Override
public void onWriteCompositeResponseOk(LwM2mClient client, WriteCompositeRequest request) {
log.warn("202) ReadCompositeResponse: [{}]", request.getNodes());
log.trace("ReadCompositeResponse: [{}]", request.getNodes());
request.getNodes().forEach((k, v) -> {
this.updateResourcesValue(client, (LwM2mResource) v, k.toString());
});

Loading…
Cancel
Save