Browse Source

Merge branch 'master' into Lwm2m_OPAQUE

# Conflicts:
#	common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContextImpl.java
pull/4834/head
nickAS21 5 years ago
parent
commit
b161f20220
  1. 4
      application/src/main/java/org/thingsboard/server/actors/device/DeviceActorMessageProcessor.java
  2. 1
      application/src/main/resources/logback.xml
  3. 2
      common/data/src/main/java/org/thingsboard/server/common/data/device/data/lwm2m/OtherConfiguration.java
  4. 2
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MAuthorizer.java
  5. 18
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportCoapResource.java
  6. 20
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportUtil.java
  7. 10
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/attributes/DefaultLwM2MAttributesService.java
  8. 2
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java
  9. 2
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContext.java
  10. 94
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContextImpl.java
  11. 313
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ota/DefaultLwM2MOtaUpdateService.java
  12. 72
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ota/LwM2MClientOtaInfo.java
  13. 16
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ota/LwM2MOtaUpdateService.java
  14. 56
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ota/firmware/LwM2MClientFwOtaInfo.java
  15. 57
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ota/software/LwM2MClientSwOtaInfo.java
  16. 3
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ota/software/SoftwareUpdateResult.java
  17. 11
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/DefaultLwM2MRpcRequestHandler.java
  18. 18
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbDummyLwM2MClientOtaInfoStore.java
  19. 8
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbDummyLwM2MClientStore.java
  20. 10
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2MClientOtaInfoStore.java
  21. 4
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2MClientStore.java
  22. 34
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mRedisClientOtaInfoStore.java
  23. 3
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mSecurityStore.java
  24. 32
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbRedisLwM2MClientStore.java
  25. 52
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/DefaultLwM2MUplinkMsgHandler.java
  26. 1
      common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttSslHandlerProvider.java
  27. 2
      common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttTransportContext.java
  28. 2
      ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.html
  29. 4
      ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.scss
  30. 6
      ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.ts
  31. 4
      ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-profile-config.models.ts
  32. 3
      ui-ngx/src/assets/locale/locale.constant-en_US.json

4
application/src/main/java/org/thingsboard/server/actors/device/DeviceActorMessageProcessor.java

@ -269,7 +269,9 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor {
ToDeviceRpcRequestMetadata requestMd = toDeviceRpcPendingMap.remove(msg.getId());
if (requestMd != null) {
log.debug("[{}] RPC request [{}] timeout detected!", deviceId, msg.getId());
systemContext.getTbRpcService().save(tenantId, new RpcId(requestMd.getMsg().getMsg().getId()), RpcStatus.TIMEOUT, null);
if (requestMd.getMsg().getMsg().isPersisted()) {
systemContext.getTbRpcService().save(tenantId, new RpcId(requestMd.getMsg().getMsg().getId()), RpcStatus.TIMEOUT, null);
}
systemContext.getTbCoreDeviceRpcService().processRpcResponseFromDeviceActor(new FromDeviceRpcResponse(requestMd.getMsg().getMsg().getId(),
null, requestMd.isSent() ? RpcError.TIMEOUT : RpcError.NO_ACTIVE_CONNECTION));
}

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/data/src/main/java/org/thingsboard/server/common/data/device/data/lwm2m/OtherConfiguration.java

@ -27,6 +27,6 @@ public class OtherConfiguration {
private PowerMode powerMode;
private String fwUpdateResource;
private String swUpdateResource;
private boolean composite;
private boolean compositeOperationsSupport;
}

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);
}

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

@ -16,34 +16,24 @@
package org.thingsboard.server.transport.lwm2m.server;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.google.gson.JsonSyntaxException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.leshan.core.attributes.Attribute;
import org.eclipse.leshan.core.attributes.AttributeSet;
import org.eclipse.leshan.core.model.ObjectModel;
import org.eclipse.leshan.core.model.ResourceModel;
import org.eclipse.leshan.core.node.LwM2mMultipleResource;
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;
import org.eclipse.leshan.core.request.WriteAttributesRequest;
import org.eclipse.leshan.core.util.Hex;
import org.eclipse.leshan.server.registration.Registration;
import org.nustaq.serialization.FSTConfiguration;
import org.thingsboard.server.common.data.DeviceProfile;
import org.thingsboard.server.common.data.DeviceTransportType;
import org.thingsboard.server.common.data.device.data.lwm2m.BootstrapConfiguration;
import org.thingsboard.server.common.data.device.profile.DeviceProfileTransportConfiguration;
import org.thingsboard.server.common.data.device.profile.Lwm2mDeviceProfileTransportConfiguration;
import org.thingsboard.server.common.transport.TransportServiceCallback;
import org.thingsboard.server.transport.lwm2m.config.LwM2mVersion;
import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient;
import org.thingsboard.server.transport.lwm2m.server.client.ResourceValue;
@ -56,10 +46,8 @@ import org.thingsboard.server.transport.lwm2m.server.uplink.DefaultLwM2MUplinkMs
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import static org.eclipse.leshan.core.attributes.Attribute.DIMENSION;
@ -81,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 {
@ -155,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;
@ -175,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());
}
}
@ -197,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);
}
}

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

