msa: lwm2m tests add NoSec Psk

This commit is contained in:
nick 2024-04-10 14:57:12 +03:00
parent 756bac5135
commit c37b406795
19 changed files with 2925 additions and 3 deletions

View File

@ -186,6 +186,10 @@
<artifactId>allure-testng</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.leshan</groupId>
<artifactId>leshan-client-cf</artifactId>
</dependency>
</dependencies>
<build>
<plugins>

View File

@ -0,0 +1,321 @@
/**
* Copyright © 2016-2024 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.msa;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.eclipse.leshan.client.object.Security;
import org.eclipse.leshan.core.util.Hex;
import org.junit.Assert;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.common.util.ThingsBoardThreadFactory;
import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.DeviceProfile;
import org.thingsboard.server.common.data.DeviceProfileProvisionType;
import org.thingsboard.server.common.data.DeviceProfileType;
import org.thingsboard.server.common.data.DeviceTransportType;
import org.thingsboard.server.common.data.ResourceType;
import org.thingsboard.server.common.data.TbResource;
import org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MBootstrapClientCredentials;
import org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MClientCredential;
import org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MDeviceCredentials;
import org.thingsboard.server.common.data.device.credentials.lwm2m.NoSecBootstrapClientCredential;
import org.thingsboard.server.common.data.device.credentials.lwm2m.NoSecClientCredential;
import org.thingsboard.server.common.data.device.credentials.lwm2m.PSKBootstrapClientCredential;
import org.thingsboard.server.common.data.device.credentials.lwm2m.PSKClientCredential;
import org.thingsboard.server.common.data.device.profile.DefaultDeviceProfileConfiguration;
import org.thingsboard.server.common.data.device.profile.DeviceProfileData;
import org.thingsboard.server.common.data.device.profile.DisabledDeviceProfileProvisionConfiguration;
import org.thingsboard.server.common.data.device.profile.Lwm2mDeviceProfileTransportConfiguration;
import org.thingsboard.server.common.data.device.profile.lwm2m.OtherConfiguration;
import org.thingsboard.server.common.data.device.profile.lwm2m.TelemetryMappingConfiguration;
import org.thingsboard.server.common.data.device.profile.lwm2m.bootstrap.LwM2MBootstrapServerCredential;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.common.data.security.DeviceCredentials;
import org.thingsboard.server.common.data.security.DeviceCredentialsType;
import org.thingsboard.server.msa.connectivity.lwm2m.LwM2MTestClient;
import org.thingsboard.server.msa.connectivity.lwm2m.Lwm2mTestHelper.LwM2MClientState;
import java.net.ServerSocket;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import static org.assertj.core.api.Assertions.assertThat;
import static org.awaitility.Awaitility.await;
import static org.eclipse.leshan.client.object.Security.psk;
import static org.thingsboard.server.msa.connectivity.lwm2m.Lwm2mTestHelper.CLIENT_ENDPOINT_NO_SEC;
import static org.thingsboard.server.msa.connectivity.lwm2m.Lwm2mTestHelper.CLIENT_ENDPOINT_PSK;
import static org.thingsboard.server.msa.connectivity.lwm2m.Lwm2mTestHelper.CLIENT_LWM2M_SETTINGS;
import static org.thingsboard.server.msa.connectivity.lwm2m.Lwm2mTestHelper.CLIENT_PSK_IDENTITY;
import static org.thingsboard.server.msa.connectivity.lwm2m.Lwm2mTestHelper.CLIENT_PSK_KEY;
import static org.thingsboard.server.msa.connectivity.lwm2m.Lwm2mTestHelper.LwM2MClientState.ON_INIT;
import static org.thingsboard.server.msa.connectivity.lwm2m.Lwm2mTestHelper.LwM2MClientState.ON_REGISTRATION_STARTED;
import static org.thingsboard.server.msa.connectivity.lwm2m.Lwm2mTestHelper.LwM2MClientState.ON_REGISTRATION_SUCCESS;
import static org.thingsboard.server.msa.connectivity.lwm2m.Lwm2mTestHelper.LwM2MClientState.ON_UPDATE_SUCCESS;
import static org.thingsboard.server.msa.connectivity.lwm2m.Lwm2mTestHelper.OBSERVE_ATTRIBUTES_WITHOUT_PARAMS;
import static org.thingsboard.server.msa.connectivity.lwm2m.Lwm2mTestHelper.SECURE_URI;
import static org.thingsboard.server.msa.connectivity.lwm2m.Lwm2mTestHelper.SECURITY_NO_SEC;
import static org.thingsboard.server.msa.connectivity.lwm2m.Lwm2mTestHelper.resources;
import static org.thingsboard.server.msa.connectivity.lwm2m.Lwm2mTestHelper.shortServerId;
@Slf4j
public class AbstractLwm2mClientTest extends AbstractContainerTest{
protected ScheduledExecutorService executor;
protected Security security;
protected final PageLink pageLink = new PageLink(30);
protected TenantId tenantId;
protected DeviceProfile lwm2mDeviceProfile;
protected Device lwM2MDeviceTest;
protected LwM2MTestClient lwM2MTestClient;
public final Set<LwM2MClientState> expectedStatusesRegistrationLwm2mSuccess = new HashSet<>(Arrays.asList(ON_INIT, ON_REGISTRATION_STARTED, ON_REGISTRATION_SUCCESS));
public void connectLwm2mClientNoSec() throws Exception {
LwM2MDeviceCredentials deviceCredentials = getDeviceCredentialsNoSec(createNoSecClientCredentials(CLIENT_ENDPOINT_NO_SEC));
basicTestConnection(SECURITY_NO_SEC,
deviceCredentials,
CLIENT_ENDPOINT_NO_SEC,
"TestConnection Lwm2m NoSec (msa)");
}
public void connectLwm2mClientPsk() throws Exception {
String clientEndpoint = CLIENT_ENDPOINT_PSK;
String identity = CLIENT_PSK_IDENTITY;
String keyPsk = CLIENT_PSK_KEY;
PSKClientCredential clientCredentials = new PSKClientCredential();
clientCredentials.setEndpoint(clientEndpoint);
clientCredentials.setIdentity(identity);
clientCredentials.setKey(keyPsk);
Security security = psk(SECURE_URI,
shortServerId,
identity.getBytes(StandardCharsets.UTF_8),
Hex.decodeHex(keyPsk.toCharArray()));
LwM2MDeviceCredentials deviceCredentials = getDeviceCredentialsSecurePsk(clientCredentials);
basicTestConnection(security,
deviceCredentials,
clientEndpoint,
"TestConnection Lwm2m Rpc (msa)");
}
public void basicTestConnection(Security security,
LwM2MDeviceCredentials deviceCredentials,
String clientEndpoint, String alias) throws Exception {
// create lwm2mClient and lwM2MDevice
lwM2MDeviceTest = createDeviceWithCredentials(deviceCredentials, clientEndpoint);
lwM2MTestClient = createNewClient(security, clientEndpoint, executor);
LwM2MClientState finishState = ON_REGISTRATION_SUCCESS;
await(alias + " - " + ON_REGISTRATION_STARTED)
.atMost(40, TimeUnit.SECONDS)
.until(() -> {
log.warn("msa basicTestConnection started -> finishState: [{}] states: {}", finishState, lwM2MTestClient.getClientStates());
return lwM2MTestClient.getClientStates().contains(finishState) || lwM2MTestClient.getClientStates().contains(ON_REGISTRATION_STARTED);
});
await(alias + " - " + ON_UPDATE_SUCCESS)
.atMost(40, TimeUnit.SECONDS)
.until(() -> {
log.warn("msa basicTestConnection update -> finishState: [{}] states: {}", finishState, lwM2MTestClient.getClientStates());
return lwM2MTestClient.getClientStates().contains(finishState) || lwM2MTestClient.getClientStates().contains(ON_UPDATE_SUCCESS);
});
Assert.assertTrue(lwM2MTestClient.getClientStates().containsAll(expectedStatusesRegistrationLwm2mSuccess));
}
public LwM2MTestClient createNewClient(Security security,
String endpoint, ScheduledExecutorService executor) throws Exception {
this.executor = executor;
LwM2MTestClient lwM2MTestClient = new LwM2MTestClient(endpoint);
try (ServerSocket socket = new ServerSocket(0)) {
int clientPort = socket.getLocalPort();
lwM2MTestClient.init(security, clientPort);
}
return lwM2MTestClient;
}
protected void destroyAfter(){
clientDestroy();
deviceDestroy();
deviceProfileDestroy();
if (executor != null) {
executor.shutdown();
}
}
protected void clientDestroy() {
try {
if (lwM2MTestClient != null) {
lwM2MTestClient.destroy();
}
} catch (Exception e) {
log.error("Failed client Destroy", e);
}
}
protected void deviceDestroy() {
try {
if (lwM2MDeviceTest != null) {
testRestClient.deleteDeviceIfExists(lwM2MDeviceTest.getId());
}
} catch (Exception e) {
log.error("Failed device Delete", e);
}
}
protected void initTest(String deviceProfileName) throws Exception {
if (executor != null) {
executor.shutdown();
}
executor = Executors.newScheduledThreadPool(10, ThingsBoardThreadFactory.forName("test-scheduled-" + deviceProfileName));
lwm2mDeviceProfile = getDeviceProfile(deviceProfileName);
tenantId = lwm2mDeviceProfile.getTenantId();
for (String resourceName : resources) {
TbResource lwModel = new TbResource();
lwModel.setResourceType(ResourceType.LWM2M_MODEL);
lwModel.setTitle(resourceName);
lwModel.setFileName(resourceName);
lwModel.setTenantId(tenantId);
byte[] bytes = IOUtils.toByteArray(AbstractLwm2mClientTest.class.getClassLoader().getResourceAsStream("lwm2m-registry/" + resourceName));
lwModel.setData(bytes);
testRestClient.postTbResourceIfNotExists(lwModel);
}
}
protected DeviceProfile getDeviceProfile(String deviceProfileName) throws Exception {
DeviceProfile deviceProfile = getDeviceProfileIfExists(deviceProfileName);
if (deviceProfile == null) {
deviceProfile = testRestClient.postDeviceProfile(createDeviceProfile(deviceProfileName));
}
return deviceProfile;
}
protected DeviceProfile getDeviceProfileIfExists(String deviceProfileName) throws Exception {
return testRestClient.getDeviceProfiles(pageLink).getData().stream()
.filter(x -> x.getName().equals(deviceProfileName))
.findFirst()
.orElse(null);
}
protected DeviceProfile createDeviceProfile(String deviceProfileName) throws Exception {
DeviceProfile deviceProfile = new DeviceProfile();
deviceProfile.setName(deviceProfileName);
deviceProfile.setType(DeviceProfileType.DEFAULT);
deviceProfile.setTransportType(DeviceTransportType.LWM2M);
deviceProfile.setProvisionType(DeviceProfileProvisionType.DISABLED);
deviceProfile.setDescription(deviceProfile.getName());
DeviceProfileData deviceProfileData = new DeviceProfileData();
deviceProfileData.setConfiguration(new DefaultDeviceProfileConfiguration());
deviceProfileData.setProvisionConfiguration(new DisabledDeviceProfileProvisionConfiguration(null));
deviceProfileData.setTransportConfiguration(getTransportConfiguration());
deviceProfile.setProfileData(deviceProfileData);
return deviceProfile;
}
protected void deviceProfileDestroy(){
try {
if (lwm2mDeviceProfile != null) {
testRestClient.deleteDeviceProfileIfExists(lwm2mDeviceProfile);
}
} catch (Exception e) {
log.error("Failed deviceProfile Delete", e);
}
}
protected Device createDeviceWithCredentials(LwM2MDeviceCredentials deviceCredentials, String clientEndpoint) throws Exception {
Device device = createDevice(deviceCredentials, clientEndpoint);
return device;
}
protected Device createDevice(LwM2MDeviceCredentials credentials, String clientEndpoint) throws Exception {
Device device = testRestClient.getDeviceByNameIfExists(clientEndpoint);
if (device == null) {
device = new Device();
device.setName(clientEndpoint);
device.setDeviceProfileId(lwm2mDeviceProfile.getId());
device.setTenantId(tenantId);
device = testRestClient.postDevice("", device);
}
DeviceCredentials deviceCredentials = testRestClient.getDeviceCredentialsByDeviceId(device.getId());
deviceCredentials.setCredentialsType(DeviceCredentialsType.LWM2M_CREDENTIALS);
deviceCredentials.setCredentialsValue(JacksonUtil.toString(credentials));
deviceCredentials = testRestClient.postDeviceCredentials(deviceCredentials);
assertThat(deviceCredentials).isNotNull();
return device;
}
protected LwM2MDeviceCredentials getDeviceCredentialsNoSec(LwM2MClientCredential clientCredentials) {
LwM2MDeviceCredentials credentials = new LwM2MDeviceCredentials();
credentials.setClient(clientCredentials);
LwM2MBootstrapClientCredentials bootstrapCredentials = new LwM2MBootstrapClientCredentials();
NoSecBootstrapClientCredential serverCredentials = new NoSecBootstrapClientCredential();
bootstrapCredentials.setBootstrapServer(serverCredentials);
bootstrapCredentials.setLwm2mServer(serverCredentials);
credentials.setBootstrap(bootstrapCredentials);
return credentials;
}
public NoSecClientCredential createNoSecClientCredentials(String clientEndpoint) {
NoSecClientCredential clientCredentials = new NoSecClientCredential();
clientCredentials.setEndpoint(clientEndpoint);
return clientCredentials;
}
protected Lwm2mDeviceProfileTransportConfiguration getTransportConfiguration() {
List<LwM2MBootstrapServerCredential> bootstrapServerCredentials = new ArrayList<>();
Lwm2mDeviceProfileTransportConfiguration transportConfiguration = new Lwm2mDeviceProfileTransportConfiguration();
TelemetryMappingConfiguration observeAttrConfiguration = JacksonUtil.fromString(OBSERVE_ATTRIBUTES_WITHOUT_PARAMS, TelemetryMappingConfiguration.class);
OtherConfiguration clientLwM2mSettings = JacksonUtil.fromString(CLIENT_LWM2M_SETTINGS, OtherConfiguration.class);
transportConfiguration.setBootstrapServerUpdateEnable(true);
transportConfiguration.setObserveAttr(observeAttrConfiguration);
transportConfiguration.setClientLwM2mSettings(clientLwM2mSettings);
transportConfiguration.setBootstrap(bootstrapServerCredentials);
return transportConfiguration;
}
protected LwM2MDeviceCredentials getDeviceCredentialsSecurePsk(LwM2MClientCredential clientCredentials) {
LwM2MDeviceCredentials credentials = new LwM2MDeviceCredentials();
credentials.setClient(clientCredentials);
LwM2MBootstrapClientCredentials bootstrapCredentials;
bootstrapCredentials = getBootstrapClientCredentialsPsk(clientCredentials);
credentials.setBootstrap(bootstrapCredentials);
return credentials;
}
private LwM2MBootstrapClientCredentials getBootstrapClientCredentialsPsk(LwM2MClientCredential clientCredentials) {
LwM2MBootstrapClientCredentials bootstrapCredentials = new LwM2MBootstrapClientCredentials();
PSKBootstrapClientCredential serverCredentials = new PSKBootstrapClientCredential();
if (clientCredentials != null) {
serverCredentials.setClientSecretKey(((PSKClientCredential) clientCredentials).getKey());
serverCredentials.setClientPublicKeyOrId(((PSKClientCredential) clientCredentials).getIdentity());
}
bootstrapCredentials.setBootstrapServer(serverCredentials);
bootstrapCredentials.setLwm2mServer(serverCredentials);
return bootstrapCredentials;
}
}

View File

@ -23,6 +23,7 @@ import io.restassured.config.RestAssuredConfig;
import io.restassured.filter.log.RequestLoggingFilter;
import io.restassured.filter.log.ResponseLoggingFilter;
import io.restassured.http.ContentType;
import io.restassured.internal.ValidatableResponseImpl;
import io.restassured.path.json.JsonPath;
import io.restassured.response.ValidatableResponse;
import io.restassured.specification.RequestSpecification;
@ -32,6 +33,7 @@ import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.DeviceProfile;
import org.thingsboard.server.common.data.EntityView;
import org.thingsboard.server.common.data.EventInfo;
import org.thingsboard.server.common.data.TbResource;
import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.alarm.Alarm;
import org.thingsboard.server.common.data.asset.Asset;
@ -63,6 +65,7 @@ import java.util.List;
import java.util.Map;
import static io.restassured.RestAssured.given;
import static java.net.HttpURLConnection.HTTP_BAD_REQUEST;
import static java.net.HttpURLConnection.HTTP_NOT_FOUND;
import static java.net.HttpURLConnection.HTTP_OK;
import static org.hamcrest.Matchers.is;
@ -548,6 +551,43 @@ public class TestRestClient {
.as(new TypeRef<>() {});
}
public ValidatableResponse postTbResourceIfNotExists(TbResource lwModel) {
return given().spec(requestSpec).body(lwModel)
.post("/api/resource")
.then()
.statusCode(anyOf(is(HTTP_OK), is(HTTP_BAD_REQUEST)));
}
public void deleteDeviceProfileIfExists(DeviceProfile deviceProfile) {
given().spec(requestSpec)
.delete("/api/deviceProfile/" + deviceProfile.getId().getId().toString())
.then()
.statusCode(anyOf(is(HTTP_OK), is(HTTP_NOT_FOUND)));
}
public Device getDeviceByNameIfExists(String deviceName) {
ValidatableResponse response = given().spec(requestSpec)
.pathParams("deviceName", deviceName)
.get("/api/tenant/devices?deviceName={deviceName}")
.then()
.statusCode(anyOf(is(HTTP_OK), is(HTTP_NOT_FOUND)));
if(((ValidatableResponseImpl) response).extract().response().getStatusCode()==HTTP_OK){
return response.extract()
.as(Device.class);
} else {
return null;
}
}
public DeviceCredentials postDeviceCredentials(DeviceCredentials deviceCredentials) {
return given().spec(requestSpec).body(deviceCredentials)
.post("/api/device/credentials")
.then()
.assertThat()
.statusCode(HTTP_OK)
.extract()
.as(DeviceCredentials.class);
}
private void addTimePageLinkToParam(Map<String, String> params, TimePageLink pageLink) {
this.addPageLinkToParam(params, pageLink);
if (pageLink.getStartTime() != null) {

View File

@ -0,0 +1,45 @@
/**
* Copyright © 2016-2024 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.msa.connectivity;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import org.thingsboard.server.msa.AbstractLwm2mClientTest;
import org.thingsboard.server.msa.DisableUIListeners;
import static org.thingsboard.server.msa.ui.utils.Const.TENANT_EMAIL;
import static org.thingsboard.server.msa.ui.utils.Const.TENANT_PASSWORD;
@DisableUIListeners
public class Lwm2mClientNoSecTest extends AbstractLwm2mClientTest {
@BeforeMethod
public void setUp() throws Exception {
testRestClient.login(TENANT_EMAIL, TENANT_PASSWORD);
initTest("lwm2m-NoSec");
}
@AfterMethod
public void tearDown() {
destroyAfter();
}
@Test
public void connectLwm2mClientNoSecWithLwm2mServer() throws Exception {
connectLwm2mClientNoSec();
}
}

View File

@ -0,0 +1,45 @@
/**
* Copyright © 2016-2024 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.msa.connectivity;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import org.thingsboard.server.msa.AbstractLwm2mClientTest;
import org.thingsboard.server.msa.DisableUIListeners;
import static org.thingsboard.server.msa.ui.utils.Const.TENANT_EMAIL;
import static org.thingsboard.server.msa.ui.utils.Const.TENANT_PASSWORD;
@DisableUIListeners
public class Lwm2mClientPskTest extends AbstractLwm2mClientTest {
@BeforeMethod
public void setUp() throws Exception {
testRestClient.login(TENANT_EMAIL, TENANT_PASSWORD);
initTest("lwm2m-Psk");
}
@AfterMethod
public void tearDown() {
destroyAfter();
}
@Test
public void connectLwm2mClientPskWithLwm2mServer() throws Exception {
connectLwm2mClientPsk();
}
}

View File

@ -0,0 +1,157 @@
/**
* Copyright © 2016-2024 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.msa.connectivity.lwm2m;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.leshan.client.resource.BaseInstanceEnabler;
import org.eclipse.leshan.client.servers.LwM2mServer;
import org.eclipse.leshan.core.model.ObjectModel;
import org.eclipse.leshan.core.node.LwM2mResource;
import org.eclipse.leshan.core.request.argument.Arguments;
import org.eclipse.leshan.core.response.ExecuteResponse;
import org.eclipse.leshan.core.response.ReadResponse;
import org.eclipse.leshan.core.response.WriteResponse;
import org.thingsboard.common.util.ThingsBoardThreadFactory;
import javax.security.auth.Destroyable;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
@Slf4j
public class FwLwM2MDevice extends BaseInstanceEnabler implements Destroyable {
private static final List<Integer> supportedResources = Arrays.asList(0, 1, 2, 3, 5, 6, 7, 9);
private final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(ThingsBoardThreadFactory.forName(getClass().getSimpleName() + "-test-scope"));
private final AtomicInteger state = new AtomicInteger(0);
private final AtomicInteger updateResult = new AtomicInteger(0);
@Override
public ReadResponse read(LwM2mServer identity, int resourceId) {
if (!identity.isSystem())
log.info("Read on Device resource /{}/{}/{}", getModel().id, getId(), resourceId);
switch (resourceId) {
case 3:
return ReadResponse.success(resourceId, getState());
case 5:
return ReadResponse.success(resourceId, getUpdateResult());
case 6:
return ReadResponse.success(resourceId, getPkgName());
case 7:
return ReadResponse.success(resourceId, getPkgVersion());
case 9:
return ReadResponse.success(resourceId, getFirmwareUpdateDeliveryMethod());
default:
return super.read(identity, resourceId);
}
}
@Override
public ExecuteResponse execute(LwM2mServer identity, int resourceId, Arguments arguments) {
String withArguments = "";
if (!arguments.isEmpty())
withArguments = " with arguments " + arguments;
log.info("Execute on Device resource /{}/{}/{} {}", getModel().id, getId(), resourceId, withArguments);
switch (resourceId) {
case 2:
startUpdating();
return ExecuteResponse.success();
default:
return super.execute(identity, resourceId, arguments);
}
}
@Override
public WriteResponse write(LwM2mServer identity, boolean replace, int resourceId, LwM2mResource value) {
log.info("Write on Device resource /{}/{}/{}", getModel().id, getId(), resourceId);
switch (resourceId) {
case 0:
startDownloading();
return WriteResponse.success();
case 1:
startDownloading();
return WriteResponse.success();
default:
return super.write(identity, replace, resourceId, value);
}
}
private int getState() {
return state.get();
}
private int getUpdateResult() {
return updateResult.get();
}
private String getPkgName() {
return "firmware";
}
private String getPkgVersion() {
return "1.0.0";
}
private int getFirmwareUpdateDeliveryMethod() {
return 1;
}
@Override
public List<Integer> getAvailableResourceIds(ObjectModel model) {
return supportedResources;
}
@Override
public void destroy() {
scheduler.shutdownNow();
}
private void startDownloading() {
scheduler.schedule(() -> {
try {
state.set(1);
fireResourceChange(3);
Thread.sleep(100);
state.set(2);
fireResourceChange(3);
} catch (Exception e) {
}
}, 100, TimeUnit.MILLISECONDS);
}
private void startUpdating() {
scheduler.schedule(() -> {
try {
state.set(3);
fireResourceChange(3);
Thread.sleep(100);
updateResult.set(1);
fireResourceChange(5);
} catch (Exception e) {
}
}, 100, TimeUnit.MILLISECONDS);
}
}

View File

@ -0,0 +1,337 @@
/**
* Copyright © 2016-2024 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.msa.connectivity.lwm2m;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.californium.elements.config.Configuration;
import org.eclipse.californium.scandium.config.DtlsConnectorConfig;
import org.eclipse.leshan.client.LeshanClient;
import org.eclipse.leshan.client.LeshanClientBuilder;
import org.eclipse.leshan.client.californium.endpoint.CaliforniumClientEndpointFactory;
import org.eclipse.leshan.client.californium.endpoint.CaliforniumClientEndpointsProvider;
import org.eclipse.leshan.client.californium.endpoint.ClientProtocolProvider;
import org.eclipse.leshan.client.californium.endpoint.coap.CoapOscoreProtocolProvider;
import org.eclipse.leshan.client.californium.endpoint.coaps.CoapsClientEndpointFactory;
import org.eclipse.leshan.client.californium.endpoint.coaps.CoapsClientProtocolProvider;
import org.eclipse.leshan.client.endpoint.LwM2mClientEndpointsProvider;
import org.eclipse.leshan.client.engine.DefaultRegistrationEngineFactory;
import org.eclipse.leshan.client.object.Security;
import org.eclipse.leshan.client.object.Server;
import org.eclipse.leshan.client.observer.LwM2mClientObserver;
import org.eclipse.leshan.client.resource.DummyInstanceEnabler;
import org.eclipse.leshan.client.resource.LwM2mObjectEnabler;
import org.eclipse.leshan.client.resource.ObjectsInitializer;
import org.eclipse.leshan.client.resource.listener.ObjectsListenerAdapter;
import org.eclipse.leshan.client.send.ManualDataSender;
import org.eclipse.leshan.client.servers.LwM2mServer;
import org.eclipse.leshan.core.ResponseCode;
import org.eclipse.leshan.core.model.InvalidDDFFileException;
import org.eclipse.leshan.core.model.LwM2mModel;
import org.eclipse.leshan.core.model.ObjectLoader;
import org.eclipse.leshan.core.model.ObjectModel;
import org.eclipse.leshan.core.model.StaticModel;
import org.eclipse.leshan.core.node.codec.DefaultLwM2mDecoder;
import org.eclipse.leshan.core.node.codec.DefaultLwM2mEncoder;
import org.eclipse.leshan.core.request.BootstrapRequest;
import org.eclipse.leshan.core.request.DeregisterRequest;
import org.eclipse.leshan.core.request.RegisterRequest;
import org.eclipse.leshan.core.request.UpdateRequest;
import org.junit.Assert;
import org.thingsboard.server.msa.connectivity.lwm2m.Lwm2mTestHelper.LwM2MClientState;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import static org.eclipse.californium.scandium.config.DtlsConfig.DTLS_CONNECTION_ID_LENGTH;
import static org.eclipse.californium.scandium.config.DtlsConfig.DTLS_RECOMMENDED_CIPHER_SUITES_ONLY;
import static org.eclipse.leshan.core.LwM2mId.ACCESS_CONTROL;
import static org.eclipse.leshan.core.LwM2mId.DEVICE;
import static org.eclipse.leshan.core.LwM2mId.FIRMWARE;
import static org.eclipse.leshan.core.LwM2mId.SECURITY;
import static org.eclipse.leshan.core.LwM2mId.SERVER;
import static org.thingsboard.server.msa.connectivity.lwm2m.Lwm2mTestHelper.LwM2MClientState.ON_BOOTSTRAP_FAILURE;
import static org.thingsboard.server.msa.connectivity.lwm2m.Lwm2mTestHelper.LwM2MClientState.ON_BOOTSTRAP_STARTED;
import static org.thingsboard.server.msa.connectivity.lwm2m.Lwm2mTestHelper.LwM2MClientState.ON_BOOTSTRAP_SUCCESS;
import static org.thingsboard.server.msa.connectivity.lwm2m.Lwm2mTestHelper.LwM2MClientState.ON_BOOTSTRAP_TIMEOUT;
import static org.thingsboard.server.msa.connectivity.lwm2m.Lwm2mTestHelper.LwM2MClientState.ON_DEREGISTRATION_FAILURE;
import static org.thingsboard.server.msa.connectivity.lwm2m.Lwm2mTestHelper.LwM2MClientState.ON_DEREGISTRATION_STARTED;
import static org.thingsboard.server.msa.connectivity.lwm2m.Lwm2mTestHelper.LwM2MClientState.ON_DEREGISTRATION_SUCCESS;
import static org.thingsboard.server.msa.connectivity.lwm2m.Lwm2mTestHelper.LwM2MClientState.ON_DEREGISTRATION_TIMEOUT;
import static org.thingsboard.server.msa.connectivity.lwm2m.Lwm2mTestHelper.LwM2MClientState.ON_EXPECTED_ERROR;
import static org.thingsboard.server.msa.connectivity.lwm2m.Lwm2mTestHelper.LwM2MClientState.ON_INIT;
import static org.thingsboard.server.msa.connectivity.lwm2m.Lwm2mTestHelper.LwM2MClientState.ON_REGISTRATION_FAILURE;
import static org.thingsboard.server.msa.connectivity.lwm2m.Lwm2mTestHelper.LwM2MClientState.ON_REGISTRATION_STARTED;
import static org.thingsboard.server.msa.connectivity.lwm2m.Lwm2mTestHelper.LwM2MClientState.ON_REGISTRATION_SUCCESS;
import static org.thingsboard.server.msa.connectivity.lwm2m.Lwm2mTestHelper.LwM2MClientState.ON_REGISTRATION_TIMEOUT;
import static org.thingsboard.server.msa.connectivity.lwm2m.Lwm2mTestHelper.LwM2MClientState.ON_UPDATE_FAILURE;
import static org.thingsboard.server.msa.connectivity.lwm2m.Lwm2mTestHelper.LwM2MClientState.ON_UPDATE_STARTED;
import static org.thingsboard.server.msa.connectivity.lwm2m.Lwm2mTestHelper.LwM2MClientState.ON_UPDATE_SUCCESS;
import static org.thingsboard.server.msa.connectivity.lwm2m.Lwm2mTestHelper.LwM2MClientState.ON_UPDATE_TIMEOUT;
import static org.thingsboard.server.msa.connectivity.lwm2m.Lwm2mTestHelper.resources;
import static org.thingsboard.server.msa.connectivity.lwm2m.Lwm2mTestHelper.serverId;
import static org.thingsboard.server.msa.connectivity.lwm2m.Lwm2mTestHelper.shortServerId;
@Slf4j
@Data
public class LwM2MTestClient {
private final String endpoint;
private LeshanClient leshanClient;
private SimpleLwM2MDevice lwM2MDevice;
private Set<LwM2MClientState> clientStates;
private FwLwM2MDevice fwLwM2MDevice;
private Map<LwM2MClientState, Integer> clientDtlsCid;
public void init(Security security, int clientPort) throws InvalidDDFFileException, IOException {
Assert.assertNull("client already initialized", leshanClient);
List<ObjectModel> models = new ArrayList<>();
for (String resourceName : resources) {
models.addAll(ObjectLoader.loadDdfFile(LwM2MTestClient.class.getClassLoader().getResourceAsStream("lwm2m-registry/" + resourceName), resourceName));
}
LwM2mModel model = new StaticModel(models);
ObjectsInitializer initializer = new ObjectsInitializer(model);
// SECURITY
initializer.setInstancesForObject(SECURITY, security);
// SERVER
Server lwm2mServer = new Server(shortServerId, 300);
lwm2mServer.setId(serverId);
initializer.setInstancesForObject(SERVER, lwm2mServer);
initializer.setInstancesForObject(DEVICE, lwM2MDevice = new SimpleLwM2MDevice());
initializer.setClassForObject(ACCESS_CONTROL, DummyInstanceEnabler.class);
initializer.setInstancesForObject(FIRMWARE, fwLwM2MDevice = new FwLwM2MDevice());
List<LwM2mObjectEnabler> enablers = initializer.createAll();
// Create Californium Endpoints Provider:
// --------------------------------------
// Define Custom CoAPS protocol provider
CoapsClientProtocolProvider customCoapsProtocolProvider = new CoapsClientProtocolProvider() {
@Override
public CaliforniumClientEndpointFactory createDefaultEndpointFactory() {
return new CoapsClientEndpointFactory() {
@Override
protected DtlsConnectorConfig.Builder createRootDtlsConnectorConfigBuilder(
Configuration configuration) {
DtlsConnectorConfig.Builder builder = super.createRootDtlsConnectorConfigBuilder(configuration);
return builder;
};
};
}
};
// Create client endpoints Provider
List<ClientProtocolProvider> protocolProvider = new ArrayList<>();
/**
* "Use java-coap for CoAP protocol instead of Californium."
*/
protocolProvider.add(new CoapOscoreProtocolProvider());
protocolProvider.add(customCoapsProtocolProvider);
CaliforniumClientEndpointsProvider.Builder endpointsBuilder = new CaliforniumClientEndpointsProvider.Builder(
protocolProvider.toArray(new ClientProtocolProvider[protocolProvider.size()]));
// Create Californium Configuration
Configuration clientCoapConfig = endpointsBuilder.createDefaultConfiguration();
// Set some DTLS stuff
// These configuration values are always overwritten by CLI therefore set them to transient.
clientCoapConfig.setTransient(DTLS_RECOMMENDED_CIPHER_SUITES_ONLY);
clientCoapConfig.setTransient(DTLS_CONNECTION_ID_LENGTH);
boolean supportDeprecatedCiphers = false;
clientCoapConfig.set(DTLS_RECOMMENDED_CIPHER_SUITES_ONLY, !supportDeprecatedCiphers);
// Set Californium Configuration
endpointsBuilder.setConfiguration(clientCoapConfig);
endpointsBuilder.setClientAddress(new InetSocketAddress(clientPort).getAddress());
// creates EndpointsProvider
List<LwM2mClientEndpointsProvider> endpointsProvider = new ArrayList<>();
endpointsProvider.add(endpointsBuilder.build());
// Configure Registration Engine
DefaultRegistrationEngineFactory engineFactory = new DefaultRegistrationEngineFactory();
/**
* Force reconnection/rehandshake on registration update.
*/
int comPeriodInSec = 5;
if (comPeriodInSec > 0) engineFactory.setCommunicationPeriod(comPeriodInSec * 1000);
/**
* By default client will try to resume DTLS session by using abbreviated Handshake. This option force to always do a full handshake."
*/
boolean reconnectOnUpdate = false;
engineFactory.setReconnectOnUpdate(reconnectOnUpdate);
engineFactory.setResumeOnConnect(true);
/**
* Client use queue mode.
*/
engineFactory.setQueueMode(false);
// Create client
LeshanClientBuilder builder = new LeshanClientBuilder(endpoint);
builder.setObjects(enablers);
builder.setEndpointsProviders(endpointsProvider.toArray(new LwM2mClientEndpointsProvider[endpointsProvider.size()]));
builder.setDataSenders(new ManualDataSender());
builder.setRegistrationEngineFactory(engineFactory);
boolean supportOldFormat = true;
if (supportOldFormat) {
builder.setDecoder(new DefaultLwM2mDecoder(supportOldFormat));
builder.setEncoder(new DefaultLwM2mEncoder(new LwM2mValueConverterImpl(), supportOldFormat));
}
builder.setRegistrationEngineFactory(engineFactory);
// builder.setSharedExecutor(executor);
clientStates = new HashSet<>();
clientDtlsCid = new HashMap<>();
clientStates.add(ON_INIT);
leshanClient = builder.build();
LwM2mClientObserver observer = new LwM2mClientObserver() {
@Override
public void onBootstrapStarted(LwM2mServer bsserver, BootstrapRequest request) {
clientStates.add(ON_BOOTSTRAP_STARTED);
}
@Override
public void onBootstrapSuccess(LwM2mServer bsserver, BootstrapRequest request) {
clientStates.add(ON_BOOTSTRAP_SUCCESS);
}
@Override
public void onBootstrapFailure(LwM2mServer bsserver, BootstrapRequest request, ResponseCode responseCode, String errorMessage, Exception cause) {
clientStates.add(ON_BOOTSTRAP_FAILURE);
}
@Override
public void onBootstrapTimeout(LwM2mServer bsserver, BootstrapRequest request) {
clientStates.add(ON_BOOTSTRAP_TIMEOUT);
}
@Override
public void onRegistrationStarted(LwM2mServer server, RegisterRequest request) {
clientStates.add(ON_REGISTRATION_STARTED);
}
@Override
public void onRegistrationSuccess(LwM2mServer server, RegisterRequest request, String registrationID) {
clientStates.add(ON_REGISTRATION_SUCCESS);
}
@Override
public void onRegistrationFailure(LwM2mServer server, RegisterRequest request, ResponseCode responseCode, String errorMessage, Exception cause) {
clientStates.add(ON_REGISTRATION_FAILURE);
}
@Override
public void onRegistrationTimeout(LwM2mServer server, RegisterRequest request) {
clientStates.add(ON_REGISTRATION_TIMEOUT);
}
@Override
public void onUpdateStarted(LwM2mServer server, UpdateRequest request) {
clientStates.add(ON_UPDATE_STARTED);
}
@Override
public void onUpdateSuccess(LwM2mServer server, UpdateRequest request) {
clientStates.add(ON_UPDATE_SUCCESS);
}
@Override
public void onUpdateFailure(LwM2mServer server, UpdateRequest request, ResponseCode responseCode, String errorMessage, Exception cause) {
clientStates.add(ON_UPDATE_FAILURE);
}
@Override
public void onUpdateTimeout(LwM2mServer server, UpdateRequest request) {
clientStates.add(ON_UPDATE_TIMEOUT);
}
@Override
public void onDeregistrationStarted(LwM2mServer server, DeregisterRequest request) {
clientStates.add(ON_DEREGISTRATION_STARTED);
}
@Override
public void onDeregistrationSuccess(LwM2mServer server, DeregisterRequest request) {
clientStates.add(ON_DEREGISTRATION_SUCCESS);
}
@Override
public void onDeregistrationFailure(LwM2mServer server, DeregisterRequest request, ResponseCode responseCode, String errorMessage, Exception cause) {
clientStates.add(ON_DEREGISTRATION_FAILURE);
}
@Override
public void onDeregistrationTimeout(LwM2mServer server, DeregisterRequest request) {
clientStates.add(ON_DEREGISTRATION_TIMEOUT);
}
@Override
public void onUnexpectedError(Throwable unexpectedError) {
clientStates.add(ON_EXPECTED_ERROR);
}
};
this.leshanClient.addObserver(observer);
// Add some log about object tree life cycle.
this.leshanClient.getObjectTree().addListener(new ObjectsListenerAdapter() {
@Override
public void objectRemoved(LwM2mObjectEnabler object) {
log.info("Object {} v{} disabled.", object.getId(), object.getObjectModel().version);
}
@Override
public void objectAdded(LwM2mObjectEnabler object) {
log.info("Object {} v{} enabled.", object.getId(), object.getObjectModel().version);
}
});
leshanClient.start();
}
public void destroy() {
if (leshanClient != null) {
leshanClient.destroy(true);
}
if (lwM2MDevice != null) {
lwM2MDevice.destroy();
}
if (fwLwM2MDevice != null) {
fwLwM2MDevice.destroy();
}
}
}

