Browse Source

Merge pull request #4787 from YevhenBondarenko/feature/power-mode

Feature/power mode
pull/4793/head
Andrew Shvayka 5 years ago
committed by GitHub
parent
commit
d190cba277
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 18
      application/src/main/java/org/thingsboard/server/service/transport/DefaultTransportApiService.java
  2. 5
      common/data/src/main/java/org/thingsboard/server/common/data/device/data/Lwm2mDeviceTransportConfiguration.java
  3. 20
      common/data/src/main/java/org/thingsboard/server/common/data/device/data/PowerMode.java
  4. 6
      common/data/src/main/java/org/thingsboard/server/common/data/device/data/lwm2m/OtherConfiguration.java
  5. 1
      common/queue/src/main/proto/queue.proto
  6. 19
      common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/CoapTransportResource.java
  7. 16
      common/transport/http/src/main/java/org/thingsboard/server/transport/http/DeviceApiController.java
  8. 10
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/LwM2mCredentialsSecurityInfoValidator.java
  9. 11
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MAuthorizer.java
  10. 8
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MDtlsCertificateVerifier.java
  11. 4
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/DefaultLwM2mTransportService.java
  12. 17
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mSessionMsgListener.java
  13. 13
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportCoapResource.java
  14. 2
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportUtil.java
  15. 22
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2MAuthException.java
  16. 7
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java
  17. 14
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ota/DefaultLwM2MOtaUpdateService.java
  18. 84
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/DefaultLwM2MUplinkMsgHandler.java
  19. 24
      common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttTransportHandler.java
  20. 23
      common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/GatewayDeviceSessionCtx.java
  21. 21
      common/transport/snmp/src/main/java/org/thingsboard/server/transport/snmp/session/DeviceSessionContext.java
  22. 4
      common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/TransportService.java
  23. 2
      common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/auth/TransportDeviceInfo.java
  24. 35
      common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportService.java
  25. 27
      ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.html
  26. 56
      ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.ts
  27. 24
      ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-profile-config.models.ts
  28. 4
      ui-ngx/src/app/modules/home/pages/device/data/device-transport-configuration.component.html
  29. 14
      ui-ngx/src/app/modules/home/pages/device/data/lwm2m-device-transport-configuration.component.html
  30. 9
      ui-ngx/src/app/modules/home/pages/device/data/lwm2m-device-transport-configuration.component.ts
  31. 2
      ui-ngx/src/app/shared/models/device.models.ts
  32. 15
      ui-ngx/src/assets/locale/locale.constant-en_US.json

18
application/src/main/java/org/thingsboard/server/service/transport/DefaultTransportApiService.java