@ -23,9 +23,6 @@ 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;
import org.thingsboard.server.common.data.ota.OtaPackageUtil;
import org.thingsboard.server.common.transport.TransportService;
import org.thingsboard.server.common.transport.TransportServiceCallback;
import org.thingsboard.server.gen.transport.TransportProtos;
@ -126,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();
@ -139,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);
}
}
@ -147,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);

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

@ -15,6 +15,7 @@
*/
package org.thingsboard.server.transport.lwm2m.server.client;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
@ -62,6 +63,7 @@ import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.f
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.getVerFromPathIdVerOrId;
@Slf4j
@EqualsAndHashCode(of = {"endpoint"})
public class LwM2mClient implements Serializable {
private static final long serialVersionUID = 8793482946289222623L;

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

@ -58,4 +58,6 @@ public interface LwM2mClientContext {
void update(LwM2mClient lwM2MClient);
void removeCredentials(TransportProtos.SessionInfoProto sessionInfo);
void sendMsgsAfterSleeping(LwM2mClient lwM2MClient);
}

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

@ -21,21 +21,28 @@ import org.eclipse.leshan.core.SecurityMode;
import org.eclipse.leshan.core.model.ResourceModel;
import org.eclipse.leshan.core.node.LwM2mPath;
import org.eclipse.leshan.server.registration.Registration;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.thingsboard.server.common.data.DeviceProfile;
import org.thingsboard.server.common.data.device.data.PowerMode;
import org.thingsboard.server.common.data.device.profile.Lwm2mDeviceProfileTransportConfiguration;
import org.thingsboard.server.common.data.id.DeviceProfileId;
import org.thingsboard.server.common.transport.TransportDeviceProfileCache;
import org.thingsboard.server.common.transport.TransportServiceCallback;
import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse;
import org.thingsboard.server.gen.transport.TransportProtos;
import org.thingsboard.server.queue.util.AfterStartUp;
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;
import org.thingsboard.server.transport.lwm2m.server.ota.LwM2MOtaUpdateService;
import org.thingsboard.server.transport.lwm2m.server.session.LwM2MSessionManager;
import org.thingsboard.server.transport.lwm2m.server.store.TbLwM2MClientStore;
import org.thingsboard.server.transport.lwm2m.server.store.TbMainSecurityStore;
import org.thingsboard.server.transport.lwm2m.server.uplink.DefaultLwM2MUplinkMsgHandler;
import java.util.Arrays;
import java.util.Collection;
@ -63,10 +70,29 @@ public class LwM2mClientContextImpl implements LwM2mClientContext {
private final TbLwM2MClientStore clientStore;
private final LwM2MSessionManager sessionManager;
private final TransportDeviceProfileCache deviceProfileCache;
@Autowired
@Lazy
private DefaultLwM2MUplinkMsgHandler defaultLwM2MUplinkMsgHandler;
@Autowired
@Lazy
private LwM2MOtaUpdateService otaUpdateService;
private final Map<String, LwM2mClient> lwM2mClientsByEndpoint = new ConcurrentHashMap<>();
private final Map<String, LwM2mClient> lwM2mClientsByRegistrationId = new ConcurrentHashMap<>();
private final Map<UUID, Lwm2mDeviceProfileTransportConfiguration> profiles = new ConcurrentHashMap<>();
@AfterStartUp
public void init() {
String nodeId = context.getNodeId();
Set<LwM2mClient> fetchedClients = clientStore.getAll();
log.debug("Fetched clients from store: {}", fetchedClients);
fetchedClients.forEach(client -> {
lwM2mClientsByEndpoint.put(client.getEndpoint(), client);
updateFetchedClient(nodeId, client);
});
}
@Override
public LwM2mClient getClientByEndpoint(String endpoint) {
return lwM2mClientsByEndpoint.computeIfAbsent(endpoint, ep -> {
@ -77,23 +103,27 @@ public class LwM2mClientContextImpl implements LwM2mClientContext {
client = new LwM2mClient(nodeId, ep);
} else {
log.debug("[{}] fetched client from store: {}", endpoint, client);
boolean updated = false;
if (client.getRegistration() != null) {
lwM2mClientsByRegistrationId.put(client.getRegistration().getId(), client);
}
if (client.getSession() != null) {
client.refreshSessionId(nodeId);
sessionManager.register(client.getSession());
updated = true;
}
if (updated) {
clientStore.put(client);
}
updateFetchedClient(nodeId, client);
}
return client;
});
}
private void updateFetchedClient(String nodeId, LwM2mClient client) {
boolean updated = false;
if (client.getRegistration() != null) {
lwM2mClientsByRegistrationId.put(client.getRegistration().getId(), client);
}
if (client.getSession() != null) {
client.refreshSessionId(nodeId);
sessionManager.register(client.getSession());
updated = true;
}
if (updated) {
clientStore.put(client);
}
}
@Override
public Optional<TransportProtos.SessionInfoProto> register(LwM2mClient client, Registration registration) throws LwM2MClientStateException {
TransportProtos.SessionInfoProto oldSession = null;
@ -142,6 +172,7 @@ public class LwM2mClientContextImpl implements LwM2mClientContext {
}
client.setRegistration(registration);
clientStore.put(client);
sendMsgsAfterSleeping(client);
} finally {
client.unlock();
}
@ -232,6 +263,28 @@ public class LwM2mClientContextImpl implements LwM2mClientContext {
//TODO: implement
}
@Override
public void sendMsgsAfterSleeping(LwM2mClient lwM2MClient) {
if (LwM2MClientState.REGISTERED.equals(lwM2MClient.getState())) {
PowerMode powerMode = lwM2MClient.getPowerMode();
if (powerMode == null) {
Lwm2mDeviceProfileTransportConfiguration deviceProfile = getProfile(lwM2MClient.getProfileId());
powerMode = deviceProfile.getClientLwM2mSettings().getPowerMode();
}
if (PowerMode.PSM.equals(powerMode) || PowerMode.E_DRX.equals(powerMode)) {
defaultLwM2MUplinkMsgHandler.initAttributes(lwM2MClient);
TransportProtos.TransportToDeviceActorMsg persistentRpcRequestMsg = TransportProtos.TransportToDeviceActorMsg
.newBuilder()
.setSessionInfo(lwM2MClient.getSession())
.setSendPendingRPC(TransportProtos.SendPendingRPCMsg.newBuilder().build())
.build();
context.getTransportService().process(persistentRpcRequestMsg, TransportServiceCallback.EMPTY);
otaUpdateService.init(lwM2MClient);
}
}
}
@Override
public Collection<LwM2mClient> getLwM2mClients() {
return lwM2mClientsByEndpoint.values();
@ -245,22 +298,23 @@ public class LwM2mClientContextImpl implements LwM2mClientContext {
@Override
public Lwm2mDeviceProfileTransportConfiguration getProfile(Registration registration) {
UUID profileId = getClientByEndpoint(registration.getEndpoint()).getProfileId();
Lwm2mDeviceProfileTransportConfiguration result = doGetAndCache(profileId);
return doGetAndCache(profileId);
}
private Lwm2mDeviceProfileTransportConfiguration doGetAndCache(UUID profileId) {
Lwm2mDeviceProfileTransportConfiguration result = profiles.get(profileId);
if (result == null) {
log.debug("[{}] Fetching profile [{}]", registration.getEndpoint(), profileId);
log.debug("Fetching profile [{}]", profileId);
DeviceProfile deviceProfile = deviceProfileCache.get(new DeviceProfileId(profileId));
if (deviceProfile != null) {
profileUpdate(deviceProfile);
result = doGetAndCache(profileId);
result = profileUpdate(deviceProfile);
} else {
log.info("Device profile was not found! Most probably device profile [{}] has been removed from the database.", profileId);
}
}
return result;
}
private Lwm2mDeviceProfileTransportConfiguration doGetAndCache(UUID profileId) {
return profiles.get(profileId);
}
@Override
public Lwm2mDeviceProfileTransportConfiguration profileUpdate(DeviceProfile deviceProfile) {
Lwm2mDeviceProfileTransportConfiguration clientProfile = LwM2mTransportUtil.toLwM2MClientProfile(deviceProfile);

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)) {
@ -324,20 +324,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) {
}
}

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

@ -17,12 +17,20 @@ package org.thingsboard.server.transport.lwm2m.server.store;
import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient;
import java.util.Collections;
import java.util.Set;
public class TbDummyLwM2MClientStore implements TbLwM2MClientStore {
@Override
public LwM2mClient get(String endpoint) {
return null;
}
@Override
public Set<LwM2mClient> getAll() {
return Collections.emptySet();
}
@Override
public void put(LwM2mClient client) {

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);
}

4
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2MClientStore.java

@ -17,10 +17,14 @@ package org.thingsboard.server.transport.lwm2m.server.store;
import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient;
import java.util.Set;
public interface TbLwM2MClientStore {
LwM2mClient get(String endpoint);
Set<LwM2mClient> getAll();
void put(LwM2mClient client);
void remove(String endpoint);

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);
}
}
}

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