View File

@ -0,0 +1,192 @@
/**
* Copyright © 2016-2024 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.msa.connectivity.lwm2m;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.leshan.core.model.ResourceModel.Type;
import org.eclipse.leshan.core.node.LwM2mPath;
import org.eclipse.leshan.core.node.ObjectLink;
import org.eclipse.leshan.core.node.codec.CodecException;
import org.eclipse.leshan.core.node.codec.LwM2mValueConverter;
import org.eclipse.leshan.core.util.Hex;
import org.thingsboard.server.common.data.StringUtils;
import java.math.BigInteger;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Base64;
import java.util.Date;
import static org.eclipse.leshan.core.model.ResourceModel.Type.OPAQUE;
@Slf4j
public class LwM2mValueConverterImpl implements LwM2mValueConverter {
private static final LwM2mValueConverterImpl INSTANCE = new LwM2mValueConverterImpl();
public static LwM2mValueConverterImpl getInstance() {
return INSTANCE;
}
@Override
public Object convertValue(Object value, Type currentType, Type expectedType, LwM2mPath resourcePath)
throws CodecException {
if (value == null) {
return null;
}
if (expectedType == null) {
/** unknown resource, trusted value */
return value;
}
if (currentType == expectedType) {
/** expected type */
return value;
}
if (currentType == null) {
currentType = OPAQUE;
}
switch (expectedType) {
case INTEGER:
switch (currentType) {
case FLOAT:
log.debug("Trying to convert float value [{}] to Integer", value);
Long longValue = ((Double) value).longValue();
if ((double) value == longValue.doubleValue()) {
return longValue;
}
case STRING:
log.debug("Trying to convert String value [{}] to Integer", value);
return Long.parseLong((String) value);
default:
break;
}
break;
case FLOAT:
switch (currentType) {
case INTEGER:
log.debug("Trying to convert integer value [{}] to float", value);
Double floatValue = ((Long) value).doubleValue();
if ((long) value == floatValue.longValue()) {
return floatValue;
}
case STRING:
log.debug("Trying to convert String value [{}] to Float", value);
return Float.valueOf((String) value);
default:
break;
}
break;
case BOOLEAN:
switch (currentType) {
case STRING:
log.debug("Trying to convert string value {} to boolean", value);
if (StringUtils.equalsIgnoreCase((String) value, "true")) {
return true;
} else if (StringUtils.equalsIgnoreCase((String) value, "false")) {
return false;
}
break;
case INTEGER:
log.debug("Trying to convert int value {} to boolean", value);
Long val = (Long) value;
if (val == 1) {
return true;
} else if (val == 0) {
return false;
}
break;
default:
break;
}
break;
case TIME:
switch (currentType) {
case INTEGER:
log.debug("Trying to convert long value {} to date", value);
/* let's assume we received the millisecond since 1970/1/1 */
return new Date(((Number) value).longValue() * 1000L);
case STRING:
log.debug("Trying to convert string value {} to date", value);
/** let's assume we received an ISO 8601 format date */
try {
return new Date(Long.decode(value.toString()));
/**
DatatypeFactory datatypeFactory = DatatypeFactory.newInstance();
XMLGregorianCalendar cal = datatypeFactory.newXMLGregorianCalendar((String) value);
return cal.toGregorianCalendar().getTime();
**/
} catch (IllegalArgumentException e) {
log.debug("Unable to convert string to date", e);
throw new CodecException("Unable to convert string (%s) to date for resource %s", value,
resourcePath);
}
default:
break;
}
break;
case STRING:
switch (currentType) {
case BOOLEAN:
case INTEGER:
case FLOAT:
return String.valueOf(value);
case TIME:
String DATE_FORMAT = "MMM d, yyyy HH:mm a";
Long timeValue;
try {
timeValue = ((Date) value).getTime();
}
catch (Exception e){
timeValue = new BigInteger((byte [])value).longValue();
}
DateFormat formatter = new SimpleDateFormat(DATE_FORMAT);
return formatter.format(new Date(timeValue));
case OPAQUE:
return Hex.encodeHexString((byte[])value);
case OBJLNK:
return ObjectLink.decodeFromString((String) value);
default:
break;
}
break;
case OPAQUE:
if (currentType == Type.STRING) {
/** let's assume we received an hexadecimal string */
log.debug("Trying to convert hexadecimal/base64 string [{}] to byte array", value);
try {
return Hex.decodeHex(((String)value).toCharArray());
} catch (IllegalArgumentException e) {
try {
return Base64.getDecoder().decode((String) value);
} catch (IllegalArgumentException ea) {
throw new CodecException("Unable to convert hexastring or base64 [%s] to byte array for resource %s",
value, resourcePath);
}
}
}
break;
case OBJLNK:
if (currentType == Type.STRING) {
return ObjectLink.fromPath(value.toString());
}
default:
}
throw new CodecException("Invalid value type for resource %s, expected %s, got %s", resourcePath, expectedType,
currentType);
}
}

