diff --git a/application/src/main/java/org/thingsboard/server/service/transport/DefaultTransportApiService.java b/application/src/main/java/org/thingsboard/server/service/transport/DefaultTransportApiService.java index c09d81bd45..56fb65c4e2 100644 --- a/application/src/main/java/org/thingsboard/server/service/transport/DefaultTransportApiService.java +++ b/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 getEmptyTransportApiResponseFuture() { diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/data/Lwm2mDeviceTransportConfiguration.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/data/Lwm2mDeviceTransportConfiguration.java index 510bfeda7f..085e60212a 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/device/data/Lwm2mDeviceTransportConfiguration.java +++ b/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 properties = new HashMap<>(); diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/data/PowerMode.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/data/PowerMode.java new file mode 100644 index 0000000000..d7323e654a --- /dev/null +++ b/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 +} diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/data/lwm2m/OtherConfiguration.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/data/lwm2m/OtherConfiguration.java index 829180983b..e45a3d0e31 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/device/data/lwm2m/OtherConfiguration.java +++ b/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; } diff --git a/common/queue/src/main/proto/queue.proto b/common/queue/src/main/proto/queue.proto index 049b6934e7..1225e6d824 100644 --- a/common/queue/src/main/proto/queue.proto +++ b/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; } /** diff --git a/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/CoapTransportResource.java b/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/CoapTransportResource.java index 2df86cd68a..56d49fc779 100644 --- a/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/CoapTransportResource.java +++ b/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(); } diff --git a/common/transport/http/src/main/java/org/thingsboard/server/transport/http/DeviceApiController.java b/common/transport/http/src/main/java/org/thingsboard/server/transport/http/DeviceApiController.java index 9122126557..874dd6bdd5 100644 --- a/common/transport/http/src/main/java/org/thingsboard/server/transport/http/DeviceApiController.java +++ b/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 diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/LwM2mCredentialsSecurityInfoValidator.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/LwM2mCredentialsSecurityInfoValidator.java index 067a53514d..bf30723ce0 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/LwM2mCredentialsSecurityInfoValidator.java +++ b/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; } /** diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MAuthorizer.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MAuthorizer.java index cd7f1f3072..5a94a7e3ed 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MAuthorizer.java +++ b/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; diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MDtlsCertificateVerifier.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MDtlsCertificateVerifier.java index 04b69c815f..6710152c60 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MDtlsCertificateVerifier.java +++ b/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); diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/DefaultLwM2mTransportService.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/DefaultLwM2mTransportService.java index c027267197..8059d210dc 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/DefaultLwM2mTransportService.java +++ b/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); diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mSessionMsgListener.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mSessionMsgListener.java index 7ebc6b6808..f5920cbddd 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mSessionMsgListener.java +++ b/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= 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); diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportUtil.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportUtil.java index bbab28ded5..4282531237 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportUtil.java +++ b/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: diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2MAuthException.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2MAuthException.java new file mode 100644 index 0000000000..5d39a0337d --- /dev/null +++ b/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; + +} diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java index dbcb82a167..5fa0858359 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java +++ b/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) { diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ota/DefaultLwM2MOtaUpdateService.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ota/DefaultLwM2MOtaUpdateService.java index d3f1e8eb9d..374633dcef 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/ota/DefaultLwM2MOtaUpdateService.java +++ b/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()); }); } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/DefaultLwM2MUplinkMsgHandler.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/DefaultLwM2MUplinkMsgHandler.java index 1d14de3ba0..e5192501fc 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/DefaultLwM2MUplinkMsgHandler.java +++ b/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 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 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 getNamesFromProfileForSharedAttributes(LwM2mClient lwM2MClient) { Lwm2mDeviceProfileTransportConfiguration profile = clientContext.getProfile(lwM2MClient.getProfileId()); return profile.getObserveAttr().getKeyName(); diff --git a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttTransportHandler.java b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttTransportHandler.java index fb807a43f3..3d073298de 100644 --- a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttTransportHandler.java +++ b/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) { diff --git a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/GatewayDeviceSessionCtx.java b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/GatewayDeviceSessionCtx.java index 754a7afaf2..fb41093c35 100644 --- a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/GatewayDeviceSessionCtx.java +++ b/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) + ); } } ); diff --git a/common/transport/snmp/src/main/java/org/thingsboard/server/transport/snmp/session/DeviceSessionContext.java b/common/transport/snmp/src/main/java/org/thingsboard/server/transport/snmp/session/DeviceSessionContext.java index b8095a6eaf..1fba12782a 100644 --- a/common/transport/snmp/src/main/java/org/thingsboard/server/transport/snmp/session/DeviceSessionContext.java +++ b/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 diff --git a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/TransportService.java b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/TransportService.java index 9c5463e625..a3826f5844 100644 --- a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/TransportService.java +++ b/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 callback); - void process(SessionInfoProto sessionInfo, ToDevicePersistedRpcResponseMsg msg, TransportServiceCallback callback); + void process(SessionInfoProto sessionInfo, ToDeviceRpcRequestMsg msg, boolean isFailedRpc, TransportServiceCallback callback); void process(SessionInfoProto sessionInfo, SubscriptionInfoProto msg, TransportServiceCallback callback); diff --git a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/auth/TransportDeviceInfo.java b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/auth/TransportDeviceInfo.java index 433a5af8ee..f6ef357a93 100644 --- a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/auth/TransportDeviceInfo.java +++ b/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; } diff --git a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportService.java b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportService.java index 3fc0950469..5330021747 100644 --- a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportService.java +++ b/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 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 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)); + } } } diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.html b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.html index 2f51216298..a54a33733d 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.html +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.html @@ -133,10 +133,10 @@ - {{ 'device-profile.lwm2m.fw-update-recourse' | translate }} - - - {{ 'device-profile.lwm2m.fw-update-recourse-required' | translate }} + {{ 'device-profile.lwm2m.fw-update-resource' | translate }} + + + {{ 'device-profile.lwm2m.fw-update-resource-required' | translate }} @@ -150,13 +150,24 @@ - {{ 'device-profile.lwm2m.sw-update-recourse' | translate }} - - - {{ 'device-profile.lwm2m.sw-update-recourse-required' | translate }} + {{ 'device-profile.lwm2m.sw-update-resource' | translate }} + + + {{ 'device-profile.lwm2m.sw-update-resource-required' | translate }} +
+ device-profile.power-saving-mode + + + + + {{ powerModeTranslationMap.get(powerMod) | translate}} + + + +
diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.ts b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.ts index 2d330620ef..f83921fca5 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.ts +++ b/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}); } } diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-profile-config.models.ts b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-profile-config.models.ts index 16e11dcc93..0f419457f0 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-profile-config.models.ts +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-profile-config.models.ts @@ -115,6 +115,20 @@ export const securityConfigModeNames = new Map( ] ); +export enum PowerMode { + PSM = 'PSM', + DRX = 'DRX', + E_DRX = 'E_DRX' +} + +export const PowerModeTranslationMap = new Map( + [ + [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 }; } diff --git a/ui-ngx/src/app/modules/home/pages/device/data/device-transport-configuration.component.html b/ui-ngx/src/app/modules/home/pages/device/data/device-transport-configuration.component.html index dfe34de697..d6d871e4a5 100644 --- a/ui-ngx/src/app/modules/home/pages/device/data/device-transport-configuration.component.html +++ b/ui-ngx/src/app/modules/home/pages/device/data/device-transport-configuration.component.html @@ -29,12 +29,12 @@ formControlName="configuration"> - +
- + + device-profile.power-saving-mode + + {{ "device-profile.power-saving-mode-type.default" | translate }} + + {{ powerModeTranslationMap.get(powerMod) | translate }} + + +
diff --git a/ui-ngx/src/app/modules/home/pages/device/data/lwm2m-device-transport-configuration.component.ts b/ui-ngx/src/app/modules/home/pages/device/data/lwm2m-device-transport-configuration.component.ts index 72ba719873..f74029c2ff 100644 --- a/ui-ngx/src/app/modules/home/pages/device/data/lwm2m-device-transport-configuration.component.ts +++ b/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); diff --git a/ui-ngx/src/app/shared/models/device.models.ts b/ui-ngx/src/app/shared/models/device.models.ts index a766c3a6c3..2c09d64113 100644 --- a/ui-ngx/src/app/shared/models/device.models.ts +++ b/ui-ngx/src/app/shared/models/device.models.ts @@ -200,7 +200,7 @@ export const deviceTransportTypeConfigurationInfoMap = new Map