diff --git a/application/src/main/java/org/thingsboard/server/service/state/DefaultDeviceStateService.java b/application/src/main/java/org/thingsboard/server/service/state/DefaultDeviceStateService.java index c9c54161dd..38f4ee50c7 100644 --- a/application/src/main/java/org/thingsboard/server/service/state/DefaultDeviceStateService.java +++ b/application/src/main/java/org/thingsboard/server/service/state/DefaultDeviceStateService.java @@ -24,6 +24,7 @@ import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListeningExecutorService; import com.google.common.util.concurrent.MoreExecutors; import lombok.Getter; +import lombok.Setter; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; @@ -83,6 +84,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.Optional; import java.util.Random; import java.util.Set; import java.util.UUID; @@ -152,6 +154,7 @@ public class DefaultDeviceStateService extends AbstractPartitionBasedService attributeOpt = attributesService.find(TenantId.SYS_TENANT_ID, deviceStateData.getDeviceId(), SERVER_SCOPE, INACTIVITY_TIMEOUT).get(); + attributeOpt.flatMap(KvEntry::getLongValue).ifPresent((inactivityTimeout) -> { + if (inactivityTimeout > 0) { + deviceStateData.getState().setInactivityTimeout(inactivityTimeout); + } + }); + } catch (Exception e) { + log.warn("[{}] Failed to fetch inactivity timeout from attribute", deviceStateData.getDeviceId(), e); + } + } } private EntityKeyType getKeyType() { diff --git a/application/src/test/java/org/thingsboard/server/service/state/DefaultDeviceStateServiceTest.java b/application/src/test/java/org/thingsboard/server/service/state/DefaultDeviceStateServiceTest.java index d5d74f2512..bc0e067442 100644 --- a/application/src/test/java/org/thingsboard/server/service/state/DefaultDeviceStateServiceTest.java +++ b/application/src/test/java/org/thingsboard/server/service/state/DefaultDeviceStateServiceTest.java @@ -15,27 +15,45 @@ */ package org.thingsboard.server.service.state; +import com.google.common.util.concurrent.Futures; +import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.junit.MockitoJUnitRunner; +import org.thingsboard.server.cluster.TbClusterService; +import org.thingsboard.server.common.data.DeviceIdInfo; import org.thingsboard.server.common.data.id.DeviceId; +import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.kv.BaseAttributeKvEntry; +import org.thingsboard.server.common.data.kv.LongDataEntry; +import org.thingsboard.server.common.data.query.EntityData; +import org.thingsboard.server.common.data.query.EntityKeyType; +import org.thingsboard.server.common.data.query.TsValue; import org.thingsboard.server.dao.attributes.AttributesService; import org.thingsboard.server.dao.device.DeviceService; import org.thingsboard.server.dao.tenant.TenantService; import org.thingsboard.server.dao.timeseries.TimeseriesService; import org.thingsboard.server.queue.discovery.PartitionService; -import org.thingsboard.server.cluster.TbClusterService; import org.thingsboard.server.queue.discovery.TbServiceInfoProvider; +import java.util.Map; +import java.util.Optional; +import java.util.UUID; + import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.MatcherAssert.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.BDDMockito.willReturn; import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; +import static org.mockito.Mockito.when; +import static org.thingsboard.server.common.data.DataConstants.SERVER_SCOPE; +import static org.thingsboard.server.service.state.DefaultDeviceStateService.INACTIVITY_TIMEOUT; @RunWith(MockitoJUnitRunner.class) public class DefaultDeviceStateServiceTest { @@ -83,4 +101,25 @@ public class DefaultDeviceStateServiceTest { Mockito.verify(service, times(1)).fetchDeviceStateDataUsingEntityDataQuery(deviceId); } + @Test + public void givenPersistToTelemetryAndDefaultInactivityTimeoutFetched_whenTransformingToDeviceStateData_thenTryGetInactivityFromAttribute() { + var defaultInactivityTimeoutInSec = 60L; + service.setDefaultInactivityTimeoutInSec(defaultInactivityTimeoutInSec); + service.setPersistToTelemetry(true); + + var deviceUuid = UUID.randomUUID(); + var deviceId = new DeviceId(deviceUuid); + + when(attributesService.find(any(), any(), anyString(), anyString())) + .thenReturn(Futures.immediateFuture(Optional.of(new BaseAttributeKvEntry(0, new LongDataEntry(INACTIVITY_TIMEOUT, 5000L))))); + + var latest = + Map.of(EntityKeyType.TIME_SERIES, Map.of(INACTIVITY_TIMEOUT, new TsValue(0, Long.toString(defaultInactivityTimeoutInSec * 1000)))); + DeviceStateData deviceStateData = service.toDeviceStateData(new EntityData(deviceId, latest, Map.of()), new DeviceIdInfo(TenantId.SYS_TENANT_ID.getId(), UUID.randomUUID(), deviceUuid)); + + Mockito.verify(attributesService, times(1)).find(TenantId.SYS_TENANT_ID, deviceId, SERVER_SCOPE, INACTIVITY_TIMEOUT); + + Assert.assertEquals(5000L, deviceStateData.getState().getInactivityTimeout()); + } + } \ No newline at end of file