View File

@ -0,0 +1,134 @@
/**
* Copyright © 2016-2024 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.msa.connectivity.lwm2m;
import org.eclipse.californium.elements.config.Configuration;
import org.eclipse.leshan.client.object.Security;
import static org.eclipse.californium.scandium.config.DtlsConfig.DTLS_CONNECTION_ID_LENGTH;
import static org.eclipse.californium.scandium.config.DtlsConfig.DTLS_CONNECTION_ID_NODE_ID;
import static org.eclipse.leshan.client.object.Security.noSec;
public class Lwm2mTestHelper {
// Models
public static final String[] resources = new String[]{ "0.xml", "1.xml", "2.xml", "3.xml", "5.xml"};
public static final int serverId = 1;
public static final int port = 5685;
public static final int securityPort = 5686;
public static final Integer shortServerId = 123;
public static final String host = "localhost";
public static final String COAP = "coap://";
public static final String COAPS = "coaps://";
public static final String URI = COAP + host + ":" + port;
public static final String SECURE_URI = COAPS + host + ":" + securityPort;
public static final String CLIENT_ENDPOINT_NO_SEC = "LwNoSec00000000";
public static final Security SECURITY_NO_SEC = noSec(URI, shortServerId);
public static final String CLIENT_ENDPOINT_PSK = "LwPsk00000000";
public static final String CLIENT_PSK_IDENTITY = "SOME_PSK_ID";
public static final String CLIENT_PSK_KEY = "73656372657450534b73656372657450";
public static final String OBSERVE_ATTRIBUTES_WITHOUT_PARAMS =
" {\n" +
" \"keyName\": {},\n" +
" \"observe\": [],\n" +
" \"attribute\": [],\n" +
" \"telemetry\": [],\n" +
" \"attributeLwm2m\": {}\n" +
" }";
public static final String CLIENT_LWM2M_SETTINGS =
" {\n" +
" \"edrxCycle\": null,\n" +
" \"powerMode\": \"DRX\",\n" +
" \"fwUpdateResource\": null,\n" +
" \"fwUpdateStrategy\": 1,\n" +
" \"psmActivityTimer\": null,\n" +
" \"swUpdateResource\": null,\n" +
" \"swUpdateStrategy\": 1,\n" +
" \"pagingTransmissionWindow\": null,\n" +
" \"clientOnlyObserveAfterConnect\": 1\n" +
" }";
public static final int BINARY_APP_DATA_CONTAINER = 19;
public static final int OBJECT_INSTANCE_ID_0 = 0;
public static final int OBJECT_INSTANCE_ID_1 = 1;
public enum LwM2MClientState {
ON_INIT(0, "onInit"),
ON_BOOTSTRAP_STARTED(1, "onBootstrapStarted"),
ON_BOOTSTRAP_SUCCESS(2, "onBootstrapSuccess"),
ON_BOOTSTRAP_FAILURE(3, "onBootstrapFailure"),
ON_BOOTSTRAP_TIMEOUT(4, "onBootstrapTimeout"),
ON_REGISTRATION_STARTED(5, "onRegistrationStarted"),
ON_REGISTRATION_SUCCESS(6, "onRegistrationSuccess"),
ON_REGISTRATION_FAILURE(7, "onRegistrationFailure"),
ON_REGISTRATION_TIMEOUT(7, "onRegistrationTimeout"),
ON_UPDATE_STARTED(8, "onUpdateStarted"),
ON_UPDATE_SUCCESS(9, "onUpdateSuccess"),
ON_UPDATE_FAILURE(10, "onUpdateFailure"),
ON_UPDATE_TIMEOUT(11, "onUpdateTimeout"),
ON_DEREGISTRATION_STARTED(12, "onDeregistrationStarted"),
ON_DEREGISTRATION_SUCCESS(13, "onDeregistrationSuccess"),
ON_DEREGISTRATION_FAILURE(14, "onDeregistrationFailure"),
ON_DEREGISTRATION_TIMEOUT(15, "onDeregistrationTimeout"),
ON_EXPECTED_ERROR(16, "onUnexpectedError"),
ON_READ_CONNECTION_ID (17, "onReadConnection"),
ON_WRITE_CONNECTION_ID (18, "onWriteConnection");
public int code;
public String type;
LwM2MClientState(int code, String type) {
this.code = code;
this.type = type;
}
public static LwM2MClientState fromLwM2MClientStateByType(String type) {
for (LwM2MClientState to : LwM2MClientState.values()) {
if (to.type.equals(type)) {
return to;
}
}
throw new IllegalArgumentException(String.format("Unsupported Client State type : %s", type));
}
public static LwM2MClientState fromLwM2MClientStateByCode(int code) {
for (LwM2MClientState to : LwM2MClientState.values()) {
if (to.code == code) {
return to;
}
}
throw new IllegalArgumentException(String.format("Unsupported Client State code : %s", code));
}
}
public static void setDtlsConnectorConfigCidLength(Configuration serverCoapConfig, Integer cIdLength) {
serverCoapConfig.setTransient(DTLS_CONNECTION_ID_LENGTH);
serverCoapConfig.setTransient(DTLS_CONNECTION_ID_NODE_ID);
serverCoapConfig.set(DTLS_CONNECTION_ID_LENGTH, cIdLength);
if ( cIdLength > 4) {
serverCoapConfig.set(DTLS_CONNECTION_ID_NODE_ID, 0);
} else {
serverCoapConfig.set(DTLS_CONNECTION_ID_NODE_ID, null);
}
}
}

View File

@ -0,0 +1,218 @@
/**
* Copyright © 2016-2024 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.msa.connectivity.lwm2m;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.leshan.client.resource.BaseInstanceEnabler;
import org.eclipse.leshan.client.servers.LwM2mServer;
import org.eclipse.leshan.core.Destroyable;
import org.eclipse.leshan.core.model.ObjectModel;
import org.eclipse.leshan.core.model.ResourceModel;
import org.eclipse.leshan.core.node.LwM2mResource;
import org.eclipse.leshan.core.request.argument.Arguments;
import org.eclipse.leshan.core.response.ExecuteResponse;
import org.eclipse.leshan.core.response.ReadResponse;
import org.eclipse.leshan.core.response.WriteResponse;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Calendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.PrimitiveIterator;
import java.util.Random;
import java.util.TimeZone;
@Slf4j
public class SimpleLwM2MDevice extends BaseInstanceEnabler implements Destroyable {
private static final Random RANDOM = new Random();
private static final int min = 5;
private static final int max = 50;
private static final PrimitiveIterator.OfInt randomIterator = new Random().ints(min,max + 1).iterator();
private static final List<Integer> supportedResources = Arrays.asList(0, 1, 2, 3, 6, 7, 8, 9, 10, 11, 13, 14, 15, 16, 17, 18, 19, 20, 21);
public SimpleLwM2MDevice() {
}
@Override
public ReadResponse read(LwM2mServer identity, int resourceId) {
if (!identity.isSystem())
log.info("Read on Device resource /{}/{}/{}", getModel().id, getId(), resourceId);
switch (resourceId) {
case 0:
return ReadResponse.success(resourceId, getManufacturer());
case 1:
return ReadResponse.success(resourceId, getModelNumber());
case 2:
return ReadResponse.success(resourceId, getSerialNumber());
case 3:
return ReadResponse.success(resourceId, getFirmwareVersion());
case 6:
return ReadResponse.success(resourceId, getAvailablePowerSources(), ResourceModel.Type.INTEGER);
case 9:
return ReadResponse.success(resourceId, getBatteryLevel());
case 10:
return ReadResponse.success(resourceId, getMemoryFree());
case 11:
Map<Integer, Long> errorCodes = new HashMap<>();
errorCodes.put(0, getErrorCode());
return ReadResponse.success(resourceId, errorCodes, ResourceModel.Type.INTEGER);
case 14:
return ReadResponse.success(resourceId, getUtcOffset());
case 15:
return ReadResponse.success(resourceId, getTimezone());
case 16:
return ReadResponse.success(resourceId, getSupportedBinding());
case 17:
return ReadResponse.success(resourceId, getDeviceType());
case 18:
return ReadResponse.success(resourceId, getHardwareVersion());
case 19:
return ReadResponse.success(resourceId, getSoftwareVersion());
case 20:
return ReadResponse.success(resourceId, getBatteryStatus());
case 21:
return ReadResponse.success(resourceId, getMemoryTotal());
default:
return super.read(identity, resourceId);
}
}
@Override
public ExecuteResponse execute(LwM2mServer identity, int resourceId, Arguments arguments) {
String withArguments = "";
if (!arguments.isEmpty())
withArguments = " with arguments " + arguments;
log.info("Execute on Device resource /{}/{}/{} {}", getModel().id, getId(), resourceId, withArguments);
return ExecuteResponse.success();
}
@Override
public WriteResponse write(LwM2mServer identity, boolean replace, int resourceId, LwM2mResource value) {
log.info("Write on Device resource /{}/{}/{}", getModel().id, getId(), resourceId);
switch (resourceId) {
case 13:
return WriteResponse.notFound();
case 14:
setUtcOffset((String) value.getValue());
fireResourceChange(resourceId);
return WriteResponse.success();
case 15:
setTimezone((String) value.getValue());
fireResourceChange(resourceId);
return WriteResponse.success();
default:
return super.write(identity, replace, resourceId, value);
}
}
private String getManufacturer() {
return "Thingsboard Demo Lwm2mDevice";
}
private String getModelNumber() {
return "Model 500";
}
private String getSerialNumber() {
return "Thingsboard-500-000-0001";
}
private String getFirmwareVersion() {
return "1.0.2";
}
private long getErrorCode() {
return 0;
}
private Map<Integer, Long> getAvailablePowerSources() {
Map<Integer, Long> availablePowerSources = new HashMap<>();
availablePowerSources.put(0, 1L);
availablePowerSources.put(1, 2L);
availablePowerSources.put(2, 5L);
return availablePowerSources;
}
private int getBatteryLevel() {
return randomIterator.nextInt();
// return 42;
}
private long getMemoryFree() {
return Runtime.getRuntime().freeMemory() / 1024;
}
private String utcOffset = new SimpleDateFormat("X").format(Calendar.getInstance().getTime());
private String getUtcOffset() {
return utcOffset;
}
private void setUtcOffset(String t) {
utcOffset = t;
}
private String timeZone = TimeZone.getDefault().getID();
private String getTimezone() {
return timeZone;
}
private void setTimezone(String t) {
timeZone = t;
}
private String getSupportedBinding() {
return "U";
}
private String getDeviceType() {
return "Demo";
}
private String getHardwareVersion() {
return "1.0.1";
}
private String getSoftwareVersion() {
return "1.0.2";
}
private int getBatteryStatus() {
return RANDOM.nextInt(7);
}
private long getMemoryTotal() {
return Runtime.getRuntime().totalMemory() / 1024;
}
@Override
public List<Integer> getAvailableResourceIds(ObjectModel model) {
return supportedResources;
}
@Override
public void destroy() {
}
}

View File

@ -0,0 +1,405 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
FILE INFORMATION
OMA Permanent Document
File: OMA-SUP-XML_0-V1_2-20201110-A.xml
Path: http://www.openmobilealliance.org/release/ObjLwM2M_Security/
OMNA LwM2M Registry
Path: https://github.com/OpenMobileAlliance/lwm2m-registry
Name: 0.xml
NORMATIVE INFORMATION
Information about this file can be found in the latest revision of
OMA-TS-LightweightM2M_Core-V1_2
This is available at http://www.openmobilealliance.org/release/LightweightM2M/
Send comments to https://github.com/OpenMobileAlliance/OMA_LwM2M_for_Developers/issues
LEGAL DISCLAIMER
Copyright 2020 Open Mobile Alliance.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
The above license is used as a license under copyright only. Please
reference the OMA IPR Policy for patent licensing terms:
https://www.omaspecworks.org/about/intellectual-property-rights/
-->
<LWM2M xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://www.openmobilealliance.org/tech/profiles/LWM2M-v1_1.xsd">
<Object ObjectType="MODefinition">
<Name>LWM2M Security</Name>
<Description1><![CDATA[This LwM2M Object provides the keying material of a LwM2M Client appropriate to access a specified LwM2M Server. One Object Instance SHOULD address a LwM2M Bootstrap-Server.
These LwM2M Object Resources MUST only be changed by a LwM2M Bootstrap-Server or Bootstrap from Smartcard and MUST NOT be accessible by any other LwM2M Server.]]></Description1>
<ObjectID>0</ObjectID>
<ObjectURN>urn:oma:lwm2m:oma:0:1.2</ObjectURN>
<LWM2MVersion>1.1</LWM2MVersion>
<ObjectVersion>1.2</ObjectVersion>
<MultipleInstances>Multiple</MultipleInstances>
<Mandatory>Mandatory</Mandatory>
<Resources>
<Item ID="0">
<Name>LWM2M Server URI</Name>
<Operations></Operations>
<MultipleInstances>Single</MultipleInstances>
<Mandatory>Mandatory</Mandatory>
<Type>String</Type>
<RangeEnumeration>0..255</RangeEnumeration>
<Units></Units>
<Description><![CDATA[Uniquely identifies the LwM2M Server or LwM2M Bootstrap-Server. The format of the CoAP URI is defined in Section 6 of RFC 7252.]]></Description>
</Item>
<Item ID="1">
<Name>Bootstrap-Server</Name>
<Operations></Operations>
<MultipleInstances>Single</MultipleInstances>
<Mandatory>Mandatory</Mandatory>
<Type>Boolean</Type>
<RangeEnumeration></RangeEnumeration>
<Units></Units>
<Description><![CDATA[Determines if the current instance concerns a LwM2M Bootstrap-Server (true) or a standard LwM2M Server (false)]]></Description>
</Item>
<Item ID="2">
<Name>Security Mode</Name>
<Operations></Operations>
<MultipleInstances>Single</MultipleInstances>
<Mandatory>Mandatory</Mandatory>
<Type>Integer</Type>
<RangeEnumeration>0..4</RangeEnumeration>
<Units></Units>
<Description><![CDATA[Determines which security mode is used
0: Pre-Shared Key mode
1: Raw Public Key mode
2: Certificate mode
3: NoSec mode
4: Certificate mode with EST]]></Description>
</Item>
<Item ID="3">
<Name>Public Key or Identity</Name>
<Operations></Operations>
<MultipleInstances>Single</MultipleInstances>
<Mandatory>Mandatory</Mandatory>
<Type>Opaque</Type>
<RangeEnumeration></RangeEnumeration>
<Units></Units>
<Description><![CDATA[Stores the LwM2M Client's certificate, public key (RPK mode) or PSK Identity (PSK mode).]]></Description>
</Item>
<Item ID="4">
<Name>Server Public Key</Name>
<Operations></Operations>
<MultipleInstances>Single</MultipleInstances>
<Mandatory>Mandatory</Mandatory>
<Type>Opaque</Type>
<RangeEnumeration></RangeEnumeration>
<Units></Units>
<Description><![CDATA[Stores the LwM2M Server's, respectively LwM2M Bootstrap-Server's, certificate, public key (RPK mode) or trust anchor. The Certificate Mode Resource determines the content of this resource.]]></Description>
</Item>
<Item ID="5">
<Name>Secret Key</Name>
<Operations></Operations>
<MultipleInstances>Single</MultipleInstances>
<Mandatory>Mandatory</Mandatory>
<Type>Opaque</Type>
<RangeEnumeration></RangeEnumeration>
<Units></Units>
<Description><![CDATA[Stores the secret key (PSK mode) or private key (RPK or certificate mode).]]></Description>
</Item>
<Item ID="6">
<Name>SMS Security Mode</Name>
<Operations></Operations>
<MultipleInstances>Single</MultipleInstances>
<Mandatory>Optional</Mandatory>
<Type>Integer</Type>
<RangeEnumeration>0..255</RangeEnumeration>
<Units></Units>
<Description><![CDATA[Determines which SMS security mode is used:
0: Reserved for future use
1: DTLS mode (Device terminated) PSK mode assumed
2: Secure Packet Structure mode (Smartcard terminated)
3: NoSec mode
4: Reserved mode (DTLS mode with multiplexing Security Association support)
5-203 : Reserved for future use
204-255: Proprietary modes]]></Description>
</Item>
<Item ID="7">
<Name>SMS Binding Key Parameters</Name>
<Operations></Operations>
<MultipleInstances>Single</MultipleInstances>
<Mandatory>Optional</Mandatory>
<Type>Opaque</Type>
<RangeEnumeration>6</RangeEnumeration>
<Units></Units>
<Description><![CDATA[Stores the KIc, KID, SPI and TAR.]]></Description>
</Item>
<Item ID="8">
<Name>SMS Binding Secret Key(s)</Name>
<Operations></Operations>
<MultipleInstances>Single</MultipleInstances>
<Mandatory>Optional</Mandatory>
<Type>Opaque</Type>
<RangeEnumeration>16,32,48</RangeEnumeration>
<Units></Units>
<Description><![CDATA[Stores the values of the key(s) for the SMS binding.]]></Description>
</Item>
<Item ID="9">
<Name>LwM2M Server SMS Number</Name>
<Operations></Operations>
<MultipleInstances>Single</MultipleInstances>
<Mandatory>Optional</Mandatory>
<Type>String</Type>
<RangeEnumeration></RangeEnumeration>
<Units></Units>
<Description><![CDATA[MSISDN used by the LwM2M Client to send messages to the LwM2M Server via the SMS binding.]]></Description>
</Item>
<Item ID="10">
<Name>Short Server ID</Name>
<Operations></Operations>
<MultipleInstances>Single</MultipleInstances>
<Mandatory>Optional</Mandatory>
<Type>Integer</Type>
<RangeEnumeration>1..65534</RangeEnumeration>
<Units></Units>
<Description><![CDATA[This identifier uniquely identifies each LwM2M Server configured for the LwM2M Client.
This Resource MUST be set when the Bootstrap-Server Resource has a value of 'false'.
The values ID:0 and ID:65535 values MUST NOT be used for identifying the LwM2M Server.]]></Description>
</Item>
<Item ID="11">
<Name>Client Hold Off Time</Name>
<Operations></Operations>
<MultipleInstances>Single</MultipleInstances>
<Mandatory>Optional</Mandatory>
<Type>Integer</Type>
<RangeEnumeration></RangeEnumeration>
<Units>s</Units>
<Description><![CDATA[The number of seconds to wait before initiating a Client Initiated Bootstrap once the LwM2M Client has determined it should initiate this bootstrap mode.
In case client initiated bootstrap is supported by the LwM2M Client, this resource MUST be supported. This information is relevant for use with a Bootstrap-Server only.]]></Description>
</Item>
<Item ID="12">
<Name>Bootstrap-Server Account Timeout</Name>
<Operations></Operations>
<MultipleInstances>Single</MultipleInstances>
<Mandatory>Optional</Mandatory>
<Type>Integer</Type>
<RangeEnumeration></RangeEnumeration>
<Units>s</Units>
<Description><![CDATA[The LwM2M Client MUST purge the LwM2M Bootstrap-Server Account after the timeout value given by this resource. The lowest timeout value is 1.
If the value is set to 0, or if this resource is not instantiated, the Bootstrap-Server Account lifetime is infinite.]]></Description>
</Item>
<Item ID="13">
<Name>Matching Type</Name>
<Operations></Operations>
<MultipleInstances>Single</MultipleInstances>
<Mandatory>Optional</Mandatory>
<Type>Integer</Type>
<RangeEnumeration>0..3</RangeEnumeration>
<Units></Units>
<Description><![CDATA[The Matching Type Resource specifies how the certificate or raw public key in in the Server Public Key is presented. Four values are currently defined:
0: Exact match. This is the default value and also corresponds to the functionality of LwM2M v1.0. Hence, if this resource is not present then the content of the Server Public Key Resource corresponds to this value.
1: SHA-256 hash [RFC6234]
2: SHA-384 hash [RFC6234]
3: SHA-512 hash [RFC6234]]]></Description>
</Item>
<Item ID="14">
<Name>SNI</Name>
<Operations></Operations>
<MultipleInstances>Single</MultipleInstances>
<Mandatory>Optional</Mandatory>
<Type>String</Type>
<RangeEnumeration></RangeEnumeration>
<Units></Units>
<Description><![CDATA[This resource holds the value of the Server Name Indication (SNI) value to be used during the TLS handshake. When this resource is present then the LwM2M Server URI acts as the address of the service while the SNI value is used for matching a presented certificate, or PSK identity.]]></Description>
</Item>
<Item ID="15">
<Name>Certificate Usage</Name>
<Operations></Operations>
<MultipleInstances>Single</MultipleInstances>
<Mandatory>Optional</Mandatory>
<Type>Integer</Type>
<RangeEnumeration>0..3</RangeEnumeration>
<Units></Units>
<Description><![CDATA[The Certificate Usage Resource specifies the semantic of the certificate or
raw public key stored in the Server Public Key Resource, which is used to match
the certificate presented in the TLS/DTLS handshake. The currently defined values are
0 for "CA constraint", 1 for "service certificate constraint", 2 for "trust anchor
assertion", and 3 for "domain-issued certificate". When this resource is absent,
value (3) for domain issued certificate mode is assumed. More details about the
semantic of each value can be found in the security consideration section of the
LwM2M specification.]]></Description>
</Item>
<Item ID="16">
<Name>DTLS/TLS Ciphersuite</Name>
<Operations></Operations>
<MultipleInstances>Multiple</MultipleInstances>
<Mandatory>Optional</Mandatory>
<Type>Integer</Type>
<RangeEnumeration></RangeEnumeration>
<Units></Units>
<Description><![CDATA[When this resource is present it instructs the TLS/DTLS client to propose the indicated ciphersuite(s) in the ClientHello of the handshake. A ciphersuite is indicated as a 32-bit integer value. The IANA TLS ciphersuite registry is maintained at https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml. As an example, the TLS_PSK_WITH_AES_128_CCM_8 ciphersuite is represented with the following string "0xC0,0xA8". To form an integer value the two values are concatenated. In this example, the value is 0xc0a8 or 49320.]]></Description>
</Item>
<Item ID="17"><Name>OSCORE Security Mode</Name>
<Operations></Operations>
<MultipleInstances>Single</MultipleInstances>
<Mandatory>Optional</Mandatory>
<Type>Objlnk</Type>
<RangeEnumeration></RangeEnumeration>
<Units></Units>
<Description><![CDATA[If this resource is defined, it provides a link to the OSCORE Object Instance and OSCORE MUST be used by the LwM2M Client with the linked OSCORE Object Instance.]]></Description>
</Item>
<Item ID="18">
<Name>Groups To Use by Client</Name>
<Operations></Operations>
<MultipleInstances>Multiple</MultipleInstances>
<Mandatory>Optional</Mandatory>
<Type>Integer</Type>
<RangeEnumeration>0..65535</RangeEnumeration>
<Units></Units>
<Description><![CDATA[If this resource is defined, it indicates what groups the LwM2M Client should use with a LwM2M Server/LwM2M Bootstrap-Server (ordered from most preferred to least preferred). Resource instance 0 indicates the most preferred group. The values are taken from Section 4.2.7 of RFC 8446. An example is secp256r1 (0x0017).]]></Description>
</Item>
<Item ID="19">
<Name>Signature Algorithms Supported by Server</Name>
<Operations></Operations>
<MultipleInstances>Multiple</MultipleInstances>
<Mandatory>Optional</Mandatory>
<Type>Integer</Type>
<RangeEnumeration>0..65535</RangeEnumeration>
<Units></Units>
<Description><![CDATA[If this resource is defined, it indicates what signature algorithms the LwM2M Server/LwM2M Bootstrap-Server supports. The values are taken from Section 4.2.3 of RFC 8446. An example is ecdsa_secp256r1_sha256(0x0403).]]></Description>
</Item>
<Item ID="20"><Name>Signature Algorithms To Use by Client</Name>
<Operations></Operations>
<MultipleInstances>Multiple</MultipleInstances>
<Mandatory>Optional</Mandatory>
<Type>Integer</Type>
<RangeEnumeration>0..65535</RangeEnumeration>
<Units></Units>
<Description><![CDATA[If this resource is defined, it indicates what signature algorithms the LwM2M Client should use with a LwM2M Server/LwM2M Bootstrap-Server (ordered from most preferred to least preferred). Resource instance 0 indicates the most preferred group. The values are taken from Section 4.2.3 of RFC 8446. An example is ecdsa_secp256r1_sha256(0x0403).]]></Description>
</Item>
<Item ID="21">
<Name>Signature Algorithm Certs Supported by Server</Name>
<Operations></Operations>
<MultipleInstances>Multiple</MultipleInstances>
<Mandatory>Optional</Mandatory>
<Type>Integer</Type>
<RangeEnumeration>0..65535</RangeEnumeration>
<Units></Units>
<Description><![CDATA[If this resource is defined, it indicates what certificate-specific signature algorithms the the LwM2M Server/LwM2M Bootstrap-Server supports. The values are taken from Section 4.2.3 of RFC 8446. An example is ecdsa_secp256r1_sha256(0x0403).]]></Description>
</Item>
<Item ID="22">
<Name>TLS 1.3 Features To Use by Client</Name>
<Operations></Operations>
<MultipleInstances>Single</MultipleInstances>
<Mandatory>Optional</Mandatory>
<Type>Integer</Type>
<RangeEnumeration>0..65535</RangeEnumeration>
<Units></Units>
<Description><![CDATA[If this resource is defined, it indicates which features the LwM2M Client should use with the respective LwM2M Server/LwM2M Bootstrap-Server. The bitmask values listed below are defined. A bit value of '0' means the feature should not be used. bit(0) - PSK Plain, bit(1) - 0-RTT, bit(2) - PSK with PFS, bit(3) - Certificate-based Authentication. Bit(4) to bit(31) are reserved.]]></Description>
</Item>
<Item ID="23">
<Name>TLS Extensions Supported by Server</Name>
<Operations></Operations>
<MultipleInstances>Single</MultipleInstances>
<Mandatory>Optional</Mandatory>
<Type>Integer</Type>
<RangeEnumeration>0..65535</RangeEnumeration>
<Units></Units>
<Description><![CDATA[If this resource is defined, it indicates what extensions the LwM2M Server/LwM2M Bootstrap-Server supports in form of a bitmap. The following values are defined: bit(0) - Server Name Indication (RFC 6066), bit (1) - Max Fragment Length (RFC 6066), bit (2) - Status Request (RFC 6066), bit (3) - Heartbeat (RFC 6520), bit (4) - Application Layer Protocol Negotiation (RFC 7301), bit (5) - Signed Certificate Timestamp (RFC 6962), bit (6) - Certificate Compression (draft-ietf-tls-certificate-compression), bit (7) - Record Size Limit (RFC 8449), bit (8) - Ticket Pinning (draft-ietf-tls-pinning-ticket), bit (9) - Certificate Authorities (RFC 8446), bit (10) - OID Filters (RFC 8446), bit (11) - Post Handshake Auth (RFC 8446), bit (12) - Connection ID (draft-ietf-tls-dtls-connection-id/draft-ietf-tls-dtls13). Bit(13) to bit(31) are reserved. ]]></Description>
</Item>
<Item ID="24">
<Name>TLS Extensions To Use by Client</Name>
<Operations></Operations>
<MultipleInstances>Single</MultipleInstances>
<Mandatory>Optional</Mandatory>
<Type>Integer</Type>
<RangeEnumeration>0..65535</RangeEnumeration>
<Units></Units>
<Description><![CDATA[If this resource is defined, it indicates what extensions the LwM2M Client should use with the LwM2M Server/LwM2M Bootstrap-Server in form of a bitmap. The following values are defined: bit(0) - Server Name Indication (RFC 6066), bit (1) - Max Fragment Length (RFC 6066), bit (2) - Status Request (RFC 6066), bit (3) - Heartbeat (RFC 6520), bit (4) - Application Layer Protocol Negotiation (RFC 7301), bit (5) - Signed Certificate Timestamp (RFC 6962), bit (6) - Certificate Compression (draft-ietf-tls-certificate-compression), bit (7) - Record Size Limit (RFC 8449), bit (8) - Ticket Pinning (draft-ietf-tls-pinning-ticket), bit (9) - Certificate Authorities (RFC 8446), bit (10) - OID Filters (RFC 8446), bit (11) - Post Handshake Auth (RFC 8446), bit (12) - Connection ID (draft-ietf-tls-dtls-connection-id/draft-ietf-tls-dtls13). Bit(13) to bit(31) are reserved. ]]></Description>
</Item>
<Item ID="25">
<Name>Secondary LwM2M Server URI</Name>
<Operations></Operations>
<MultipleInstances>Multiple</MultipleInstances>
<Mandatory>Optional</Mandatory>
<Type>String</Type>
<RangeEnumeration>0..255</RangeEnumeration>
<Units></Units>
<Description><![CDATA[If this resource is present then the LwM2M Server URI in the Security Object, Resource ID 0, is augmented with information about further LwM2M Server URIs that can be used with the same security information found in the LwM2M Security Object. This is useful when a LwM2M Server is reachable via two different transport bindings (i.e. URIs). For example when the same server is reachable with two different URIs, such as a "coaps" and a "coaps+tcp" URI scheme.]]></Description>
</Item>
<Item ID="26"><Name>MQTT Server</Name>
<Operations></Operations>
<MultipleInstances>Single</MultipleInstances>
<Mandatory>Optional</Mandatory>
<Type>Objlnk</Type>
<RangeEnumeration></RangeEnumeration>
<Units></Units>
<Description><![CDATA[If this resource is defined, it provides a link to a MQTT Server Object Instance, which offers additional configuration information for use with this MQTT server. This Resource is used only when the URI scheme in the LwM2M Server URI Resource indicates the use of MQTT.]]></Description>
</Item>
<Item ID="27"><Name>LwM2M COSE Security</Name>
<Operations></Operations>
<MultipleInstances>Multiple</MultipleInstances>
<Mandatory>Optional</Mandatory>
<Type>Objlnk</Type>
<RangeEnumeration></RangeEnumeration>
<Units></Units>
<Description><![CDATA[If this resource is defined, it provides a links to LwM2M COSE Object Instances, which contain security-relevant configuration information for use with COSE.]]></Description>
</Item>
<Item ID="28"><Name>RDS Destination Port</Name>
<Operations></Operations>
<MultipleInstances>Single</MultipleInstances>
<Mandatory>Optional</Mandatory>
<Type>Integer</Type>
<RangeEnumeration>0..15</RangeEnumeration>
<Units></Units>
<Description><![CDATA[This resource provides the default RDS Destination Port Number (as defined in 3GPP TS 24.250) to use for contacting the LwM2M or Bootstrap Server when communicating through the SCEF across the Non-IP binding.]]></Description>
</Item>
<Item ID="29"><Name>RDS Source Port</Name>
<Operations></Operations>
<MultipleInstances>Single</MultipleInstances>
<Mandatory>Optional</Mandatory>
<Type>Integer</Type>
<RangeEnumeration>0..15</RangeEnumeration>
<Units></Units>
<Description><![CDATA[This resource provides the default RDS Source Port Number (as defined in 3GPP TS 24.250) to use for contacting the LwM2M or Bootstrap Server when communicating through the SCEF across the Non-IP binding.]]></Description>
</Item>
<Item ID="30"><Name>RDS Application ID</Name>
<Operations></Operations>
<MultipleInstances>Single</MultipleInstances>
<Mandatory>Optional</Mandatory>
<Type>String</Type>
<RangeEnumeration></RangeEnumeration>
<Units></Units>
<Description><![CDATA[This resource provides the Application ID (as defined in 3GPP TS 24.250) to use for querying the SCEF for the source and destination port numbers for contacting the LwM2M or Bootstrap Server when communicating through the SCEF across the Non-IP binding.]]></Description>
</Item>
</Resources>
<Description2><![CDATA[]]></Description2>
</Object>
</LWM2M>

View File

@ -0,0 +1,360 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
FILE INFORMATION
OMA Permanent Document
File: OMA-SUP-XML_1-V1_2-20201110-A.xml
Path: http://www.openmobilealliance.org/release/ObjLwM2M_Server/
OMNA LwM2M Registry
Path: https://github.com/OpenMobileAlliance/lwm2m-registry
Name: 1.xml
NORMATIVE INFORMATION
Information about this file can be found in the latest revision of
OMA-TS-LightweightM2M_Core-V1_2
This is available at http://www.openmobilealliance.org/release/LightweightM2M/
Send comments to https://github.com/OpenMobileAlliance/OMA_LwM2M_for_Developers/issues
LEGAL DISCLAIMER
Copyright 2020 Open Mobile Alliance.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
The above license is used as a license under copyright only. Please
reference the OMA IPR Policy for patent licensing terms:
https://www.omaspecworks.org/about/intellectual-property-rights/
-->
<LWM2M xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://www.openmobilealliance.org/tech/profiles/LWM2M-v1_1.xsd">
<Object ObjectType="MODefinition">
<Name>LwM2M Server</Name>
<Description1><![CDATA[This LwM2M Objects provides the data related to a LwM2M Server. A Bootstrap-Server has no such an Object Instance associated to it.]]></Description1>
<ObjectID>1</ObjectID>
<ObjectURN>urn:oma:lwm2m:oma:1:1.2</ObjectURN>
<LWM2MVersion>1.2</LWM2MVersion>
<ObjectVersion>1.2</ObjectVersion>
<MultipleInstances>Multiple</MultipleInstances>
<Mandatory>Mandatory</Mandatory>
<Resources>
<Item ID="0">
<Name>Short Server ID</Name>
<Operations>R</Operations>
<MultipleInstances>Single</MultipleInstances>
<Mandatory>Mandatory</Mandatory>
<Type>Integer</Type>
<RangeEnumeration>1..65534</RangeEnumeration>
<Units></Units>
<Description><![CDATA[Used as link to associate server Object Instance.]]></Description>
</Item>
<Item ID="1">
<Name>Lifetime</Name>
<Operations>RW</Operations>
<MultipleInstances>Single</MultipleInstances>
<Mandatory>Mandatory</Mandatory>
<Type>Integer</Type>
<RangeEnumeration></RangeEnumeration>
<Units>s</Units>
<Description><![CDATA[Specify the lifetime of the registration in seconds (see Client Registration Interface). If the value is set to 0, the lifetime is infinite.]]></Description>
</Item>
<Item ID="2">
<Name>Default Minimum Period</Name>
<Operations>RW</Operations>
<MultipleInstances>Single</MultipleInstances>
<Mandatory>Optional</Mandatory>
<Type>Integer</Type>
<RangeEnumeration></RangeEnumeration>
<Units>s</Units>
<Description><![CDATA[The default value the LwM2M Client should use for the Minimum Period of an Observation in the absence of this parameter being included in an Observation.
If this Resource doesnt exist, the default value is 0.]]></Description>
</Item>
<Item ID="3">
<Name>Default Maximum Period</Name>
<Operations>RW</Operations>
<MultipleInstances>Single</MultipleInstances>
<Mandatory>Optional</Mandatory>
<Type>Integer</Type>
<RangeEnumeration></RangeEnumeration>
<Units>s</Units>
<Description><![CDATA[The default value the LwM2M Client should use for the Maximum Period of an Observation in the absence of this parameter being included in an Observation.]]></Description>
</Item>
<Item ID="4">
<Name>Disable</Name>
<Operations>E</Operations>
<MultipleInstances>Single</MultipleInstances>
<Mandatory>Optional</Mandatory>
<Type></Type>
<RangeEnumeration></RangeEnumeration>
<Units></Units>
<Description><![CDATA[If this Resource is executed, this LwM2M Server Object is disabled for a certain period defined in the Disabled Timeout Resource. After receiving "Execute" operation, LwM2M Client MUST send response of the operation and perform de-registration process, and underlying network connection between the Client and Server MUST be disconnected to disable the LwM2M Server account.
After the above process, the LwM2M Client MUST NOT send any message to the Server and ignore all the messages from the LwM2M Server for the period.]]></Description>
</Item>
<Item ID="5">
<Name>Disable Timeout</Name>
<Operations>RW</Operations>
<MultipleInstances>Single</MultipleInstances>
<Mandatory>Optional</Mandatory>
<Type>Integer</Type>
<RangeEnumeration></RangeEnumeration>
<Units>s</Units>
<Description><![CDATA[A period to disable the Server. After this period, the LwM2M Client MUST perform registration process to the Server. If this Resource is not set, a default timeout value is 86400 (1 day).]]></Description>
</Item>
<Item ID="6">
<Name>Notification Storing When Disabled or Offline</Name>
<Operations>RW</Operations>
<MultipleInstances>Single</MultipleInstances>
<Mandatory>Mandatory</Mandatory>
<Type>Boolean</Type>
<RangeEnumeration></RangeEnumeration>
<Units></Units>
<Description><![CDATA[If true, the LwM2M Client stores "Notify" operations to the LwM2M Server while the LwM2M Server account is disabled or the LwM2M Client is offline. After the LwM2M Server account is enabled or the LwM2M Client is online, the LwM2M Client reports the stored "Notify" operations to the Server.
If false, the LwM2M Client discards all the "Notify" operations or temporarily disables the Observe function while the LwM2M Server is disabled or the LwM2M Client is offline.
The default value is true.
The maximum number of storing Notifications per Server is up to the implementation.]]></Description>
</Item>
<Item ID="7">
<Name>Binding</Name>
<Operations>RW</Operations>
<MultipleInstances>Single</MultipleInstances>
<Mandatory>Mandatory</Mandatory>
<Type>String</Type>
<RangeEnumeration></RangeEnumeration>
<Units></Units>
<Description><![CDATA[The possible values are those listed in the LwM2M Core Specification. This Resource defines the transport binding configured for the LwM2M Client.
If the LwM2M Client supports the binding specified in this Resource, the LwM2M Client MUST use that transport for the Current Binding Mode.]]></Description>
</Item>
<Item ID="8">
<Name>Registration Update Trigger</Name>
<Operations>E</Operations>
<MultipleInstances>Single</MultipleInstances>
<Mandatory>Mandatory</Mandatory>
<Type></Type>
<RangeEnumeration></RangeEnumeration>
<Units></Units>
<Description><![CDATA[If this Resource is executed the LwM2M Client MUST perform an "Update" operation with this LwM2M Server. The LwM2M Client can use a transport binding supported in the Current Binding Mode, Preferred Transport resource or the transport specified as an argument in the Registration Update Trigger.]]></Description>
</Item>
<Item ID="9">
<Name>Bootstrap-Request Trigger</Name>
<Operations>E</Operations>
<MultipleInstances>Single</MultipleInstances>
<Mandatory>Optional</Mandatory>
<Type></Type>
<RangeEnumeration></RangeEnumeration>
<Units></Units>
<Description><![CDATA[When this Resource is executed the LwM2M Client MUST initiate a "Client Initiated Bootstrap" procedure in using the LwM2M Bootstrap-Server Account.]]></Description>
</Item>
<Item ID="10">
<Name>APN Link</Name>
<Operations>RW</Operations>
<MultipleInstances>Single</MultipleInstances>
<Mandatory>Optional</Mandatory>
<Type>Objlnk</Type>
<RangeEnumeration></RangeEnumeration>
<Units></Units>
<Description><![CDATA[If this resource is defined, it provides a link to the APN connection profile Object Instance (OMNA registered Object ID:11) to be used to communicate with this server.]]></Description>
</Item>
<Item ID="11">
<Name>TLS-DTLS Alert Code</Name>
<Operations>R</Operations>
<MultipleInstances>Single</MultipleInstances>
<Mandatory>Optional</Mandatory>
<Type>Integer</Type>
<RangeEnumeration>0..255</RangeEnumeration>
<Units></Units>
<Description><![CDATA[If this resource is defined, it contains the most recent TLS / DTLS alert message received from the LwM2M Server respective represented by the AlertDescription defined in Section 7.2 of RFC 5246. This resource set by the LwM2M Client may help the LwM2M Bootstrap-Server to determine the cause of TLS/DTLS connection failure with the respective LwM2M Server.]]></Description>
</Item>
<Item ID="12">
<Name>Last Bootstrapped</Name>
<Operations>R</Operations>
<MultipleInstances>Single</MultipleInstances>
<Mandatory>Optional</Mandatory>
<Type>Time</Type>
<RangeEnumeration></RangeEnumeration>
<Units></Units>
<Description><![CDATA[If this resource is defined, it represents the last time that the bootstrap server updated this LwM2M Server Account. The LwM2M Client is responsible for updating this value. When the Bootstrap Server detects that this LwM2M Server Account is "out-of-date", the Bootstrap Server can update the LwM2M Server Account as represented by the LwM2M Server object instance.]]></Description>
</Item>
<Item ID="13">
<Name>Registration Priority Order</Name>
<Operations>R</Operations>
<MultipleInstances>Single</MultipleInstances>
<Mandatory>Optional</Mandatory>
<Type>Integer</Type>
<RangeEnumeration></RangeEnumeration>
<Units></Units>
<Description><![CDATA[The LwM2M Client sequences the LwM2M Server registrations in increasing order of this value. If this value is not defined, registration attempts to this server are not impacted by other server registrations.]]></Description>
</Item>
<Item ID="14">
<Name>Initial Registration Delay Timer</Name>
<Operations>RW</Operations>
<MultipleInstances>Single</MultipleInstances>
<Mandatory>Optional</Mandatory>
<Type>Integer</Type>
<RangeEnumeration></RangeEnumeration>
<Units>s</Units>
<Description><![CDATA[The delay, in seconds, before registration is attempted for this LwM2M Server based upon the completion of registration of the previous LwM2M Server in the registration order. This is only applied until the first successful registration after a successful bootstrapping sequence.]]></Description>
</Item>
<Item ID="15">
<Name>Registration Failure Block</Name>
<Operations>R</Operations>
<MultipleInstances>Single</MultipleInstances>
<Mandatory>Optional</Mandatory>
<Type>Boolean</Type>
<RangeEnumeration></RangeEnumeration>
<Units></Units>
<Description><![CDATA[When set to true and registration to this LwM2M server fails, the LwM2M Client blocks registration to other servers in the order. When set to false, the LwM2M Client proceeds with registration to the next server in the order.]]></Description>
</Item>
<Item ID="16">
<Name>Bootstrap on Registration Failure</Name>
<Operations>R</Operations>
<MultipleInstances>Single</MultipleInstances>
<Mandatory>Optional</Mandatory>
<Type>Boolean</Type>
<RangeEnumeration></RangeEnumeration>
<Units></Units>
<Description><![CDATA[If set to true, this indicates that the LwM2M Client should re-bootstrap when either registration is explicitly rejected by the LwM2M Server or registration is considered as failing as dictated by the other resource settings. If set to false, the LwM2M Client will continue with the registration attempts as dictated by the other resource settings.]]></Description>
</Item>
<Item ID="17">
<Name>Communication Retry Count</Name>
<Operations>RW</Operations>
<MultipleInstances>Single</MultipleInstances>
<Mandatory>Optional</Mandatory>
<Type>Integer</Type>
<RangeEnumeration></RangeEnumeration>
<Units></Units>
<Description><![CDATA[The number of successive communication attempts before which a communication sequence is considered as failed.]]></Description>
</Item>
<Item ID="18">
<Name>Communication Retry Timer</Name>
<Operations>RW</Operations>
<MultipleInstances>Single</MultipleInstances>
<Mandatory>Optional</Mandatory>
<Type>Integer</Type>
<RangeEnumeration></RangeEnumeration>
<Units>s</Units>
<Description><![CDATA[The delay, in seconds, between successive communication attempts in a communication sequence. This value is multiplied by two to the power of the communication retry attempt minus one (2**(retry attempt-1)) to create an exponential back-off.]]></Description>
</Item>
<Item ID="19">
<Name>Communication Sequence Delay Timer</Name>
<Operations>RW</Operations>
<MultipleInstances>Single</MultipleInstances>
<Mandatory>Optional</Mandatory>
<Type>Integer</Type>
<RangeEnumeration></RangeEnumeration>
<Units>s</Units>
<Description><![CDATA[The delay, in seconds, between successive communication sequences. A communication sequence is defined as the exhaustion of the Communication Retry Count and Communication Retry Timer values. A communication sequence can be applied to server registrations or bootstrapping attempts. MAX_VALUE means do not perform another communication sequence.]]></Description>
</Item>
<Item ID="20">
<Name>Communication Sequence Retry Count</Name>
<Operations>RW</Operations>
<MultipleInstances>Single</MultipleInstances>
<Mandatory>Optional</Mandatory>
<Type>Integer</Type>
<RangeEnumeration></RangeEnumeration>
<Units></Units>
<Description><![CDATA[The number of successive communication sequences before which a registration attempt is considered as failed.]]></Description>
</Item>
<Item ID="21">
<Name>Trigger</Name>
<Operations>RW</Operations>
<MultipleInstances>Single</MultipleInstances>
<Mandatory>Optional</Mandatory>
<Type>Boolean</Type>
<RangeEnumeration></RangeEnumeration>
<Units></Units>
<Description><![CDATA[Using the Trigger Resource a LwM2M Client can indicate whether it is reachable over SMS (value set to 'true') or not (value set to 'false'). The default value (resource not present) is 'false'. When set to 'true' the LwM2M Server MAY, for example, request the LwM2M Client to perform operations, such as the "Update" operation by sending an "Execute" operation on "Registration Update Trigger" Resource via SMS. No SMS response is expected for such a message.]]></Description>
</Item>
<Item ID="22">
<Name>Preferred Transport</Name>
<Operations>RW</Operations>
<MultipleInstances>Single</MultipleInstances>
<Mandatory>Optional</Mandatory>
<Type>String</Type>
<RangeEnumeration>The possible values are those listed in the LwM2M Core Specification</RangeEnumeration>
<Units></Units>
<Description><![CDATA[Only a single transport binding SHALL be present. When the LwM2M client supports multiple transports, it MAY use this transport to initiate a connection. This resource can also be used to switch between multiple transports e.g. a non-IP device can switch to UDP transport to perform firmware updates.]]></Description>
</Item>
<Item ID="23"><Name>Mute Send</Name>
<Operations>RW</Operations>
<MultipleInstances>Single</MultipleInstances>
<Mandatory>Optional</Mandatory>
<Type>Boolean</Type>
<RangeEnumeration></RangeEnumeration>
<Units></Units>
<Description><![CDATA[If true or the Resource is not present, the LwM2M Client Send command capability is de-activated.
If false, the LwM2M Client Send Command capability is activated.]]></Description>
</Item>
<Item ID="24">
<Name>Alternate APN Links</Name>
<Operations>RW</Operations>
<MultipleInstances>Multiple</MultipleInstances>
<Mandatory>Optional</Mandatory>
<Type>Objlnk</Type>
<RangeEnumeration></RangeEnumeration>
<Units></Units>
<Description><![CDATA[If this resource is defined, it provides links to alternate APN connection profile Object Instance (OMNA registered Object ID:11) to be used to communicate with this server if Resource 10 has configuration conflicts.]]></Description>
</Item>
<Item ID="25">
<Name>Supported Server Versions</Name>
<Operations>RW</Operations>
<MultipleInstances>Multiple</MultipleInstances>
<Mandatory>Optional</Mandatory>
<Type>String</Type>
<RangeEnumeration></RangeEnumeration>
<Units></Units>
<Description><![CDATA[This resource provides the supported enabler versions of the server to the client as a set of strings. Format for each string is 1*DIGIT"."1*DIGIT"."1*DIGIT where the third DIGIT is optional.]]></Description>
</Item>
<Item ID="26">
<Name>Default Notification Mode</Name>
<Operations>RW</Operations>
<MultipleInstances>Single</MultipleInstances>
<Mandatory>Optional</Mandatory>
<Type>Integer</Type>
<RangeEnumeration>0..1</RangeEnumeration>
<Units></Units>
<Description><![CDATA[This resource indicates the default mode for observations to be sent: 0 = Non-Confirmable, 1 = Confirmable.]]></Description>
</Item>
<Item ID="27">
<Name>Profile ID Hash Algorithm</Name>
<Operations>RW</Operations>
<MultipleInstances>Single</MultipleInstances>
<Mandatory>Optional</Mandatory>
<Type>Integer</Type>
<RangeEnumeration>0..255</RangeEnumeration>
<Units/>
<Description><![CDATA[If this resource is defined, it contains the hash algorithm the LwM2M Server would prefer the LwM2M Client to use with the dynamically generated mode of creating Profile IDs. The numerical ID value of the 'Suite Identifiers' registered by RFC 6920 is used in this Resource.]]></Description>
</Item>
</Resources>
<Description2></Description2>
</Object>
</LWM2M>

View File

@ -0,0 +1,123 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
FILE INFORMATION
OMA Permanent Document
File: OMA-SUP-XML_2-V1_1-20201110-A.xml
Path: http://www.openmobilealliance.org/release/ObjLwM2M_ACL/
OMNA LwM2M Registry
Path: https://github.com/OpenMobileAlliance/lwm2m-registry
Name: 2.xml
NORMATIVE INFORMATION
Information about this file can be found in the latest revision of
OMA-TS-LightweightM2M_Core-V1_2
This is available at http://www.openmobilealliance.org/release/LightweightM2M/
Send comments to https://github.com/OpenMobileAlliance/OMA_LwM2M_for_Developers/issues
LEGAL DISCLAIMER
Copyright 2020 Open Mobile Alliance.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
The above license is used as a license under copyright only. Please
reference the OMA IPR Policy for patent licensing terms:
https://www.omaspecworks.org/about/intellectual-property-rights/
-->
<LWM2M xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://www.openmobilealliance.org/tech/profiles/LWM2M.xsd">
<Object ObjectType="MODefinition">
<Name>LwM2M Access Control</Name>
<Description1><![CDATA[Access Control Object is used to check whether the LwM2M Server has access right for performing an operation.]]></Description1>
<ObjectID>2</ObjectID>
<ObjectURN>urn:oma:lwm2m:oma:2:1.1</ObjectURN>
<LWM2MVersion>1.0</LWM2MVersion>
<ObjectVersion>1.1</ObjectVersion>
<MultipleInstances>Multiple</MultipleInstances>
<Mandatory>Optional</Mandatory>
<Resources>
<Item ID="0">
<Name>Object ID</Name>
<Operations>R</Operations>
<MultipleInstances>Single</MultipleInstances>
<Mandatory>Mandatory</Mandatory>
<Type>Integer</Type>
<RangeEnumeration>1..65534</RangeEnumeration>
<Units></Units>
<Description><![CDATA[Resources 0 and 1 point to the Object Instance for which the Instances of the ACL Resource of that Access Control Object Instance are applicable.]]></Description>
</Item>
<Item ID="1">
<Name>Object Instance ID</Name>
<Operations>R</Operations>
<MultipleInstances>Single</MultipleInstances>
<Mandatory>Mandatory</Mandatory>
<Type>Integer</Type>
<RangeEnumeration>0..65535</RangeEnumeration>
<Units></Units>
<Description><![CDATA[See above]]></Description>
</Item>
<Item ID="2">
<Name>ACL</Name>
<Operations>RW</Operations>
<MultipleInstances>Multiple</MultipleInstances>
<Mandatory>Optional</Mandatory>
<Type>Integer</Type>
<RangeEnumeration>0..31</RangeEnumeration>
<Units></Units>
<Description><![CDATA[The Resource Instance ID MUST be the Short Server ID of a certain LwM2M Server for which associated access rights are contained in the Resource Instance value.
The Resource Instance ID 0 is a specific ID, determining the ACL Instance which contains the default access rights.
Each bit set in the Resource Instance value, grants an access right to the LwM2M Server to the corresponding operation.
The bit order is specified as below.
1st LSB: R(Read, Observe, Write-Attributes)
2nd LSB: W(Write)
3rd LSB: E(Execute)
4th LSB: D(Delete)
5th LSB: C(Create)
Other bits are reserved for future use.]]></Description>
</Item>
<Item ID="3">
<Name>Access Control Owner</Name>
<Operations>RW</Operations>
<MultipleInstances>Single</MultipleInstances>
<Mandatory>Mandatory</Mandatory>
<Type>Integer</Type>
<RangeEnumeration>0..65535</RangeEnumeration>
<Units></Units>
<Description><![CDATA[Short Server ID of a certain LwM2M Server; only such an LwM2M Server can manage the Resources of this Object Instance.
The specific value MAX_ID=65535 means this Access Control Object Instance is created and modified during a Bootstrap phase only.]]></Description>
</Item>
</Resources>
<Description2><![CDATA[]]></Description2>
</Object>
</LWM2M>

View File

@ -0,0 +1,331 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
FILE INFORMATION
OMA Permanent Document
File: OMA-SUP-XML_3-V1_2-20201110-A.xml
Path: http://www.openmobilealliance.org/release/ObjLwM2M_Device/
OMNA LwM2M Registry
Path: https://github.com/OpenMobileAlliance/lwm2m-registry
Name: 3.xml
NORMATIVE INFORMATION
Information about this file can be found in the latest revision of
OMA-TS-LightweightM2M_Core-V1_2
This is available at http://www.openmobilealliance.org/release/LightweightM2M/
Send comments to https://github.com/OpenMobileAlliance/OMA_LwM2M_for_Developers/issues
LEGAL DISCLAIMER
Copyright 2020 Open Mobile Alliance.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
The above license is used as a license under copyright only. Please
reference the OMA IPR Policy for patent licensing terms:
https://www.omaspecworks.org/about/intellectual-property-rights/
-->
<LWM2M xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://www.openmobilealliance.org/tech/profiles/LWM2M-v1_1.xsd">
<Object ObjectType="MODefinition">
<Name>Device</Name>
<Description1><![CDATA[This LwM2M Object provides a range of device related information which can be queried by the LwM2M Server, and a device reboot and factory reset function.]]></Description1>
<ObjectID>3</ObjectID>
<ObjectURN>urn:oma:lwm2m:oma:3:1.0</ObjectURN>
<LWM2MVersion>1.1</LWM2MVersion>
<ObjectVersion>1.2</ObjectVersion>
<MultipleInstances>Single</MultipleInstances>
<Mandatory>Mandatory</Mandatory>
<Resources>
<Item ID="0">
<Name>Manufacturer</Name>
<Operations>R</Operations>
<MultipleInstances>Single</MultipleInstances>
<Mandatory>Optional</Mandatory>
<Type>String</Type>
<RangeEnumeration></RangeEnumeration>
<Units></Units>
<Description><![CDATA[Human readable manufacturer name]]></Description>
</Item>
<Item ID="1">
<Name>Model Number</Name>
<Operations>R</Operations>
<MultipleInstances>Single</MultipleInstances>
<Mandatory>Optional</Mandatory>
<Type>String</Type>
<RangeEnumeration></RangeEnumeration>
<Units></Units>
<Description><![CDATA[A model identifier (manufacturer specified string)]]></Description>
</Item>
<Item ID="2">
<Name>Serial Number</Name>
<Operations>R</Operations>
<MultipleInstances>Single</MultipleInstances>
<Mandatory>Optional</Mandatory>
<Type>String</Type>
<RangeEnumeration></RangeEnumeration>
<Units></Units>
<Description><![CDATA[Serial Number]]></Description>
</Item>
<Item ID="3">
<Name>Firmware Version</Name>
<Operations>R</Operations>
<MultipleInstances>Single</MultipleInstances>
<Mandatory>Optional</Mandatory>
<Type>String</Type>
<RangeEnumeration></RangeEnumeration>
<Units></Units>
<Description><![CDATA[Current firmware version of the Device.The Firmware Management function could rely on this resource.]]></Description>
</Item>
<Item ID="4">
<Name>Reboot</Name>
<Operations>E</Operations>
<MultipleInstances>Single</MultipleInstances>
<Mandatory>Mandatory</Mandatory>
<Type></Type>
<RangeEnumeration></RangeEnumeration>
<Units></Units>
<Description><![CDATA[Reboot the LwM2M Device to restore the Device from unexpected firmware failure.]]></Description>
</Item>
<Item ID="5">
<Name>Factory Reset</Name>
<Operations>E</Operations>
<MultipleInstances>Single</MultipleInstances>
<Mandatory>Optional</Mandatory>
<Type></Type>
<RangeEnumeration></RangeEnumeration>
<Units></Units>
<Description><![CDATA[Perform factory reset of the LwM2M Device to make the LwM2M Device to go through initial deployment sequence where provisioning and bootstrap sequence is performed. This requires client ensuring post factory reset to have minimal information to allow it to carry out one of the bootstrap methods specified in section 5.2.3.
When this Resource is executed, "De-register" operation MAY be sent to the LwM2M Server(s) before factory reset of the LwM2M Device.]]></Description>
</Item>
<Item ID="6">
<Name>Available Power Sources</Name>
<Operations>R</Operations>
<MultipleInstances>Multiple</MultipleInstances>
<Mandatory>Optional</Mandatory>
<Type>Integer</Type>
<RangeEnumeration>0..7</RangeEnumeration>
<Units></Units>
<Description><![CDATA[0: DC power
1: Internal Battery
2: External Battery
3: Fuel Cell
4: Power over Ethernet
5: USB
6: AC (Mains) power
7: Solar
The same Resource Instance ID MUST be used to associate a given Power Source (Resource ID:6) with its Present Voltage (Resource ID:7) and its Present Current (Resource ID:8)]]></Description>
</Item>
<Item ID="7">
<Name>Power Source Voltage</Name>
<Operations>R</Operations>
<MultipleInstances>Multiple</MultipleInstances>
<Mandatory>Optional</Mandatory>
<Type>Integer</Type>
<RangeEnumeration></RangeEnumeration>
<Units></Units>
<Description><![CDATA[Present voltage for each Available Power Sources Resource Instance. The unit used for this resource is in mV.]]></Description>
</Item>
<Item ID="8">
<Name>Power Source Current</Name>
<Operations>R</Operations>
<MultipleInstances>Multiple</MultipleInstances>
<Mandatory>Optional</Mandatory>
<Type>Integer</Type>
<RangeEnumeration></RangeEnumeration>
<Units></Units>
<Description><![CDATA[Present current for each Available Power Source. The unit used for this resource is in mA.]]></Description>
</Item>
<Item ID="9">
<Name>Battery Level</Name>
<Operations>R</Operations>
<MultipleInstances>Single</MultipleInstances>
<Mandatory>Optional</Mandatory>
<Type>Integer</Type>
<RangeEnumeration>0..100</RangeEnumeration>
<Units>/100</Units>
<Description><![CDATA[Contains the current battery level as a percentage (with a range from 0 to 100). This value is only valid for the Device internal Battery if present (one Available Power Sources Resource Instance is 1).]]></Description>
</Item>
<Item ID="10">
<Name>Memory Free</Name>
<Operations>R</Operations>
<MultipleInstances>Single</MultipleInstances>
<Mandatory>Optional</Mandatory>
<Type>Integer</Type>
<RangeEnumeration></RangeEnumeration>
<Units></Units>
<Description><![CDATA[Estimated current available amount of storage space which can store data and software in the LwM2M Device (expressed in kilobytes). Note: 1 kilobyte corresponds to 1000 bytes.]]></Description>
</Item>
<Item ID="11">
<Name>Error Code</Name>
<Operations>R</Operations>
<MultipleInstances>Multiple</MultipleInstances>
<Mandatory>Mandatory</Mandatory>
<Type>Integer</Type>
<RangeEnumeration>0..32</RangeEnumeration>
<Units></Units>
<Description><![CDATA[0=No error
1=Low battery power
2=External power supply off
3=GPS module failure
4=Low received signal strength
5=Out of memory
6=SMS failure
7=IP connectivity failure
8=Peripheral malfunction
9..15=Reserved for future use
16..32=Device specific error codes
When the single Device Object Instance is initiated, there is only one error code Resource Instance whose value is equal to 0 that means no error. When the first error happens, the LwM2M Client changes error code Resource Instance to any non-zero value to indicate the error type. When any other error happens, a new error code Resource Instance is created. When an error associated with a Resource Instance is no longer present, that Resource Instance is deleted. When the single existing error is no longer present, the LwM2M Client returns to the original no error state where Instance 0 has value 0.
This error code Resource MAY be observed by the LwM2M Server. How to deal with LwM2M Clients error report depends on the policy of the LwM2M Server. Error codes in between 16 and 32 are specific to the Device and may have different meanings among implementations.]]></Description>
</Item>
<Item ID="12">
<Name>Reset Error Code</Name>
<Operations>E</Operations>
<MultipleInstances>Single</MultipleInstances>
<Mandatory>Optional</Mandatory>
<Type></Type>
<RangeEnumeration></RangeEnumeration>
<Units></Units>
<Description><![CDATA[Delete all error code Resource Instances and create only one zero-value error code that implies no error, then re-evaluate all error conditions and update and create Resources Instances to capture all current error conditions.]]></Description>
</Item>
<Item ID="13">
<Name>Current Time</Name>
<Operations>RW</Operations>
<MultipleInstances>Single</MultipleInstances>
<Mandatory>Optional</Mandatory>
<Type>Time</Type>
<RangeEnumeration></RangeEnumeration>
<Units></Units>
<Description><![CDATA[Current UNIX time of the LwM2M Client.
The LwM2M Client should be responsible to increase this time value as every second elapses.
The LwM2M Server is able to write this Resource to make the LwM2M Client synchronized with the LwM2M Server.]]></Description>
</Item>
<Item ID="14">
<Name>UTC Offset</Name>
<Operations>RW</Operations>
<MultipleInstances>Single</MultipleInstances>
<Mandatory>Optional</Mandatory>
<Type>String</Type>
<RangeEnumeration></RangeEnumeration>
<Units></Units>
<Description><![CDATA[Indicates the UTC offset currently in effect for this LwM2M Device. UTC+X [ISO 8601].]]></Description>
</Item>
<Item ID="15">
<Name>Timezone</Name>
<Operations>RW</Operations>
<MultipleInstances>Single</MultipleInstances>
<Mandatory>Optional</Mandatory>
<Type>String</Type>
<RangeEnumeration></RangeEnumeration>
<Units></Units>
<Description><![CDATA[Indicates in which time zone the LwM2M Device is located, in IANA Timezone (TZ) database format.]]></Description>
</Item>
<Item ID="16">
<Name>Supported Binding and Modes</Name>
<Operations>R</Operations>
<MultipleInstances>Single</MultipleInstances>
<Mandatory>Mandatory</Mandatory>
<Type>String</Type>
<RangeEnumeration></RangeEnumeration>
<Units></Units>
<Description><![CDATA[Indicates which bindings and modes are supported in the LwM2M Client. The possible values are those listed in the LwM2M Core Specification.]]></Description>
</Item>
<Item ID="17"><Name>Device Type</Name>
<Operations>R</Operations>
<MultipleInstances>Single</MultipleInstances>
<Mandatory>Optional</Mandatory>
<Type>String</Type>
<RangeEnumeration></RangeEnumeration>
<Units></Units>
<Description><![CDATA[Type of the device (manufacturer specified string: e.g. smart meters / dev Class / ...)]]></Description>
</Item>
<Item ID="18"><Name>Hardware Version</Name>
<Operations>R</Operations>
<MultipleInstances>Single</MultipleInstances>
<Mandatory>Optional</Mandatory>
<Type>String</Type>
<RangeEnumeration></RangeEnumeration>
<Units></Units>
<Description><![CDATA[Current hardware version of the device]]></Description>
</Item>
<Item ID="19"><Name>Software Version</Name>
<Operations>R</Operations>
<MultipleInstances>Single</MultipleInstances>
<Mandatory>Optional</Mandatory>
<Type>String</Type>
<RangeEnumeration></RangeEnumeration>
<Units></Units>
<Description><![CDATA[Current software version of the device (manufacturer specified string). On elaborated LwM2M device, SW could be split in 2 parts: a firmware one and a higher level software on top.
Both pieces of Software are together managed by LwM2M Firmware Update Object (Object ID 5)]]></Description>
</Item>
<Item ID="20"><Name>Battery Status</Name>
<Operations>R</Operations>
<MultipleInstances>Single</MultipleInstances>
<Mandatory>Optional</Mandatory>
<Type>Integer</Type>
<RangeEnumeration>0..6</RangeEnumeration>
<Units></Units>
<Description><![CDATA[This value is only valid for the Device Internal Battery if present (one Available Power Sources Resource Instance value is 1).
Battery
Status Meaning Description
0 Normal The battery is operating normally and not on power.
1 Charging The battery is currently charging.
2 Charge Complete The battery is fully charged and still on power.
3 Damaged The battery has some problem.
4 Low Battery The battery is low on charge.
5 Not Installed The battery is not installed.
6 Unknown The battery information is not available.]]></Description>
</Item>
<Item ID="21"><Name>Memory Total</Name>
<Operations>R</Operations>
<MultipleInstances>Single</MultipleInstances>
<Mandatory>Optional</Mandatory>
<Type>Integer</Type>
<RangeEnumeration></RangeEnumeration>
<Units></Units>
<Description><![CDATA[Total amount of storage space which can store data and software in the LwM2M Device (expressed in kilobytes). Note: 1 kilobyte corresponds to 1000 bytes.]]></Description>
</Item>
<Item ID="22"><Name>ExtDevInfo</Name>
<Operations>R</Operations>
<MultipleInstances>Multiple</MultipleInstances>
<Mandatory>Optional</Mandatory>
<Type>Objlnk</Type>
<RangeEnumeration></RangeEnumeration>
<Units></Units>
<Description><![CDATA[Reference to external "Device" object instance containing information. For example, such an external device can be a Host Device, which is a device into which the Device containing the LwM2M client is embedded. This Resource may be used to retrieve information about the Host Device.]]></Description>
</Item></Resources>
<Description2></Description2>
</Object>
</LWM2M>

View File

@ -0,0 +1,204 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
FILE INFORMATION
OMA Permanent Document
File: OMA-SUP-XML_LWM2M_Firmware_Update-V1_0_3-20190617-A
Type: xml
Date: 2019-Jun-17
Public Reachable Information
Path: http://www.openmobilealliance.org/tech/profiles
Name: LWM2M_Firmware_Update-v1_0_3.xml
NORMATIVE INFORMATION
Information about this file can be found in the latest revision of
OMA-TS-LightweightM2M-V1_0_2
OMA-TS-LightweightM2M_Core-V1_1_1
This is available at http://www.openmobilealliance.org/
Send comments to https://github.com/OpenMobileAlliance/OMA_LwM2M_for_Developers/issues
LEGAL DISCLAIMER
Copyright 2019 Open Mobile Alliance.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
The above license is used as a license under copyright only. Please
reference the OMA IPR Policy for patent licensing terms:
https://www.omaspecworks.org/about/intellectual-property-rights/
-->
<LWM2M xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://www.openmobilealliance.org/tech/profiles/LWM2M.xsd">
<Object ObjectType="MODefinition">
<Name>Firmware Update V_1_0</Name>
<Description1><![CDATA[This LwM2M Object enables management of firmware which is to be updated. This Object includes installing a firmware package, updating firmware, and performing actions after updating firmware. The firmware update MAY require to reboot the device; it will depend on a number of factors, such as the operating system architecture and the extent of the updated software.
The envisioned functionality is to allow a LwM2M Client to connect to any LwM2M Server to obtain a firmware image using the object and resource structure defined in this section experiencing communication security protection using TLS/DTLS. There are, however, other design decisions that need to be taken into account to allow a manufacturer of a device to securely install firmware on a device. Examples for such design decisions are how to manage the firmware update repository at the server side (which may include user interface considerations), the techniques to provide additional application layer security protection of the firmware image, how many versions of firmware images to store on the device, and how to execute the firmware update process considering the hardware specific details of a given IoT hardware product. These aspects are considered to be outside the scope of this version of the specification.
A LwM2M Server may also instruct a LwM2M Client to fetch a firmware image from a dedicated server (instead of pushing firmware images to the LwM2M Client). The Package URI resource is contained in the Firmware object and can be used for this purpose.
A LwM2M Client MUST support block-wise transfer [CoAP_Blockwise] if it implements the Firmware Update object.
A LwM2M Server MUST support block-wise transfer. Other protocols, such as HTTP/HTTPs, MAY also be used for downloading firmware updates (via the Package URI resource). For constrained devices it is, however, RECOMMENDED to use CoAP for firmware downloads to avoid the need for additional protocol implementations.]]></Description1>
<ObjectID>5</ObjectID>
<ObjectURN>urn:oma:lwm2m:oma:5</ObjectURN>
<LWM2MVersion>1.0</LWM2MVersion>
<ObjectVersion>1.2</ObjectVersion>
<MultipleInstances>Single</MultipleInstances>
<Mandatory>Optional</Mandatory>
<Resources>
<Item ID="0">
<Name>Package</Name>
<Operations>W</Operations>
<MultipleInstances>Single</MultipleInstances>
<Mandatory>Mandatory</Mandatory>
<Type>Opaque</Type>
<RangeEnumeration></RangeEnumeration>
<Units></Units>
<Description><![CDATA[Firmware package]]></Description>
</Item>
<Item ID="1">
<Name>Package URI</Name>
<Operations>RW</Operations>
<MultipleInstances>Single</MultipleInstances>
<Mandatory>Mandatory</Mandatory>
<Type>String</Type>
<RangeEnumeration>0..255</RangeEnumeration>
<Units></Units>
<Description><![CDATA[URI from where the device can download the firmware package by an alternative mechanism. As soon the device has received the Package URI it performs the download at the next practical opportunity.
The URI format is defined in RFC 3986. For example, coaps://example.org/firmware is a syntactically valid URI. The URI scheme determines the protocol to be used. For CoAP this endpoint MAY be a LwM2M Server but does not necessarily need to be. A CoAP server implementing block-wise transfer is sufficient as a server hosting a firmware repository and the expectation is that this server merely serves as a separate file server making firmware images available to LwM2M Clients.]]></Description>
</Item>
<Item ID="2">
<Name>Update</Name>
<Operations>E</Operations>
<MultipleInstances>Single</MultipleInstances>
<Mandatory>Mandatory</Mandatory>
<Type></Type>
<RangeEnumeration></RangeEnumeration>
<Units></Units>
<Description><![CDATA[Updates firmware by using the firmware package stored in Package, or, by using the firmware downloaded from the Package URI.
This Resource is only executable when the value of the State Resource is Downloaded.]]></Description>
</Item>
<Item ID="3">
<Name>State</Name>
<Operations>R</Operations>
<MultipleInstances>Single</MultipleInstances>
<Mandatory>Mandatory</Mandatory>
<Type>Integer</Type>
<RangeEnumeration>0..3</RangeEnumeration>
<Units></Units>
<Description><![CDATA[Indicates current state with respect to this firmware update. This value is set by the LwM2M Client.
0: Idle (before downloading or after successful updating)
1: Downloading (The data sequence is on the way)
2: Downloaded
3: Updating
If writing the firmware package to Package Resource has completed, or, if the device has downloaded the firmware package from the Package URI the state changes to Downloaded.
Writing an empty string to Package URI Resource or setting the Package Resource to NULL (\0), resets the Firmware Update State Machine: the State Resource value is set to Idle and the Update Result Resource value is set to 0.
When in Downloaded state, and the executable Resource Update is triggered, the state changes to Updating.
If the Update Resource failed, the state returns at Downloaded.
If performing the Update Resource was successful, the state changes from Updating to Idle.
The firmware update state machine is illustrated in Figure 29 of the LwM2M version 1.0 specification (and also in Figure E.6.1-1 of this specification).]]></Description>
</Item>
<Item ID="5">
<Name>Update Result</Name>
<Operations>R</Operations>
<MultipleInstances>Single</MultipleInstances>
<Mandatory>Mandatory</Mandatory>
<Type>Integer</Type>
<RangeEnumeration>0..9</RangeEnumeration>
<Units></Units>
<Description><![CDATA[Contains the result of downloading or updating the firmware
0: Initial value. Once the updating process is initiated (Download /Update), this Resource MUST be reset to Initial value.
1: Firmware updated successfully.
2: Not enough flash memory for the new firmware package.
3: Out of RAM during downloading process.
4: Connection lost during downloading process.
5: Integrity check failure for new downloaded package.
6: Unsupported package type.
7: Invalid URI.
8: Firmware update failed.
9: Unsupported protocol. A LwM2M client indicates the failure to retrieve the firmware image using the URI provided in the Package URI resource by writing the value 9 to the /5/0/5 (Update Result resource) when the URI contained a URI scheme unsupported by the client. Consequently, the LwM2M Client is unable to retrieve the firmware image using the URI provided by the LwM2M Server in the Package URI when it refers to an unsupported protocol.]]></Description>
</Item>
<Item ID="6">
<Name>PkgName</Name>
<Operations>R</Operations>
<MultipleInstances>Single</MultipleInstances>
<Mandatory>Optional</Mandatory>
<Type>String</Type>
<RangeEnumeration>0..255</RangeEnumeration>
<Units></Units>
<Description><![CDATA[Name of the Firmware Package]]></Description>
</Item>
<Item ID="7">
<Name>PkgVersion</Name>
<Operations>R</Operations>
<MultipleInstances>Single</MultipleInstances>
<Mandatory>Optional</Mandatory>
<Type>String</Type>
<RangeEnumeration>0..255</RangeEnumeration>
<Units></Units>
<Description><![CDATA[Version of the Firmware package]]></Description>
</Item>
<Item ID="8">
<Name>Firmware Update Protocol Support</Name>
<Operations>R</Operations>
<MultipleInstances>Multiple</MultipleInstances>
<Mandatory>Optional</Mandatory>
<Type>Integer</Type>
<RangeEnumeration>0..5</RangeEnumeration>
<Units></Units>
<Description><![CDATA[This resource indicates what protocols the LwM2M Client implements to retrieve firmware images. The LwM2M server uses this information to decide what URI to include in the Package URI. A LwM2M Server MUST NOT include a URI in the Package URI object that uses a protocol that is unsupported by the LwM2M client.
For example, if a LwM2M client indicates that it supports CoAP and CoAPS then a LwM2M Server must not provide an HTTP URI in the Packet URI.
The following values are defined by this version of the specification:
0: CoAP (as defined in RFC 7252) with the additional support for block-wise transfer. CoAP is the default setting.
1: CoAPS (as defined in RFC 7252) with the additional support for block-wise transfer
2: HTTP 1.1 (as defined in RFC 7230)
3: HTTPS 1.1 (as defined in RFC 7230)
4: CoAP over TCP (as defined in RFC 8323)
5: CoAP over TLS (as defined in RFC 8323)
Additional values MAY be defined in the future. Any value not understood by the LwM2M Server MUST be ignored.]]></Description>
</Item>
<Item ID="9">
<Name>Firmware Update Delivery Method</Name>
<Operations>R</Operations>
<MultipleInstances>Single</MultipleInstances>
<Mandatory>Mandatory</Mandatory>
<Type>Integer</Type>
<RangeEnumeration>0..2</RangeEnumeration>
<Units></Units>
<Description><![CDATA[The LwM2M Client uses this resource to indicate its support for transferring firmware images to the client either via the Package Resource (=push) or via the Package URI Resource (=pull) mechanism.
0: Pull only
1: Push only
2: Both. In this case the LwM2M Server MAY choose the preferred mechanism for conveying the firmware image to the LwM2M Client.]]></Description>
</Item>
</Resources>
<Description2><![CDATA[]]></Description2>
</Object>
</LWM2M>

View File

@ -21,10 +21,10 @@
<appender name="fileLogAppender"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>/var/log/tb-coap-transport/${TB_SERVICE_ID}/tb-coap-transport.log</file>
<file>/var/log/tb-lwm2m-transport/${TB_SERVICE_ID}/tb-lwm2m-transport.log</file>
<rollingPolicy
class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>/var/log/tb-coap-transport/${TB_SERVICE_ID}/tb-coap-transport.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<fileNamePattern>/var/log/tb-lwm2m-transport/${TB_SERVICE_ID}/tb-lwm2m-transport.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<maxFileSize>100MB</maxFileSize>
<maxHistory>30</maxHistory>
<totalSizeCap>3GB</totalSizeCap>
@ -47,6 +47,8 @@
<logger name="org.apache.kafka.common.utils.AppInfoParser" level="WARN"/>
<logger name="org.apache.kafka.clients" level="WARN"/>
<logger name="org.thingsboard.server.transport.lwm2m" level="TRACE"/>
<root level="INFO">
<appender-ref ref="fileLogAppender"/>
<appender-ref ref="STDOUT"/>

View File

@ -21,7 +21,7 @@ In this example `thingsboard/tb` image will be used. You can choose any other im
Execute the following command to run this docker directly:
`
$ docker run -it -p 9090:9090 -p 1883:1883 -p 5683:5683/udp -p 5685:5685/udp -v ~/.mytb-data:/data --name mytb thingsboard/tb
$ docker run -it -p 9090:9090 -p 1883:1883 -p 5683:5683/udp -p 5685:5685/udp -p 5686:5686/udp -v ~/.mytb-data:/data --name mytb thingsboard/tb
`
Where:
@ -32,6 +32,7 @@ Where:
- `-p 1883:1883` - connect local port 1883 to exposed internal MQTT port 1883
- `-p 5683:5683` - connect local port 5683 to exposed internal COAP port 5683
- `-p 5685:5685` - connect local port 5685 to exposed internal COAP port 5685 (lwm2m)
- `-p 5686:5686` - connect local port 5686 to exposed internal COAPS port 5686 (lwm2m)
- `-v ~/.mytb-data:/data` - mounts the host's dir `~/.mytb-data` to ThingsBoard DataBase data directory
- `--name mytb` - friendly local name of this machine
- `thingsboard/tb` - docker image, can be also `thingsboard/tb-postgres` or `thingsboard/tb-cassandra`
@ -47,6 +48,7 @@ Where:
> $ VBoxManage controlvm "default" natpf1 "tcp-port1883,tcp,,1883,,1883"
> $ VBoxManage controlvm "default" natpf1 "tcp-port5683,tcp,,5683,,5683"
> $ VBoxManage controlvm "default" natpf1 "tcp-port5683,tcp,,5685,,5685"
> $ VBoxManage controlvm "default" natpf1 "tcp-port5683,tcp,,5686,,5686"
> ```
After executing `docker run` command you can open `http://{your-host-ip}:9090` in you browser (for ex. `http://localhost:9090`). You should see ThingsBoard login page.

View File

@ -87,6 +87,7 @@ EXPOSE 9090
EXPOSE 1883
EXPOSE 5683/udp
EXPOSE 5685/udp
EXPOSE 5686/udp
VOLUME ["/data"]

View File

@ -69,6 +69,7 @@ EXPOSE 9090
EXPOSE 1883
EXPOSE 5683/udp
EXPOSE 5685/udp
EXPOSE 5686/udp
VOLUME ["/data"]