diff --git a/application/src/main/java/org/thingsboard/server/service/device/DeviceBulkImportService.java b/application/src/main/java/org/thingsboard/server/service/device/DeviceBulkImportService.java index 2924f8ddeb..d042fb2657 100644 --- a/application/src/main/java/org/thingsboard/server/service/device/DeviceBulkImportService.java +++ b/application/src/main/java/org/thingsboard/server/service/device/DeviceBulkImportService.java @@ -68,6 +68,7 @@ import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; import static org.eclipse.leshan.core.LwM2m.Version.V1_0; +import static org.thingsboard.server.common.data.device.profile.lwm2m.TelemetryObserveStrategy.SINGLE; @Service @TbCoreComponent @@ -258,7 +259,7 @@ public class DeviceBulkImportService extends AbstractBulkImportService { Lwm2mDeviceProfileTransportConfiguration transportConfiguration = new Lwm2mDeviceProfileTransportConfiguration(); transportConfiguration.setBootstrap(Collections.emptyList()); transportConfiguration.setClientLwM2mSettings(new OtherConfiguration(false,1, 1, 1, PowerMode.DRX, null, null, null, null, null, V1_0.toString())); - transportConfiguration.setObserveAttr(new TelemetryMappingConfiguration(Collections.emptyMap(), Collections.emptySet(), Collections.emptySet(), Collections.emptySet(), Collections.emptyMap())); + transportConfiguration.setObserveAttr(new TelemetryMappingConfiguration(Collections.emptyMap(), Collections.emptySet(), Collections.emptySet(), Collections.emptySet(), Collections.emptyMap(), SINGLE)); DeviceProfileData deviceProfileData = new DeviceProfileData(); DefaultDeviceProfileConfiguration configuration = new DefaultDeviceProfileConfiguration(); diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/AbstractLwM2MIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/AbstractLwM2MIntegrationTest.java index 827112cf2a..76f1811b2d 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/AbstractLwM2MIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/AbstractLwM2MIntegrationTest.java @@ -208,6 +208,20 @@ public abstract class AbstractLwM2MIntegrationTest extends AbstractTransportInte " \"pagingTransmissionWindow\": null,\n" + " \"clientOnlyObserveAfterConnect\": 1\n" + " }"; + public static String TELEMETRY_WITH_STRATEGY_COMPOSITE_ALL = + " {\n" + + " \"keyName\": {\n" + + " \"/3_1.2/0/9\": \"batteryLevel\"\n" + + " },\n" + + " \"observe\": [],\n" + + " \"attribute\": [\n" + + " ],\n" + + " \"telemetry\": [\n" + + " \"/3_1.2/0/9\"\n" + + " ],\n" + + " \"attributeLwm2m\": {},\n" + + " \"observeStrategy\": 1\n" + + " }"; protected final Set expectedStatusesRegistrationLwm2mSuccess = new HashSet<>(Arrays.asList(ON_INIT, ON_REGISTRATION_STARTED, ON_REGISTRATION_SUCCESS)); protected final Set expectedStatusesRegistrationLwm2mSuccessUpdate = new HashSet<>(Arrays.asList(ON_INIT, ON_REGISTRATION_STARTED, ON_REGISTRATION_SUCCESS, ON_UPDATE_STARTED, ON_UPDATE_SUCCESS)); protected final Set expectedStatusesRegistrationBsSuccess = new HashSet<>(Arrays.asList(ON_BOOTSTRAP_STARTED, ON_BOOTSTRAP_SUCCESS, ON_REGISTRATION_STARTED, ON_REGISTRATION_SUCCESS)); diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/transportConfiguration/TransportConfigurationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/transportConfiguration/TransportConfigurationTest.java new file mode 100644 index 0000000000..85181c398d --- /dev/null +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/transportConfiguration/TransportConfigurationTest.java @@ -0,0 +1,42 @@ +/** + * Copyright © 2016-2025 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.transportConfiguration; + +import org.junit.Assert; +import org.junit.Test; +import org.thingsboard.server.common.data.device.profile.Lwm2mDeviceProfileTransportConfiguration; +import org.thingsboard.server.transport.lwm2m.security.AbstractSecurityLwM2MIntegrationTest; + +import static org.thingsboard.server.common.data.device.profile.lwm2m.TelemetryObserveStrategy.COMPOSITE_ALL; +import static org.thingsboard.server.common.data.device.profile.lwm2m.TelemetryObserveStrategy.SINGLE; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.LwM2MProfileBootstrapConfigType.NONE; + +public class TransportConfigurationTest extends AbstractSecurityLwM2MIntegrationTest { + + @Test + public void testTransportConfigurationObserveStrategyBeforeParseNullAfterParseNotNull_STRATEGY_SINGLE() throws Exception { + Lwm2mDeviceProfileTransportConfiguration transportConfiguration = getTransportConfiguration(TELEMETRY_WITHOUT_OBSERVE, getBootstrapServerCredentialsNoSec(NONE)); + Assert.assertNotNull(transportConfiguration.getObserveAttr().getObserveStrategy()); + Assert.assertEquals(SINGLE, transportConfiguration.getObserveAttr().getObserveStrategy()); + } + + @Test + public void testTransportConfigurationObserveStrategyBeforeParseNotNullAfterParseNotNull_STRATEGY_COMPOSITE_ALL() throws Exception { + Lwm2mDeviceProfileTransportConfiguration transportConfiguration = getTransportConfiguration(TELEMETRY_WITH_STRATEGY_COMPOSITE_ALL, getBootstrapServerCredentialsNoSec(NONE)); + Assert.assertNotNull(transportConfiguration.getObserveAttr().getObserveStrategy()); + Assert.assertEquals(COMPOSITE_ALL, transportConfiguration.getObserveAttr().getObserveStrategy()); + } +} diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/TelemetryMappingConfiguration.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/TelemetryMappingConfiguration.java index e76f699d7c..1669e1a101 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/TelemetryMappingConfiguration.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/TelemetryMappingConfiguration.java @@ -15,17 +15,18 @@ */ package org.thingsboard.server.common.data.device.profile.lwm2m; -import lombok.AllArgsConstructor; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Data; import lombok.NoArgsConstructor; import java.io.Serializable; +import java.util.Collections; import java.util.Map; import java.util.Set; @Data @NoArgsConstructor -@AllArgsConstructor public class TelemetryMappingConfiguration implements Serializable { private static final long serialVersionUID = -7594999741305410419L; @@ -35,5 +36,22 @@ public class TelemetryMappingConfiguration implements Serializable { private Set attribute; private Set telemetry; private Map attributeLwm2m; + private TelemetryObserveStrategy observeStrategy; + @JsonCreator + public TelemetryMappingConfiguration( + @JsonProperty("keyName") Map keyName, + @JsonProperty("observe") Set observe, + @JsonProperty("attribute") Set attribute, + @JsonProperty("telemetry") Set telemetry, + @JsonProperty("attributeLwm2m") Map attributeLwm2m, + @JsonProperty("observeStrategy") TelemetryObserveStrategy observeStrategy) { + + this.keyName = keyName != null ? keyName : Collections.emptyMap(); + this.observe = observe != null ? observe : Collections.emptySet(); + this.attribute = attribute != null ? attribute : Collections.emptySet(); + this.telemetry = telemetry != null ? telemetry : Collections.emptySet(); + this.attributeLwm2m = attributeLwm2m != null ? attributeLwm2m : Collections.emptyMap(); + this.observeStrategy = observeStrategy != null ? observeStrategy : TelemetryObserveStrategy.SINGLE; + } } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/TelemetryObserveStrategy.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/TelemetryObserveStrategy.java new file mode 100644 index 0000000000..28d571c0b4 --- /dev/null +++ b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/lwm2m/TelemetryObserveStrategy.java @@ -0,0 +1,44 @@ +package org.thingsboard.server.common.data.device.profile.lwm2m; + +import lombok.Getter; + +public enum TelemetryObserveStrategy { + + SINGLE("One resource equals one single observe request", 0), + COMPOSITE_ALL("All resources in one composite observe request", 1), + COMPOSITE_BY_OBJECT("Grouped composite observe requests by object", 2); + + @Getter + private final String description; + + @Getter + private final int id; + + TelemetryObserveStrategy(String description, int id) { + this.description = description; + this.id = id; + } + + public static TelemetryObserveStrategy fromDescription(String description) { + for (TelemetryObserveStrategy strategy : values()) { + if (strategy.description.equalsIgnoreCase(description)) { + return strategy; + } + } + return null; + } + + public static TelemetryObserveStrategy fromId(int id) { + for (TelemetryObserveStrategy strategy : values()) { + if (strategy.id == id) { + return strategy; + } + } + return null; + } + + @Override + public String toString() { + return name() + " (" + id + "): " + description; + } +}