@ -41,6 +41,8 @@ import org.thingsboard.server.common.data.TbResource;
import org.thingsboard.server.common.data.TenantProfile;
import org.thingsboard.server.common.data.device.credentials.BasicMqttCredentials;
import org.thingsboard.server.common.data.device.credentials.ProvisionDeviceCredentialsData;
import org.thingsboard.server.common.data.device.data.Lwm2mDeviceTransportConfiguration;
import org.thingsboard.server.common.data.device.data.PowerMode;
import org.thingsboard.server.common.data.device.profile.ProvisionDeviceProfileCredentials;
import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.DeviceId;
@ -459,7 +461,14 @@ public class DefaultTransportApiService implements TransportApiService {
}
private DeviceInfoProto getDeviceInfoProto(Device device) throws JsonProcessingException {
return DeviceInfoProto.newBuilder()
PowerMode powerMode = null;
switch (device.getDeviceData().getTransportConfiguration().getType()) {
case LWM2M:
powerMode = ((Lwm2mDeviceTransportConfiguration) device.getDeviceData().getTransportConfiguration()).getPowerMode();
break;
}
DeviceInfoProto.Builder builder = DeviceInfoProto.newBuilder()
.setTenantIdMSB(device.getTenantId().getId().getMostSignificantBits())
.setTenantIdLSB(device.getTenantId().getId().getLeastSignificantBits())
.setCustomerIdMSB(Optional.ofNullable(device.getCustomerId()).map(customerId -> customerId.getId().getMostSignificantBits()).orElse(0L))
@ -470,8 +479,11 @@ public class DefaultTransportApiService implements TransportApiService {
.setDeviceType(device.getType())
.setDeviceProfileIdMSB(device.getDeviceProfileId().getId().getMostSignificantBits())
.setDeviceProfileIdLSB(device.getDeviceProfileId().getId().getLeastSignificantBits())
.setAdditionalInfo(mapper.writeValueAsString(device.getAdditionalInfo()))
.build();
.setAdditionalInfo(mapper.writeValueAsString(device.getAdditionalInfo()));
if (powerMode != null) {
builder.setPowerMode(powerMode.name());
}
return builder.build();
}
private ListenableFuture<TransportApiResponseMsg> getEmptyTransportApiResponseFuture() {

5
common/data/src/main/java/org/thingsboard/server/common/data/device/data/Lwm2mDeviceTransportConfiguration.java

@ -20,9 +20,6 @@ import com.fasterxml.jackson.annotation.JsonAnySetter;
import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.Data;
import org.thingsboard.server.common.data.DeviceTransportType;
import org.thingsboard.server.common.data.device.data.lwm2m.BootstrapConfiguration;
import org.thingsboard.server.common.data.device.data.lwm2m.OtherConfiguration;
import org.thingsboard.server.common.data.device.data.lwm2m.TelemetryMappingConfiguration;
import java.util.HashMap;
import java.util.Map;
@ -30,6 +27,8 @@ import java.util.Map;
@Data
public class Lwm2mDeviceTransportConfiguration implements DeviceTransportConfiguration {
private PowerMode powerMode;
@JsonIgnore
private Map<String, Object> properties = new HashMap<>();

20
common/data/src/main/java/org/thingsboard/server/common/data/device/data/PowerMode.java

@ -0,0 +1,20 @@
/**
* 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.common.data.device.data;
public enum PowerMode {
PSM, DRX, E_DRX
}

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

@ -16,6 +16,7 @@
package org.thingsboard.server.common.data.device.data.lwm2m;
import lombok.Data;
import org.thingsboard.server.common.data.device.data.PowerMode;
@Data
public class OtherConfiguration {
@ -23,7 +24,8 @@ public class OtherConfiguration {
private Integer fwUpdateStrategy;
private Integer swUpdateStrategy;
private Integer clientOnlyObserveAfterConnect;
private String fwUpdateRecourse;
private String swUpdateRecourse;
private PowerMode powerMode;
private String fwUpdateResource;
private String swUpdateResource;
}

1
common/queue/src/main/proto/queue.proto

@ -115,6 +115,7 @@ message DeviceInfoProto {
int64 deviceProfileIdLSB = 9;
int64 customerIdMSB = 10;
int64 customerIdLSB = 11;
string powerMode = 12;
}
/**

19
common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/CoapTransportResource.java

@ -44,7 +44,6 @@ import org.thingsboard.server.common.data.device.profile.DeviceProfileTransportC
import org.thingsboard.server.common.data.device.profile.JsonTransportPayloadConfiguration;
import org.thingsboard.server.common.data.device.profile.ProtoTransportPayloadConfiguration;
import org.thingsboard.server.common.data.device.profile.TransportPayloadTypeConfiguration;
import org.thingsboard.server.common.data.rpc.RpcStatus;
import org.thingsboard.server.common.data.security.DeviceTokenCredentials;
import org.thingsboard.server.common.msg.session.FeatureType;
import org.thingsboard.server.common.msg.session.SessionMsgType;
@ -509,23 +508,7 @@ public class CoapTransportResource extends AbstractCoapTransportResource {
closeObserveRelationAndNotify(sessionId, CoAP.ResponseCode.INTERNAL_SERVER_ERROR);
successful = false;
} finally {
if (msg.getPersisted()) {
RpcStatus status;
if (!successful) {
status = RpcStatus.FAILED;
} else if (msg.getOneway()) {
status = RpcStatus.SUCCESSFUL;
} else {
status = RpcStatus.DELIVERED;
}
TransportProtos.ToDevicePersistedRpcResponseMsg responseMsg = TransportProtos.ToDevicePersistedRpcResponseMsg.newBuilder()
.setRequestId(msg.getRequestId())
.setRequestIdLSB(msg.getRequestIdLSB())
.setRequestIdMSB(msg.getRequestIdMSB())
.setStatus(status.name())
.build();
coapTransportResource.transportService.process(sessionInfo, responseMsg, TransportServiceCallback.EMPTY);
}
coapTransportResource.transportService.process(sessionInfo, msg, !successful, TransportServiceCallback.EMPTY);
if (!successful) {
closeAndDeregister();
}

16
common/transport/http/src/main/java/org/thingsboard/server/transport/http/DeviceApiController.java

@ -408,21 +408,7 @@ public class DeviceApiController implements TbTransportService {
public void onToDeviceRpcRequest(UUID sessionId, ToDeviceRpcRequestMsg msg) {
log.trace("[{}] Received RPC command to device", sessionId);
responseWriter.setResult(new ResponseEntity<>(JsonConverter.toJson(msg, true).toString(), HttpStatus.OK));
if (msg.getPersisted()) {
RpcStatus status;
if (msg.getOneway()) {
status = RpcStatus.SUCCESSFUL;
} else {
status = RpcStatus.DELIVERED;
}
TransportProtos.ToDevicePersistedRpcResponseMsg responseMsg = TransportProtos.ToDevicePersistedRpcResponseMsg.newBuilder()
.setRequestId(msg.getRequestId())
.setRequestIdLSB(msg.getRequestIdLSB())
.setRequestIdMSB(msg.getRequestIdMSB())
.setStatus(status.name())
.build();
transportService.process(sessionInfo, responseMsg, TransportServiceCallback.EMPTY);
}
transportService.process(sessionInfo, msg, false, TransportServiceCallback.EMPTY);
}
@Override

10
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/LwM2mCredentialsSecurityInfoValidator.java

@ -33,6 +33,7 @@ import org.thingsboard.server.queue.util.TbLwM2mTransportComponent;
import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig;
import org.thingsboard.server.transport.lwm2m.secure.credentials.LwM2MCredentials;
import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportContext;
import org.thingsboard.server.transport.lwm2m.server.client.LwM2MAuthException;
import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mTypeServer;
import java.io.IOException;
@ -84,7 +85,14 @@ public class LwM2mCredentialsSecurityInfoValidator {
} catch (InterruptedException e) {
log.error("Failed to await credentials!", e);
}
return resultSecurityStore[0];
TbLwM2MSecurityInfo securityInfo = resultSecurityStore[0];
if (securityInfo.getSecurityMode() == null) {
throw new LwM2MAuthException();
}
return securityInfo;
}
/**

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

@ -16,6 +16,7 @@
package org.thingsboard.server.transport.lwm2m.secure;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.leshan.core.request.Identity;
import org.eclipse.leshan.core.request.UplinkRequest;
import org.eclipse.leshan.server.registration.Registration;
@ -24,14 +25,15 @@ import org.eclipse.leshan.server.security.SecurityChecker;
import org.eclipse.leshan.server.security.SecurityInfo;
import org.springframework.stereotype.Component;
import org.thingsboard.server.queue.util.TbLwM2mTransportComponent;
import org.thingsboard.server.transport.lwm2m.server.client.LwM2MAuthException;
import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientContext;
import org.thingsboard.server.transport.lwm2m.server.store.TbLwM2MDtlsSessionStore;
import org.thingsboard.server.transport.lwm2m.server.store.TbLwM2mSecurityStore;
import org.thingsboard.server.transport.lwm2m.server.store.TbSecurityStore;
@Component
@RequiredArgsConstructor
@TbLwM2mTransportComponent
@Slf4j
public class TbLwM2MAuthorizer implements Authorizer {
private final TbLwM2MDtlsSessionStore sessionStorage;
@ -57,7 +59,12 @@ public class TbLwM2MAuthorizer implements Authorizer {
}
SecurityInfo expectedSecurityInfo = null;
if (securityStore != null) {
expectedSecurityInfo = securityStore.getByEndpoint(registration.getEndpoint());
try {
expectedSecurityInfo = securityStore.getByEndpoint(registration.getEndpoint());
} catch (LwM2MAuthException e) {
log.warn("Registration failed: FORBIDDEN, endpointId: [{}]", registration.getEndpoint());
return null;
}
}
if (securityChecker.checkSecurityInfo(registration.getEndpoint(), senderIdentity, expectedSecurityInfo)) {
return registration;

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

@ -42,6 +42,7 @@ import org.thingsboard.server.common.transport.util.SslUtil;
import org.thingsboard.server.queue.util.TbLwM2mTransportComponent;
import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig;
import org.thingsboard.server.transport.lwm2m.secure.credentials.LwM2MCredentials;
import org.thingsboard.server.transport.lwm2m.server.client.LwM2MAuthException;
import org.thingsboard.server.transport.lwm2m.server.store.TbLwM2MDtlsSessionStore;
import org.thingsboard.server.transport.lwm2m.server.store.TbMainSecurityStore;
@ -118,7 +119,12 @@ public class TbLwM2MDtlsCertificateVerifier implements NewAdvancedCertificateVer
String strCert = SslUtil.getCertificateString(cert);
String sha3Hash = EncryptionUtil.getSha3Hash(strCert);
TbLwM2MSecurityInfo securityInfo = securityInfoValidator.getEndpointSecurityInfoByCredentialsId(sha3Hash, CLIENT);
TbLwM2MSecurityInfo securityInfo;
try {
securityInfo = securityInfoValidator.getEndpointSecurityInfoByCredentialsId(sha3Hash, CLIENT);
} catch (LwM2MAuthException e) {
securityInfo = null;
}
ValidateDeviceCredentialsResponse msg = securityInfo != null ? securityInfo.getMsg() : null;
if (msg != null && org.thingsboard.server.common.data.StringUtils.isNotEmpty(msg.getCredentials())) {
LwM2MCredentials credentials = JacksonUtil.fromString(msg.getCredentials(), LwM2MCredentials.class);

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

@ -65,7 +65,7 @@ import static org.eclipse.californium.scandium.dtls.cipher.CipherSuite.TLS_ECDHE
import static org.eclipse.californium.scandium.dtls.cipher.CipherSuite.TLS_PSK_WITH_AES_128_CBC_SHA256;
import static org.eclipse.californium.scandium.dtls.cipher.CipherSuite.TLS_PSK_WITH_AES_128_CCM_8;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mNetworkConfig.getCoapConfig;
import static org.thingsboard.server.transport.lwm2m.server.ota.DefaultLwM2MOtaUpdateService.FIRMWARE_UPDATE_COAP_RECOURSE;
import static org.thingsboard.server.transport.lwm2m.server.ota.DefaultLwM2MOtaUpdateService.FIRMWARE_UPDATE_COAP_RESOURCE;
@Slf4j
@Component
@ -105,7 +105,7 @@ public class DefaultLwM2mTransportService implements LwM2MTransportService {
* "coap://host:port/{path}/{token}/{nameFile}"
*/
LwM2mTransportCoapResource otaCoapResource = new LwM2mTransportCoapResource(otaPackageDataCache, FIRMWARE_UPDATE_COAP_RECOURSE);
LwM2mTransportCoapResource otaCoapResource = new LwM2mTransportCoapResource(otaPackageDataCache, FIRMWARE_UPDATE_COAP_RESOURCE);
this.server.coap().getServer().add(otaCoapResource);
this.startLhServer();
this.context.setServer(server);

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

@ -23,7 +23,6 @@ import org.jetbrains.annotations.NotNull;
import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.DeviceProfile;
import org.thingsboard.server.common.data.ResourceType;
import org.thingsboard.server.common.data.rpc.RpcStatus;
import org.thingsboard.server.common.transport.SessionMsgListener;
import org.thingsboard.server.common.transport.TransportService;
import org.thingsboard.server.common.transport.TransportServiceCallback;
@ -85,21 +84,7 @@ public class LwM2mSessionMsgListener implements GenericFutureListener<Future<? s
public void onToDeviceRpcRequest(UUID sessionId, ToDeviceRpcRequestMsg toDeviceRequest) {
log.trace("[{}] Received RPC command to device", sessionId);
this.rpcHandler.onToDeviceRpcRequest(toDeviceRequest, this.sessionInfo);
if (toDeviceRequest.getPersisted()) {
RpcStatus status;
if (toDeviceRequest.getOneway()) {
status = RpcStatus.SUCCESSFUL;
} else {
status = RpcStatus.DELIVERED;
}
TransportProtos.ToDevicePersistedRpcResponseMsg responseMsg = TransportProtos.ToDevicePersistedRpcResponseMsg.newBuilder()
.setRequestId(toDeviceRequest.getRequestId())
.setRequestIdLSB(toDeviceRequest.getRequestIdLSB())
.setRequestIdMSB(toDeviceRequest.getRequestIdMSB())
.setStatus(status.name())
.build();
transportService.process(sessionInfo, responseMsg, TransportServiceCallback.EMPTY);
}
transportService.process(sessionInfo, toDeviceRequest, false, TransportServiceCallback.EMPTY);
}
@Override

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

@ -31,8 +31,8 @@ import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicInteger;
import static org.thingsboard.server.transport.lwm2m.server.ota.DefaultLwM2MOtaUpdateService.FIRMWARE_UPDATE_COAP_RECOURSE;
import static org.thingsboard.server.transport.lwm2m.server.ota.DefaultLwM2MOtaUpdateService.SOFTWARE_UPDATE_COAP_RECOURSE;
import static org.thingsboard.server.transport.lwm2m.server.ota.DefaultLwM2MOtaUpdateService.FIRMWARE_UPDATE_COAP_RESOURCE;
import static org.thingsboard.server.transport.lwm2m.server.ota.DefaultLwM2MOtaUpdateService.SOFTWARE_UPDATE_COAP_RESOURCE;
@Slf4j
public class LwM2mTransportCoapResource extends AbstractLwM2mTransportResource {
@ -71,8 +71,8 @@ public class LwM2mTransportCoapResource extends AbstractLwM2mTransportResource {
protected void processHandleGet(CoapExchange exchange) {
log.warn("90) processHandleGet [{}]", exchange);
if (exchange.getRequestOptions().getUriPath().size() >= 2 &&
(FIRMWARE_UPDATE_COAP_RECOURSE.equals(exchange.getRequestOptions().getUriPath().get(exchange.getRequestOptions().getUriPath().size()-2)) ||
SOFTWARE_UPDATE_COAP_RECOURSE.equals(exchange.getRequestOptions().getUriPath().get(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)))) {
this.sendOtaData(exchange);
}
}
@ -131,7 +131,7 @@ public class LwM2mTransportCoapResource extends AbstractLwM2mTransportResource {
}
private void sendOtaData(CoapExchange exchange) {
String idStr = exchange.getRequestOptions().getUriPath().get(exchange.getRequestOptions().getUriPath().size()-1
String idStr = exchange.getRequestOptions().getUriPath().get(exchange.getRequestOptions().getUriPath().size() - 1
);
UUID currentId = UUID.fromString(idStr);
Response response = new Response(CoAP.ResponseCode.CONTENT);
@ -144,8 +144,7 @@ public class LwM2mTransportCoapResource extends AbstractLwM2mTransportResource {
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);
}
else {
} else {
log.warn("92) with block1 Send currentId: [{}], length: [{}], ", currentId.toString(), fwData.length);
}
exchange.respond(response);

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

@ -123,7 +123,7 @@ public class LwM2mTransportUtil {
}
}
public static boolean equalsResourceValue(Object valueOld, Object valueNew, ResourceModel.Type type, LwM2mPath
public static boolean equalsResourceValue(Object valueOld, Object valueNew, ResourceModel.Type type, LwM2mPath
resourcePath) throws CodecException {
switch (type) {
case BOOLEAN:

22
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2MAuthException.java

@ -0,0 +1,22 @@
/**
* 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.client;
public class LwM2MAuthException extends RuntimeException {
private static final long serialVersionUID = 4202690897971364044L;
}

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

@ -32,6 +32,8 @@ import org.eclipse.leshan.server.registration.Registration;
import org.eclipse.leshan.server.security.SecurityInfo;
import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.DeviceProfile;
import org.thingsboard.server.common.data.device.data.Lwm2mDeviceTransportConfiguration;
import org.thingsboard.server.common.data.device.data.PowerMode;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse;
import org.thingsboard.server.gen.transport.TransportProtos.SessionInfoProto;
@ -79,6 +81,9 @@ public class LwM2mClient implements Cloneable {
@Getter
private String deviceProfileName;
@Getter
private PowerMode powerMode;
@Getter
private String identity;
@Getter
@ -121,6 +126,7 @@ public class LwM2mClient implements Cloneable {
this.profileId = new UUID(session.getDeviceProfileIdMSB(), session.getDeviceProfileIdLSB());
this.deviceName = session.getDeviceName();
this.deviceProfileName = session.getDeviceType();
this.powerMode = credentials.getDeviceInfo().getPowerMode();
}
public void lock() {
@ -140,6 +146,7 @@ public class LwM2mClient implements Cloneable {
builder.setDeviceName(deviceName);
deviceProfileOpt.ifPresent(deviceProfile -> updateSession(deviceProfile, builder));
this.session = builder.build();
this.powerMode = ((Lwm2mDeviceTransportConfiguration) device.getDeviceData().getTransportConfiguration()).getPowerMode();
}
public void onDeviceProfileUpdate(DeviceProfile deviceProfile) {

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

@ -87,8 +87,8 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl
public static final String SOFTWARE_TITLE = getAttributeKey(OtaPackageType.SOFTWARE, OtaPackageKey.TITLE);
public static final String SOFTWARE_URL = getAttributeKey(OtaPackageType.SOFTWARE, OtaPackageKey.URL);
public static final String FIRMWARE_UPDATE_COAP_RECOURSE = "tbfw";
public static final String SOFTWARE_UPDATE_COAP_RECOURSE = "tbsw";
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_URL_ID = "/5/0/1";
private static final String FW_EXECUTE_ID = "/5/0/2";
@ -206,7 +206,7 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl
log.debug("[{}] Current fw strategy: {}", client.getEndpoint(), configuration.getFwUpdateStrategy());
LwM2MClientOtaInfo fwInfo = getOrInitFwInfo(client);
fwInfo.setFwStrategy(LwM2MFirmwareUpdateStrategy.fromStrategyFwByCode(configuration.getFwUpdateStrategy()));
fwInfo.setBaseUrl(configuration.getFwUpdateRecourse());
fwInfo.setBaseUrl(configuration.getFwUpdateResource());
startFirmwareUpdateIfNeeded(client, fwInfo);
}
@ -215,7 +215,7 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl
log.debug("[{}] Current sw strategy: {}", client.getEndpoint(), configuration.getSwUpdateStrategy());
LwM2MClientOtaInfo swInfo = getOrInitSwInfo(client);
swInfo.setSwStrategy(LwM2MSoftwareUpdateStrategy.fromStrategySwByCode(configuration.getSwUpdateStrategy()));
swInfo.setBaseUrl(configuration.getSwUpdateRecourse());
swInfo.setBaseUrl(configuration.getSwUpdateResource());
startSoftwareUpdateIfNeeded(client, swInfo);
}
@ -339,7 +339,7 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl
downlinkHandler.sendWriteReplaceRequest(client, writeRequest, new TbLwM2MWriteResponseCallback(uplinkHandler, logService, client, versionedId));
break;
case OBJ_5_TEMP_URL:
startFirmwareUpdateUsingUrl(client, fwInfo.getBaseUrl() + "/" + FIRMWARE_UPDATE_COAP_RECOURSE + "/" + otaPackageId.toString());
startFirmwareUpdateUsingUrl(client, fwInfo.getBaseUrl() + "/" + FIRMWARE_UPDATE_COAP_RESOURCE + "/" + otaPackageId.toString());
break;
default:
sendStateUpdateToTelemetry(client, fwInfo, OtaPackageUpdateStatus.FAILED, "Unsupported strategy: " + strategy.name());
@ -382,7 +382,7 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl
return this.fwStates.computeIfAbsent(client.getEndpoint(), endpoint -> {
var profile = clientContext.getProfile(client.getProfileId());
return new LwM2MClientOtaInfo(endpoint, OtaPackageType.FIRMWARE, profile.getClientLwM2mSettings().getFwUpdateStrategy(),
profile.getClientLwM2mSettings().getFwUpdateRecourse());
profile.getClientLwM2mSettings().getFwUpdateResource());
});
}
@ -390,7 +390,7 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl
//TODO: fetch state from the cache or DB.
return swStates.computeIfAbsent(client.getEndpoint(), endpoint -> {
var profile = clientContext.getProfile(client.getProfileId());
return new LwM2MClientOtaInfo(endpoint, OtaPackageType.SOFTWARE, profile.getClientLwM2mSettings().getSwUpdateStrategy(), profile.getClientLwM2mSettings().getSwUpdateRecourse());
return new LwM2MClientOtaInfo(endpoint, OtaPackageType.SOFTWARE, profile.getClientLwM2mSettings().getSwUpdateStrategy(), profile.getClientLwM2mSettings().getSwUpdateResource());
});
}

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

@ -37,10 +37,10 @@ import org.eclipse.leshan.server.registration.Registration;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.thingsboard.common.util.DonAsynchron;
import org.thingsboard.server.cache.ota.OtaPackageDataCache;
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;
@ -83,8 +83,6 @@ import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MWriteAttrib
import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MWriteAttributesRequest;
import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogService;
import org.thingsboard.server.transport.lwm2m.server.ota.LwM2MOtaUpdateService;
import org.thingsboard.server.transport.lwm2m.server.ota.firmware.LwM2MFirmwareUpdateStrategy;
import org.thingsboard.server.transport.lwm2m.server.ota.software.LwM2MSoftwareUpdateStrategy;
import org.thingsboard.server.transport.lwm2m.server.rpc.LwM2MRpcRequestHandler;
import org.thingsboard.server.transport.lwm2m.server.store.TbLwM2MDtlsSessionStore;
import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl;
@ -203,30 +201,25 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl
executor.submit(() -> {
LwM2mClient lwM2MClient = this.clientContext.getClientByEndpoint(registration.getEndpoint());
try {
log.warn("[{}] [{{}] Client: create after Registration", registration.getEndpoint(), registration.getId());
if (lwM2MClient != null) {
Optional<SessionInfoProto> oldSessionInfo = this.clientContext.register(lwM2MClient, registration);
if (oldSessionInfo.isPresent()) {
log.info("[{}] Closing old session: {}", registration.getEndpoint(), new UUID(oldSessionInfo.get().getSessionIdMSB(), oldSessionInfo.get().getSessionIdLSB()));
closeSession(oldSessionInfo.get());
}
logService.log(lwM2MClient, LOG_LWM2M_INFO + ": Client registered with registration id: " + registration.getId());
SessionInfoProto sessionInfo = lwM2MClient.getSession();
transportService.registerAsyncSession(sessionInfo, new LwM2mSessionMsgListener(this, attributesService, rpcHandler, sessionInfo, transportService));
log.warn("40) sessionId [{}] Registering rpc subscription after Registration client", new UUID(sessionInfo.getSessionIdMSB(), sessionInfo.getSessionIdLSB()));
TransportProtos.TransportToDeviceActorMsg msg = TransportProtos.TransportToDeviceActorMsg.newBuilder()
.setSessionInfo(sessionInfo)
.setSessionEvent(DefaultTransportService.getSessionEventMsg(SessionEvent.OPEN))
.setSubscribeToAttributes(TransportProtos.SubscribeToAttributeUpdatesMsg.newBuilder().setSessionType(TransportProtos.SessionType.ASYNC).build())
.setSubscribeToRPC(TransportProtos.SubscribeToRPCMsg.newBuilder().setSessionType(TransportProtos.SessionType.ASYNC).build())
.build();
transportService.process(msg, null);
this.initClientTelemetry(lwM2MClient);
this.initAttributes(lwM2MClient);
otaService.init(lwM2MClient);
} else {
log.error("Client: [{}] onRegistered [{}] name [{}] lwM2MClient ", registration.getId(), registration.getEndpoint(), null);
log.debug("[{}] [{{}] Client: create after Registration", registration.getEndpoint(), registration.getId());
Optional<SessionInfoProto> oldSessionInfo = this.clientContext.register(lwM2MClient, registration);
if (oldSessionInfo.isPresent()) {
log.info("[{}] Closing old session: {}", registration.getEndpoint(), new UUID(oldSessionInfo.get().getSessionIdMSB(), oldSessionInfo.get().getSessionIdLSB()));
closeSession(oldSessionInfo.get());
}
logService.log(lwM2MClient, LOG_LWM2M_INFO + ": Client registered with registration id: " + registration.getId());
SessionInfoProto sessionInfo = lwM2MClient.getSession();
transportService.registerAsyncSession(sessionInfo, new LwM2mSessionMsgListener(this, attributesService, rpcHandler, sessionInfo, transportService));
TransportProtos.TransportToDeviceActorMsg msg = TransportProtos.TransportToDeviceActorMsg.newBuilder()
.setSessionInfo(sessionInfo)
.setSessionEvent(DefaultTransportService.getSessionEventMsg(SessionEvent.OPEN))
.setSubscribeToAttributes(TransportProtos.SubscribeToAttributeUpdatesMsg.newBuilder().setSessionType(TransportProtos.SessionType.ASYNC).build())
.setSubscribeToRPC(TransportProtos.SubscribeToRPCMsg.newBuilder().setSessionType(TransportProtos.SessionType.ASYNC).build())
.build();
transportService.process(msg, null);
this.initClientTelemetry(lwM2MClient);
this.initAttributes(lwM2MClient);
otaService.init(lwM2MClient);
} catch (LwM2MClientStateException stateException) {
if (LwM2MClientState.UNREGISTERED.equals(stateException.getState())) {
log.info("[{}] retry registration due to race condition: [{}].", registration.getEndpoint(), stateException.getState());
@ -410,6 +403,26 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl
log.trace("[{}] [{}] Received endpoint Awake version event", registration.getId(), registration.getEndpoint());
logService.log(clientContext.getClientByEndpoint(registration.getEndpoint()), LOG_LWM2M_INFO + ": Client is awake!");
//TODO: associate endpointId with device information.
LwM2mClient lwM2MClient = this.clientContext.getClientByEndpoint(registration.getEndpoint());
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 toDeviceActorMsg = TransportProtos.TransportToDeviceActorMsg
.newBuilder()
.setSessionInfo(lwM2MClient.getSession())
.setSendPendingRPC(TransportProtos.SendPendingRPCMsg.newBuilder().build())
.build();
transportService.process(toDeviceActorMsg, TransportServiceCallback.EMPTY);
}
}
}
/**
@ -709,7 +722,6 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl
this.updateResourcesValue(client, resource, path + "/" + resId);
});
}
}
//TODO: review and optimize the logic to minimize number of the requests to device.
@ -781,14 +793,14 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl
OtherConfiguration newLwM2mSettings = newProfile.getClientLwM2mSettings();
OtherConfiguration oldLwM2mSettings = oldProfile.getClientLwM2mSettings();
if (!newLwM2mSettings.getFwUpdateStrategy().equals(oldLwM2mSettings.getFwUpdateStrategy())
|| (StringUtils.isNotEmpty(newLwM2mSettings.getFwUpdateRecourse()) &&
!newLwM2mSettings.getFwUpdateRecourse().equals(oldLwM2mSettings.getFwUpdateRecourse()))) {
|| (StringUtils.isNotEmpty(newLwM2mSettings.getFwUpdateResource()) &&
!newLwM2mSettings.getFwUpdateResource().equals(oldLwM2mSettings.getFwUpdateResource()))) {
clients.forEach(lwM2MClient -> otaService.onCurrentFirmwareStrategyUpdate(lwM2MClient, newLwM2mSettings));
}
if (!newLwM2mSettings.getSwUpdateStrategy().equals(oldLwM2mSettings.getSwUpdateStrategy())
|| (StringUtils.isNotEmpty(newLwM2mSettings.getSwUpdateRecourse()) &&
!newLwM2mSettings.getSwUpdateRecourse().equals(oldLwM2mSettings.getSwUpdateRecourse()))) {
|| (StringUtils.isNotEmpty(newLwM2mSettings.getSwUpdateResource()) &&
!newLwM2mSettings.getSwUpdateResource().equals(oldLwM2mSettings.getSwUpdateResource()))) {
clients.forEach(lwM2MClient -> otaService.onCurrentSoftwareStrategyUpdate(lwM2MClient, newLwM2mSettings));
}
}
@ -920,16 +932,6 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl
}
}
private TransportProtos.GetOtaPackageRequestMsg createOtaPackageRequestMsg(SessionInfoProto sessionInfo, String nameFwSW) {
return TransportProtos.GetOtaPackageRequestMsg.newBuilder()
.setDeviceIdMSB(sessionInfo.getDeviceIdMSB())
.setDeviceIdLSB(sessionInfo.getDeviceIdLSB())
.setTenantIdMSB(sessionInfo.getTenantIdMSB())
.setTenantIdLSB(sessionInfo.getTenantIdLSB())
.setType(nameFwSW)
.build();
}
private Map<String, String> getNamesFromProfileForSharedAttributes(LwM2mClient lwM2MClient) {
Lwm2mDeviceProfileTransportConfiguration profile = clientContext.getProfile(lwM2MClient.getProfileId());
return profile.getObserveAttr().getKeyName();

24
common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttTransportHandler.java

@ -50,7 +50,6 @@ import org.thingsboard.server.common.data.TransportPayloadType;
import org.thingsboard.server.common.data.device.profile.MqttTopics;
import org.thingsboard.server.common.data.id.OtaPackageId;
import org.thingsboard.server.common.data.ota.OtaPackageType;
import org.thingsboard.server.common.data.rpc.RpcStatus;
import org.thingsboard.server.common.msg.EncryptionUtil;
import org.thingsboard.server.common.msg.tools.TbRateLimitsException;
import org.thingsboard.server.common.transport.SessionMsgListener;
@ -820,25 +819,10 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement
.ifPresent(payload -> {
ChannelFuture channelFuture = deviceSessionCtx.getChannel().writeAndFlush(payload);
if (rpcRequest.getPersisted()) {
channelFuture.addListener(future -> {
RpcStatus status;
Throwable t = future.cause();
if (t != null) {
log.error("Failed delivering RPC command to device!", t);
status = RpcStatus.FAILED;
} else if (rpcRequest.getOneway()) {
status = RpcStatus.SUCCESSFUL;
} else {
status = RpcStatus.DELIVERED;
}
TransportProtos.ToDevicePersistedRpcResponseMsg msg = TransportProtos.ToDevicePersistedRpcResponseMsg.newBuilder()
.setRequestId(rpcRequest.getRequestId())
.setRequestIdLSB(rpcRequest.getRequestIdLSB())
.setRequestIdMSB(rpcRequest.getRequestIdMSB())
.setStatus(status.name())
.build();
transportService.process(deviceSessionCtx.getSessionInfo(), msg, TransportServiceCallback.EMPTY);
});
channelFuture.addListener(future ->
transportService.process(deviceSessionCtx.getSessionInfo(), rpcRequest,
future.cause() != null, TransportServiceCallback.EMPTY)
);
}
});
} catch (Exception e) {

23
common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/GatewayDeviceSessionCtx.java

@ -18,7 +18,6 @@ package org.thingsboard.server.transport.mqtt.session;
import io.netty.channel.ChannelFuture;
import lombok.extern.slf4j.Slf4j;
import org.thingsboard.server.common.data.DeviceProfile;
import org.thingsboard.server.common.data.rpc.RpcStatus;
import org.thingsboard.server.common.transport.SessionMsgListener;
import org.thingsboard.server.common.transport.TransportService;
import org.thingsboard.server.common.transport.TransportServiceCallback;
@ -102,25 +101,9 @@ public class GatewayDeviceSessionCtx extends MqttDeviceAwareSessionContext imple
payload -> {
ChannelFuture channelFuture = parent.writeAndFlush(payload);
if (request.getPersisted()) {
channelFuture.addListener(future -> {
RpcStatus status;
Throwable t = future.cause();
if (t != null) {
log.error("Failed delivering RPC command to device!", t);
status = RpcStatus.FAILED;
} else if (request.getOneway()) {
status = RpcStatus.SUCCESSFUL;
} else {
status = RpcStatus.DELIVERED;
}
TransportProtos.ToDevicePersistedRpcResponseMsg msg = TransportProtos.ToDevicePersistedRpcResponseMsg.newBuilder()
.setRequestId(request.getRequestId())
.setRequestIdLSB(request.getRequestIdLSB())
.setRequestIdMSB(request.getRequestIdMSB())
.setStatus(status.name())
.build();
transportService.process(getSessionInfo(), msg, TransportServiceCallback.EMPTY);
});
channelFuture.addListener(future ->
transportService.process(getSessionInfo(), request, future.cause() != null, TransportServiceCallback.EMPTY)
);
}
}
);

21
common/transport/snmp/src/main/java/org/thingsboard/server/transport/snmp/session/DeviceSessionContext.java

@ -26,7 +26,6 @@ import org.thingsboard.server.common.data.DeviceProfile;
import org.thingsboard.server.common.data.device.data.SnmpDeviceTransportConfiguration;
import org.thingsboard.server.common.data.device.profile.SnmpDeviceProfileTransportConfiguration;
import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.common.data.rpc.RpcStatus;
import org.thingsboard.server.common.transport.SessionMsgListener;
import org.thingsboard.server.common.transport.TransportServiceCallback;
import org.thingsboard.server.common.transport.session.DeviceAwareSessionContext;
@ -141,23 +140,9 @@ public class DeviceSessionContext extends DeviceAwareSessionContext implements S
@Override
public void onToDeviceRpcRequest(UUID sessionId, ToDeviceRpcRequestMsg toDeviceRequest) {
log.trace("[{}] Received RPC command to device", sessionId);
snmpTransportContext.getSnmpTransportService().onToDeviceRpcRequest(this, toDeviceRequest);
if (toDeviceRequest.getPersisted()) {
RpcStatus status;
if (toDeviceRequest.getOneway()) {
status = RpcStatus.SUCCESSFUL;
} else {
status = RpcStatus.DELIVERED;
}
TransportProtos.ToDevicePersistedRpcResponseMsg responseMsg = TransportProtos.ToDevicePersistedRpcResponseMsg.newBuilder()
.setRequestId(toDeviceRequest.getRequestId())
.setRequestIdLSB(toDeviceRequest.getRequestIdLSB())
.setRequestIdMSB(toDeviceRequest.getRequestIdMSB())
.setStatus(status.name())
.build();
snmpTransportContext.getTransportService().process(getSessionInfo(), responseMsg, TransportServiceCallback.EMPTY);
}
log.trace("[{}] Received RPC command to device", sessionId);
snmpTransportContext.getSnmpTransportService().onToDeviceRpcRequest(this, toDeviceRequest);
snmpTransportContext.getTransportService().process(getSessionInfo(), toDeviceRequest, false, TransportServiceCallback.EMPTY);
}
@Override

4
common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/TransportService.java

@ -46,7 +46,7 @@ import org.thingsboard.server.gen.transport.TransportProtos.SessionInfoProto;
import org.thingsboard.server.gen.transport.TransportProtos.SubscribeToAttributeUpdatesMsg;
import org.thingsboard.server.gen.transport.TransportProtos.SubscribeToRPCMsg;
import org.thingsboard.server.gen.transport.TransportProtos.SubscriptionInfoProto;
import org.thingsboard.server.gen.transport.TransportProtos.ToDevicePersistedRpcResponseMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToDeviceRpcRequestMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToDeviceRpcResponseMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToServerRpcRequestMsg;
import org.thingsboard.server.gen.transport.TransportProtos.TransportToDeviceActorMsg;
@ -109,7 +109,7 @@ public interface TransportService {
void process(SessionInfoProto sessionInfo, ToServerRpcRequestMsg msg, TransportServiceCallback<Void> callback);
void process(SessionInfoProto sessionInfo, ToDevicePersistedRpcResponseMsg msg, TransportServiceCallback<Void> callback);
void process(SessionInfoProto sessionInfo, ToDeviceRpcRequestMsg msg, boolean isFailedRpc, TransportServiceCallback<Void> callback);
void process(SessionInfoProto sessionInfo, SubscriptionInfoProto msg, TransportServiceCallback<Void> callback);

2
common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/auth/TransportDeviceInfo.java

@ -16,6 +16,7 @@
package org.thingsboard.server.common.transport.auth;
import lombok.Data;
import org.thingsboard.server.common.data.device.data.PowerMode;
import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.common.data.id.DeviceProfileId;
@ -32,6 +33,7 @@ public class TransportDeviceInfo implements Serializable {
private DeviceId deviceId;
private String deviceName;
private String deviceType;
private PowerMode powerMode;
private String additionalInfo;
}

35
common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportService.java

@ -34,7 +34,9 @@ import org.thingsboard.server.common.data.DeviceProfile;
import org.thingsboard.server.common.data.DeviceTransportType;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.ResourceType;
import org.thingsboard.server.common.data.StringUtils;
import org.thingsboard.server.common.data.Tenant;
import org.thingsboard.server.common.data.device.data.PowerMode;
import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.common.data.id.DeviceProfileId;
@ -42,6 +44,7 @@ import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.RuleChainId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.id.TenantProfileId;
import org.thingsboard.server.common.data.rpc.RpcStatus;
import org.thingsboard.server.common.msg.TbMsg;
import org.thingsboard.server.common.msg.TbMsgMetaData;
import org.thingsboard.server.common.msg.queue.ServiceQueue;
@ -439,6 +442,9 @@ public class DefaultTransportService implements TransportService {
tdi.setAdditionalInfo(di.getAdditionalInfo());
tdi.setDeviceName(di.getDeviceName());
tdi.setDeviceType(di.getDeviceType());
if (StringUtils.isNotEmpty(di.getPowerMode())) {
tdi.setPowerMode(PowerMode.valueOf(di.getPowerMode()));
}
return tdi;
}
@ -558,11 +564,30 @@ public class DefaultTransportService implements TransportService {
}
@Override
public void process(TransportProtos.SessionInfoProto sessionInfo, TransportProtos.ToDevicePersistedRpcResponseMsg msg, TransportServiceCallback<Void> callback) {
if (checkLimits(sessionInfo, msg, callback)) {
reportActivityInternal(sessionInfo);
sendToDeviceActor(sessionInfo, TransportToDeviceActorMsg.newBuilder().setSessionInfo(sessionInfo).setPersistedRpcResponseMsg(msg).build(),
new ApiStatsProxyCallback<>(getTenantId(sessionInfo), getCustomerId(sessionInfo), 1, callback));
public void process(TransportProtos.SessionInfoProto sessionInfo, TransportProtos.ToDeviceRpcRequestMsg msg, boolean isFailedRpc, TransportServiceCallback<Void> callback) {
if (msg.getPersisted()) {
RpcStatus status;
if (isFailedRpc) {
status = RpcStatus.FAILED;
} else if (msg.getOneway()) {
status = RpcStatus.SUCCESSFUL;
} else {
status = RpcStatus.DELIVERED;
}
TransportProtos.ToDevicePersistedRpcResponseMsg responseMsg = TransportProtos.ToDevicePersistedRpcResponseMsg.newBuilder()
.setRequestId(msg.getRequestId())
.setRequestIdLSB(msg.getRequestIdLSB())
.setRequestIdMSB(msg.getRequestIdMSB())
.setStatus(status.name())
.build();
if (checkLimits(sessionInfo, responseMsg, callback)) {
reportActivityInternal(sessionInfo);
sendToDeviceActor(sessionInfo, TransportToDeviceActorMsg.newBuilder().setSessionInfo(sessionInfo).setPersistedRpcResponseMsg(responseMsg).build(),
new ApiStatsProxyCallback<>(getTenantId(sessionInfo), getCustomerId(sessionInfo), 1, TransportServiceCallback.EMPTY));
}
}
}

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

@ -133,10 +133,10 @@
</mat-select>
</mat-form-field>
<mat-form-field class="mat-block" fxFlex *ngIf="isFwUpdateStrategy">
<mat-label>{{ 'device-profile.lwm2m.fw-update-recourse' | translate }}</mat-label>
<input matInput formControlName="fwUpdateRecourse" required>
<mat-error *ngIf="lwm2mDeviceProfileFormGroup.get('clientLwM2mSettings.fwUpdateRecourse').hasError('required')">
{{ 'device-profile.lwm2m.fw-update-recourse-required' | translate }}
<mat-label>{{ 'device-profile.lwm2m.fw-update-resource' | translate }}</mat-label>
<input matInput formControlName="fwUpdateResource" required>
<mat-error *ngIf="lwm2mDeviceProfileFormGroup.get('clientLwM2mSettings.fwUpdateResource').hasError('required')">
{{ 'device-profile.lwm2m.fw-update-resource-required' | translate }}
</mat-error>
</mat-form-field>
</fieldset>
@ -150,13 +150,24 @@
</mat-select>
</mat-form-field>
<mat-form-field class="mat-block" fxFlex *ngIf="isSwUpdateStrategy">
<mat-label>{{ 'device-profile.lwm2m.sw-update-recourse' | translate }}</mat-label>
<input matInput formControlName="swUpdateRecourse" required>
<mat-error *ngIf="lwm2mDeviceProfileFormGroup.get('clientLwM2mSettings.swUpdateRecourse').hasError('required')">
{{ 'device-profile.lwm2m.sw-update-recourse-required' | translate }}
<mat-label>{{ 'device-profile.lwm2m.sw-update-resource' | translate }}</mat-label>
<input matInput formControlName="swUpdateResource" required>
<mat-error *ngIf="lwm2mDeviceProfileFormGroup.get('clientLwM2mSettings.swUpdateResource').hasError('required')">
{{ 'device-profile.lwm2m.sw-update-resource-required' | translate }}
</mat-error>
</mat-form-field>
</fieldset>
<fieldset class="fields-group">
<legend class="group-title" translate>device-profile.power-saving-mode</legend>
<mat-form-field class="mat-block" fxFlex>
<mat-label> </mat-label>
<mat-select formControlName="powerMode">
<mat-option *ngFor="let powerMod of powerMods" [value]="powerMod">
{{ powerModeTranslationMap.get(powerMod) | translate}}
</mat-option>
</mat-select>
</mat-form-field>
</fieldset>
<!-- <mat-accordion multi="true">-->
<!-- <div *ngIf="false">-->
<!-- <mat-expansion-panel>-->

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

@ -30,7 +30,8 @@ import {
DEFAULT_NOTIF_IF_DESIBLED,
DEFAULT_SW_UPDATE_RESOURCE,
getDefaultBootstrapServerSecurityConfig,
getDefaultBootstrapServersSecurityConfig, getDefaultLwM2MServerSecurityConfig,
getDefaultBootstrapServersSecurityConfig,
getDefaultLwM2MServerSecurityConfig,
getDefaultProfileClientLwM2mSettingsConfig,
getDefaultProfileObserveAttrConfig,
Instance,
@ -41,7 +42,10 @@ import {
ObjectLwM2M,
OBSERVE,
OBSERVE_ATTR_TELEMETRY,
RESOURCES, ServerSecurityConfig,
PowerMode,
PowerModeTranslationMap,
RESOURCES,
ServerSecurityConfig,
TELEMETRY
} from './lwm2m-profile-config.models';
import { DeviceProfileService } from '@core/http/device-profile.service';
@ -76,6 +80,8 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro
sortFunction: (key: string, value: object) => object;
isFwUpdateStrategy: boolean;
isSwUpdateStrategy: boolean;
powerMods = Object.values(PowerMode);
powerModeTranslationMap = PowerModeTranslationMap;
get required(): boolean {
return this.requiredValue;
@ -109,8 +115,9 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro
clientOnlyObserveAfterConnect: [1, []],
fwUpdateStrategy: [1, []],
swUpdateStrategy: [1, []],
fwUpdateRecourse: [{value: '', disabled: true}, []],
swUpdateRecourse: [{value: '', disabled: true}, []]
fwUpdateResource: [{value: '', disabled: true}, []],
swUpdateResource: [{value: '', disabled: true}, []],
powerMode: [null, Validators.required]
})
});
this.lwm2mDeviceConfigFormGroup = this.fb.group({
@ -120,12 +127,12 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro
takeUntil(this.destroy$)
).subscribe((fwStrategy) => {
if (fwStrategy === 2) {
this.lwm2mDeviceProfileFormGroup.get('clientLwM2mSettings.fwUpdateRecourse').enable({emitEvent: false});
this.lwm2mDeviceProfileFormGroup.get('clientLwM2mSettings.fwUpdateRecourse')
this.lwm2mDeviceProfileFormGroup.get('clientLwM2mSettings.fwUpdateResource').enable({emitEvent: false});
this.lwm2mDeviceProfileFormGroup.get('clientLwM2mSettings.fwUpdateResource')
.patchValue(DEFAULT_FW_UPDATE_RESOURCE, {emitEvent: false});
this.isFwUpdateStrategy = true;
} else {
this.lwm2mDeviceProfileFormGroup.get('clientLwM2mSettings.fwUpdateRecourse').disable({emitEvent: false});
this.lwm2mDeviceProfileFormGroup.get('clientLwM2mSettings.fwUpdateResource').disable({emitEvent: false});
this.isFwUpdateStrategy = false;
}
this.otaUpdateFwStrategyValidate(true);
@ -134,13 +141,13 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro
takeUntil(this.destroy$)
).subscribe((swStrategy) => {
if (swStrategy === 2) {
this.lwm2mDeviceProfileFormGroup.get('clientLwM2mSettings.swUpdateRecourse').enable({emitEvent: false});
this.lwm2mDeviceProfileFormGroup.get('clientLwM2mSettings.swUpdateRecourse')
this.lwm2mDeviceProfileFormGroup.get('clientLwM2mSettings.swUpdateResource').enable({emitEvent: false});
this.lwm2mDeviceProfileFormGroup.get('clientLwM2mSettings.swUpdateResource')
.patchValue(DEFAULT_SW_UPDATE_RESOURCE, {emitEvent: false});
this.isSwUpdateStrategy = true;
} else {
this.isSwUpdateStrategy = false;
this.lwm2mDeviceProfileFormGroup.get('clientLwM2mSettings.swUpdateRecourse').disable({emitEvent: false});
this.lwm2mDeviceProfileFormGroup.get('clientLwM2mSettings.swUpdateResource').disable({emitEvent: false});
}
this.otaUpdateSwStrategyValidate(true);
});
@ -237,10 +244,10 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro
}
private updateWriteValue = (value: ModelValue): void => {
const fwResource = isDefinedAndNotNull(this.configurationValue.clientLwM2mSettings.fwUpdateRecourse) ?
this.configurationValue.clientLwM2mSettings.fwUpdateRecourse : '';
const swResource = isDefinedAndNotNull(this.configurationValue.clientLwM2mSettings.fwUpdateRecourse) ?
this.configurationValue.clientLwM2mSettings.swUpdateRecourse : '';
const fwResource = isDefinedAndNotNull(this.configurationValue.clientLwM2mSettings.fwUpdateResource) ?
this.configurationValue.clientLwM2mSettings.fwUpdateResource : '';
const swResource = isDefinedAndNotNull(this.configurationValue.clientLwM2mSettings.swUpdateResource) ?
this.configurationValue.clientLwM2mSettings.swUpdateResource : '';
this.lwm2mDeviceProfileFormGroup.patchValue({
objectIds: value,
observeAttrTelemetry: this.getObserveAttrTelemetryObjects(value.objectsList),
@ -249,13 +256,14 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro
clientOnlyObserveAfterConnect: this.configurationValue.clientLwM2mSettings.clientOnlyObserveAfterConnect,
fwUpdateStrategy: this.configurationValue.clientLwM2mSettings.fwUpdateStrategy || 1,
swUpdateStrategy: this.configurationValue.clientLwM2mSettings.swUpdateStrategy || 1,
fwUpdateRecourse: fwResource,
swUpdateRecourse: swResource
fwUpdateResource: fwResource,
swUpdateResource: swResource,
powerMode: this.configurationValue.clientLwM2mSettings.powerMode
}
},
{emitEvent: false});
this.configurationValue.clientLwM2mSettings.fwUpdateRecourse = fwResource;
this.configurationValue.clientLwM2mSettings.swUpdateRecourse = swResource;
this.configurationValue.clientLwM2mSettings.fwUpdateResource = fwResource;
this.configurationValue.clientLwM2mSettings.swUpdateResource = swResource;
this.isFwUpdateStrategy = this.configurationValue.clientLwM2mSettings.fwUpdateStrategy === 2;
this.isSwUpdateStrategy = this.configurationValue.clientLwM2mSettings.swUpdateStrategy === 2;
this.otaUpdateSwStrategyValidate();
@ -561,20 +569,20 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro
private otaUpdateFwStrategyValidate(updated = false): void {
if (this.isFwUpdateStrategy) {
this.lwm2mDeviceProfileFormGroup.get('clientLwM2mSettings.fwUpdateRecourse').setValidators([Validators.required]);
this.lwm2mDeviceProfileFormGroup.get('clientLwM2mSettings.fwUpdateResource').setValidators([Validators.required]);
} else {
this.lwm2mDeviceProfileFormGroup.get('clientLwM2mSettings.fwUpdateRecourse').clearValidators();
this.lwm2mDeviceProfileFormGroup.get('clientLwM2mSettings.fwUpdateResource').clearValidators();
}
this.lwm2mDeviceProfileFormGroup.get('clientLwM2mSettings.fwUpdateRecourse').updateValueAndValidity({emitEvent: updated});
this.lwm2mDeviceProfileFormGroup.get('clientLwM2mSettings.fwUpdateResource').updateValueAndValidity({emitEvent: updated});
}
private otaUpdateSwStrategyValidate(updated = false): void {
if (this.isSwUpdateStrategy) {
this.lwm2mDeviceProfileFormGroup.get('clientLwM2mSettings.swUpdateRecourse').setValidators([Validators.required]);
this.lwm2mDeviceProfileFormGroup.get('clientLwM2mSettings.swUpdateResource').setValidators([Validators.required]);
} else {
this.lwm2mDeviceProfileFormGroup.get('clientLwM2mSettings.swUpdateRecourse').clearValidators();
this.lwm2mDeviceProfileFormGroup.get('clientLwM2mSettings.swUpdateResource').clearValidators();
}
this.lwm2mDeviceProfileFormGroup.get('clientLwM2mSettings.swUpdateRecourse').updateValueAndValidity({emitEvent: updated});
this.lwm2mDeviceProfileFormGroup.get('clientLwM2mSettings.swUpdateResource').updateValueAndValidity({emitEvent: updated});
}
}

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

@ -115,6 +115,20 @@ export const securityConfigModeNames = new Map<securityConfigMode, string>(
]
);
export enum PowerMode {
PSM = 'PSM',
DRX = 'DRX',
E_DRX = 'E_DRX'
}
export const PowerModeTranslationMap = new Map<PowerMode, string>(
[
[PowerMode.PSM, 'device-profile.power-saving-mode-type.psm'],
[PowerMode.DRX, 'device-profile.power-saving-mode-type.drx'],
[PowerMode.E_DRX, 'device-profile.power-saving-mode-type.edrx']
]
);
export interface ModelValue {
objectIds: string[];
objectsList: ObjectLwM2M[];
@ -160,8 +174,9 @@ export interface ClientLwM2mSettings {
clientOnlyObserveAfterConnect: number;
fwUpdateStrategy: number;
swUpdateStrategy: number;
fwUpdateRecourse: string;
swUpdateRecourse: string;
fwUpdateResource: string;
swUpdateResource: string;
powerMode: PowerMode;
}
export interface ObservableAttributes {
@ -216,8 +231,9 @@ export function getDefaultProfileClientLwM2mSettingsConfig(): ClientLwM2mSetting
clientOnlyObserveAfterConnect: 1,
fwUpdateStrategy: 1,
swUpdateStrategy: 1,
fwUpdateRecourse: DEFAULT_FW_UPDATE_RESOURCE,
swUpdateRecourse: DEFAULT_SW_UPDATE_RESOURCE
fwUpdateResource: DEFAULT_FW_UPDATE_RESOURCE,
swUpdateResource: DEFAULT_SW_UPDATE_RESOURCE,
powerMode: PowerMode.DRX
};
}

4
ui-ngx/src/app/modules/home/pages/device/data/device-transport-configuration.component.html

@ -29,12 +29,12 @@
formControlName="configuration">
</tb-mqtt-device-transport-configuration>
</ng-template>
<!--ng-template [ngSwitchCase]="deviceTransportType.LWM2M">
<ng-template [ngSwitchCase]="deviceTransportType.LWM2M">
<tb-lwm2m-device-transport-configuration
[required]="required"
formControlName="configuration">
</tb-lwm2m-device-transport-configuration>
</ng-template-->
</ng-template>
<ng-template [ngSwitchCase]="deviceTransportType.COAP">
<tb-coap-device-transport-configuration
[required]="required"

14
ui-ngx/src/app/modules/home/pages/device/data/lwm2m-device-transport-configuration.component.html

@ -16,9 +16,13 @@
-->
<form [formGroup]="lwm2mDeviceTransportConfigurationFormGroup" style="padding-bottom: 16px;">
<!--tb-json-object-edit
[required]="required"
label="{{ 'device-profile.transport-type-lwm2m' | translate }}"
formControlName="configuration">
</tb-json-object-edit-->
<mat-form-field class="mat-block" fxFlex>
<mat-label translate>device-profile.power-saving-mode</mat-label>
<mat-select formControlName="powerMode">
<mat-option [value]="null">{{ "device-profile.power-saving-mode-type.default" | translate }}</mat-option>
<mat-option *ngFor="let powerMod of powerMods" [value]="powerMod">
{{ powerModeTranslationMap.get(powerMod) | translate }}
</mat-option>
</mat-select>
</mat-form-field>
</form>

9
ui-ngx/src/app/modules/home/pages/device/data/lwm2m-device-transport-configuration.component.ts

@ -23,6 +23,7 @@ import {
DeviceTransportConfiguration,
DeviceTransportType, Lwm2mDeviceTransportConfiguration
} from '@shared/models/device.models';
import {PowerMode, PowerModeTranslationMap} from "@home/components/profile/device/lwm2m/lwm2m-profile-config.models";
@Component({
selector: 'tb-lwm2m-device-transport-configuration',
@ -37,6 +38,8 @@ import {
export class Lwm2mDeviceTransportConfigurationComponent implements ControlValueAccessor, OnInit {
lwm2mDeviceTransportConfigurationFormGroup: FormGroup;
powerMods = Object.values(PowerMode);
powerModeTranslationMap = PowerModeTranslationMap;
private requiredValue: boolean;
get required(): boolean {
@ -65,7 +68,7 @@ export class Lwm2mDeviceTransportConfigurationComponent implements ControlValueA
ngOnInit() {
this.lwm2mDeviceTransportConfigurationFormGroup = this.fb.group({
configuration: [null, Validators.required]
powerMode: [null]
});
this.lwm2mDeviceTransportConfigurationFormGroup.valueChanges.subscribe(() => {
this.updateModel();
@ -82,13 +85,13 @@ export class Lwm2mDeviceTransportConfigurationComponent implements ControlValueA
}
writeValue(value: Lwm2mDeviceTransportConfiguration | null): void {
this.lwm2mDeviceTransportConfigurationFormGroup.patchValue({configuration: value}, {emitEvent: false});
this.lwm2mDeviceTransportConfigurationFormGroup.patchValue(value, {emitEvent: false});
}
private updateModel() {
let configuration: DeviceTransportConfiguration = null;
if (this.lwm2mDeviceTransportConfigurationFormGroup.valid) {
configuration = this.lwm2mDeviceTransportConfigurationFormGroup.getRawValue().configuration;
configuration = this.lwm2mDeviceTransportConfigurationFormGroup.getRawValue();
// configuration.type = DeviceTransportType.LWM2M;
}
this.propagateChange(configuration);

2
ui-ngx/src/app/shared/models/device.models.ts

@ -200,7 +200,7 @@ export const deviceTransportTypeConfigurationInfoMap = new Map<DeviceTransportTy
DeviceTransportType.LWM2M,
{
hasProfileConfiguration: true,
hasDeviceConfiguration: false,
hasDeviceConfiguration: true,
}
],
[

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

@ -1213,6 +1213,13 @@
"export-failed-error": "Unable to export device profile: {{error}}",
"device-profile-file": "Device profile file",
"invalid-device-profile-file-error": "Unable to import device profile: Invalid device profile data structure.",
"power-saving-mode": "Power Saving Mode",
"power-saving-mode-type": {
"default": "Use device profile power saving mode",
"psm": "Power Saving Mode (PSM)",
"drx": "Discontinuous Reception (DRX)",
"edrx": "Extended Discontinuous Reception (eDRX)"
},
"lwm2m": {
"object-list": "Object list",
"object-list-empty": "No objects selected.",
@ -1313,10 +1320,10 @@
"sw-update-strategy": "Software update strategy",
"sw-update-strategy-package": "Push binary file using Object 9 and Resource 2 (Package)",
"sw-update-strategy-package-uri": "Auto-generate unique CoAP URL to download the package and push software update using Object 9 and Resource 3 (Package URI)",
"fw-update-recourse": "Firmware update CoAP recourse",
"fw-update-recourse-required": "Firmware update CoAP recourse is required.",
"sw-update-recourse": "Software update CoAP recourse",
"sw-update-recourse-required": "Software update CoAP recourse is required.",
"fw-update-resource": "Firmware update CoAP resource",
"fw-update-resource-required": "Firmware update CoAP resource is required.",
"sw-update-resource": "Software update CoAP resource",
"sw-update-resource-required": "Software update CoAP resource is required.",
"config-json-tab": "Json Config Profile Device",
"attributes-name": {
"min-period": "Minimum period",

Loading…
Cancel
Save