@ -23,12 +23,9 @@ import org.thingsboard.server.transport.lwm2m.secure.LwM2mCredentialsSecurityInf
import org.thingsboard.server.transport.lwm2m.secure.TbLwM2MSecurityInfo;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import static org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mTypeServer.CLIENT;

32
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbRedisLwM2MClientStore.java

@ -16,9 +16,17 @@
package org.thingsboard.server.transport.lwm2m.server.store;
import org.nustaq.serialization.FSTConfiguration;
import org.springframework.data.redis.connection.RedisClusterConnection;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.Cursor;
import org.springframework.data.redis.core.ScanOptions;
import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class TbRedisLwM2MClientStore implements TbLwM2MClientStore {
private static final String CLIENT_EP = "CLIENT#EP#";
@ -42,6 +50,30 @@ public class TbRedisLwM2MClientStore implements TbLwM2MClientStore {
}
}
@Override
public Set<LwM2mClient> getAll() {
try (var connection = connectionFactory.getConnection()) {
Set<LwM2mClient> clients = new HashSet<>();
ScanOptions scanOptions = ScanOptions.scanOptions().count(100).match(CLIENT_EP + "*").build();
List<Cursor<byte[]>> scans = new ArrayList<>();
if (connection instanceof RedisClusterConnection) {
((RedisClusterConnection) connection).clusterGetNodes().forEach(node -> {
scans.add(((RedisClusterConnection) connection).scan(node, scanOptions));
});
} else {
scans.add(connection.scan(scanOptions));
}
scans.forEach(scan -> {
scan.forEachRemaining(key -> {
byte[] element = connection.get(key);
clients.add((LwM2mClient) serializer.asObject(element));
});
});
return clients;
}
}
@Override
public void put(LwM2mClient client) {
byte[] clientSerialized = serializer.asByteArray(client);

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

@ -42,7 +42,6 @@ import org.thingsboard.common.util.DonAsynchron;
import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.DeviceProfile;
import org.thingsboard.server.common.data.StringUtils;
import org.thingsboard.server.common.data.device.data.PowerMode;
import org.thingsboard.server.common.data.device.data.lwm2m.ObjectAttributes;
import org.thingsboard.server.common.data.device.data.lwm2m.OtherConfiguration;
import org.thingsboard.server.common.data.device.data.lwm2m.TelemetryMappingConfiguration;
@ -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) -> {
@ -387,26 +391,9 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl
@Override
public void onAwakeDev(Registration registration) {
log.trace("[{}] [{}] Received endpoint Awake version event", registration.getId(), registration.getEndpoint());
LwM2mClient lwM2MClient = this.clientContext.getClientByEndpoint(registration.getEndpoint());
logService.log(lwM2MClient, LOG_LWM2M_INFO + ": Client is awake!");
if (LwM2MClientState.REGISTERED.equals(lwM2MClient.getState())) {
PowerMode powerMode = lwM2MClient.getPowerMode();
if (powerMode == null) {
Lwm2mDeviceProfileTransportConfiguration deviceProfile = clientContext.getProfile(lwM2MClient.getProfileId());
powerMode = deviceProfile.getClientLwM2mSettings().getPowerMode();
}
if (PowerMode.PSM.equals(powerMode) || PowerMode.E_DRX.equals(powerMode)) {
initAttributes(lwM2MClient);
TransportProtos.TransportToDeviceActorMsg persistentRpcRequestMsg = TransportProtos.TransportToDeviceActorMsg
.newBuilder()
.setSessionInfo(lwM2MClient.getSession())
.setSendPendingRPC(TransportProtos.SendPendingRPCMsg.newBuilder().build())
.build();
transportService.process(persistentRpcRequestMsg, TransportServiceCallback.EMPTY);
}
}
LwM2mClient client = this.clientContext.getClientByEndpoint(registration.getEndpoint());
logService.log(client, LOG_LWM2M_INFO + ": Client is awake!");
clientContext.sendMsgsAfterSleeping(client);
}
/**
@ -424,7 +411,6 @@ 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);
this.sendObserveRequests(lwM2MClient, profile, supportedObjects);
this.sendWriteAttributeRequests(lwM2MClient, profile, supportedObjects);
@ -537,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 {
@ -704,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());
});

1
common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttSslHandlerProvider.java

@ -55,7 +55,6 @@ import java.util.concurrent.TimeUnit;
*/
@Slf4j
@Component("MqttSslHandlerProvider")
@ConditionalOnExpression("'${transport.mqtt.enabled}'=='true'")
@ConditionalOnProperty(prefix = "transport.mqtt.ssl", value = "enabled", havingValue = "true", matchIfMissing = false)
public class MqttSslHandlerProvider {

2
common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttTransportContext.java

@ -52,7 +52,7 @@ public class MqttTransportContext extends TransportContext {
private Integer maxPayloadSize;
@Getter
@Value("${transport.mqtt.netty.skip_validity_check_for_client_cert:false}")
@Value("${transport.mqtt.ssl.skip_validity_check_for_client_cert:false}")
private boolean skipValidityCheckForClientCert;
@Getter

2
ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.html

@ -168,6 +168,8 @@
</mat-select>
</mat-form-field>
</fieldset>
<mat-slide-toggle class="mat-slider"
formControlName="compositeOperationsSupport">{{ 'device-profile.lwm2m.composite-operations-support' | translate }}</mat-slide-toggle>
<!-- <mat-accordion multi="true">-->
<!-- <div *ngIf="false">-->
<!-- <mat-expansion-panel>-->

4
ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.scss

@ -24,4 +24,8 @@
color: rgba(0, 0, 0, .7);
}
}
.mat-slider {
margin: 8px 0 8px 10px;
}
}

6
ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.ts

@ -117,7 +117,8 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro
swUpdateStrategy: [1, []],
fwUpdateResource: [{value: '', disabled: true}, []],
swUpdateResource: [{value: '', disabled: true}, []],
powerMode: [null, Validators.required]
powerMode: [PowerMode.DRX, Validators.required],
compositeOperationsSupport: [false]
})
});
this.lwm2mDeviceConfigFormGroup = this.fb.group({
@ -258,7 +259,8 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro
swUpdateStrategy: this.configurationValue.clientLwM2mSettings.swUpdateStrategy || 1,
fwUpdateResource: fwResource,
swUpdateResource: swResource,
powerMode: this.configurationValue.clientLwM2mSettings.powerMode
powerMode: this.configurationValue.clientLwM2mSettings.powerMode || PowerMode.DRX,
compositeOperationsSupport: this.configurationValue.clientLwM2mSettings.compositeOperationsSupport || false
}
},
{emitEvent: false});

4
ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-profile-config.models.ts

@ -175,6 +175,7 @@ export interface ClientLwM2mSettings {
fwUpdateResource: string;
swUpdateResource: string;
powerMode: PowerMode;
compositeOperationsSupport: boolean;
}
export interface ObservableAttributes {
@ -231,7 +232,8 @@ export function getDefaultProfileClientLwM2mSettingsConfig(): ClientLwM2mSetting
swUpdateStrategy: 1,
fwUpdateResource: DEFAULT_FW_UPDATE_RESOURCE,
swUpdateResource: DEFAULT_SW_UPDATE_RESOURCE,
powerMode: PowerMode.DRX
powerMode: PowerMode.DRX,
compositeOperationsSupport: false
};
}

3
ui-ngx/src/assets/locale/locale.constant-en_US.json

@ -1328,7 +1328,8 @@
"step": "Step",
"min-evaluation-period": "Minimum evaluation period",
"max-evaluation-period": "Maximum evaluation period"
}
},
"composite-operations-support": "Supports composite Read/Write/Observe operations"
},
"snmp": {
"add-communication-config": "Add communication config",

Loading…
Cancel
Save