Browse Source

Lwm2m discovery (#4438)

* Lwm2m: fix bug delete zero updateAttribute

* Lwm2m: front add select binding

* Lwm2m: discovery only for test

* Lwm2m: remove type_cast_enabled from the main branch.

* Lwm2m: remove type_cast_enabled from the main branch.

* Lwm2m: remove type_cast_enabled from the main branch.

* Lwm2m: remove double code.
pull/4470/head
nickAS21 5 years ago
committed by GitHub
parent
commit
51b0d50542
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 5
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapSecurityStore.java
  2. 6
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mServerListener.java
  3. 134
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportContextServer.java
  4. 16
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportHandler.java
  5. 12
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportRequest.java
  6. 276
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportServiceImpl.java
  7. 8
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java
  8. 4
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContextImpl.java
  9. 34
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/ResultsAddKeyValueProto.java
  10. 32
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/ResultsResourceValue.java
  11. 23
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2mValueConverterImpl.java
  12. 21
      transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml
  13. 17
      ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.html
  14. 8
      ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.ts
  15. 32
      ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-profile-config.models.ts

5
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapSecurityStore.java

@ -35,7 +35,6 @@ import org.thingsboard.server.transport.lwm2m.secure.LwM2mCredentialsSecurityInf
import org.thingsboard.server.transport.lwm2m.secure.ReadResultSecurityStore;
import org.thingsboard.server.transport.lwm2m.server.LwM2mSessionMsgListener;
import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportContextServer;
import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler;
import org.thingsboard.server.transport.lwm2m.utils.TypeServer;
import java.io.IOException;
@ -165,13 +164,13 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore {
lwM2MBootstrapConfig.bootstrapServer = new LwM2MServerBootstrap(lwM2MBootstrapConfig.bootstrapServer, profileServerBootstrap);
lwM2MBootstrapConfig.lwm2mServer = new LwM2MServerBootstrap(lwM2MBootstrapConfig.lwm2mServer, profileLwm2mServer);
String logMsg = String.format("%s: getParametersBootstrap: %s Access connect client with bootstrap server.", LOG_LW2M_INFO, store.getEndPoint());
context.sendParametersOnThingsboard(context.getTelemetryMsgObject(logMsg), LwM2mTransportHandler.DEVICE_TELEMETRY_TOPIC, sessionInfo);
context.sendParametersOnThingsboardTelemetry(context.getKvLogyToThingsboard(logMsg), sessionInfo);
return lwM2MBootstrapConfig;
} else {
log.error(" [{}] Different values SecurityMode between of client and profile.", store.getEndPoint());
log.error("{} getParametersBootstrap: [{}] Different values SecurityMode between of client and profile.", LOG_LW2M_ERROR, store.getEndPoint());
String logMsg = String.format("%s: getParametersBootstrap: %s Different values SecurityMode between of client and profile.", LOG_LW2M_ERROR, store.getEndPoint());
context.sendParametersOnThingsboard(context.getTelemetryMsgObject(logMsg), LwM2mTransportHandler.DEVICE_TELEMETRY_TOPIC, sessionInfo);
context.sendParametersOnThingsboardTelemetry(context.getKvLogyToThingsboard(logMsg), sessionInfo);
return null;
}
}

6
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mServerListener.java

@ -26,7 +26,7 @@ import org.eclipse.leshan.server.registration.RegistrationUpdate;
import java.util.Collection;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.convertToIdVerFromObjectId;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.convertPathFromObjectIdToIdVer;
@Slf4j
public class LwM2mServerListener {
@ -92,7 +92,7 @@ public class LwM2mServerListener {
public void onResponse(Observation observation, Registration registration, ObserveResponse response) {
if (registration != null) {
try {
service.onObservationResponse(registration, convertToIdVerFromObjectId(observation.getPath().toString(), registration), response);
service.onObservationResponse(registration, convertPathFromObjectIdToIdVer(observation.getPath().toString(), registration), response);
} catch (Exception e) {
log.error("[{}] onResponse", e.toString());
@ -107,7 +107,7 @@ public class LwM2mServerListener {
@Override
public void newObservation(Observation observation, Registration registration) {
// log.info("Received newObservation from [{}] endpoint [{}] ", observation.getPath(), registration.getEndpoint());
log.info("Received newObservation from [{}] endpoint [{}] ", observation.getPath(), registration.getEndpoint());
}
};

134
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportContextServer.java

@ -30,31 +30,33 @@ package org.thingsboard.server.transport.lwm2m.server;
* limitations under the License.
*/
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.leshan.core.model.DDFFileParser;
import org.eclipse.leshan.core.model.DefaultDDFFileValidator;
import org.eclipse.leshan.core.model.InvalidDDFFileException;
import org.eclipse.leshan.core.model.ObjectModel;
import org.eclipse.leshan.core.model.ResourceModel;
import org.eclipse.leshan.core.node.codec.CodecException;
import org.springframework.stereotype.Component;
import org.thingsboard.server.common.transport.TransportContext;
import org.thingsboard.server.common.transport.TransportResourceCache;
import org.thingsboard.server.common.transport.TransportService;
import org.thingsboard.server.common.transport.TransportServiceCallback;
import org.thingsboard.server.common.transport.adaptor.AdaptorException;
import org.thingsboard.server.common.transport.lwm2m.LwM2MTransportConfigServer;
import org.thingsboard.server.gen.transport.TransportProtos;
import org.thingsboard.server.gen.transport.TransportProtos.PostAttributeMsg;
import org.thingsboard.server.gen.transport.TransportProtos.PostTelemetryMsg;
import org.thingsboard.server.gen.transport.TransportProtos.SessionInfoProto;
import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceCredentialsResponseMsg;
import org.thingsboard.server.queue.util.TbLwM2mTransportComponent;
import org.thingsboard.server.transport.lwm2m.server.adaptors.LwM2MJsonAdaptor;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import static org.thingsboard.server.gen.transport.TransportProtos.KeyValueType.BOOLEAN_V;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.LOG_LW2M_TELEMETRY;
@Slf4j
@ -91,7 +93,7 @@ public class LwM2mTransportContextServer extends TransportContext {
/**
* send to Thingsboard Attribute || Telemetry
*
* @param msg - JsonObject: [{name: value}]
* @param msg - JsonObject: [{name: value}]
* @return - dummy
*/
private <T> TransportServiceCallback<Void> getPubAckCallbackSendAttrTelemetry(final T msg) {
@ -108,33 +110,29 @@ public class LwM2mTransportContextServer extends TransportContext {
};
}
public void sendParametersOnThingsboard(JsonElement msg, String topicName, SessionInfoProto sessionInfo) {
try {
if (topicName.equals(LwM2mTransportHandler.DEVICE_ATTRIBUTES_TOPIC)) {
PostAttributeMsg postAttributeMsg = adaptor.convertToPostAttributes(msg);
TransportServiceCallback call = this.getPubAckCallbackSendAttrTelemetry(postAttributeMsg);
transportService.process(sessionInfo, postAttributeMsg, this.getPubAckCallbackSendAttrTelemetry(call));
} else if (topicName.equals(LwM2mTransportHandler.DEVICE_TELEMETRY_TOPIC)) {
PostTelemetryMsg postTelemetryMsg = adaptor.convertToPostTelemetry(msg);
TransportServiceCallback call = this.getPubAckCallbackSendAttrTelemetry(postTelemetryMsg);
transportService.process(sessionInfo, postTelemetryMsg, this.getPubAckCallbackSendAttrTelemetry(call));
}
} catch (AdaptorException e) {
log.error("[{}] Failed to process publish msg [{}]", topicName, e);
log.info("[{}] Closing current session due to invalid publish", topicName);
}
public void sendParametersOnThingsboardAttribute(List<TransportProtos.KeyValueProto> result, SessionInfoProto sessionInfo) {
PostAttributeMsg.Builder request = PostAttributeMsg.newBuilder();
request.addAllKv(result);
PostAttributeMsg postAttributeMsg = request.build();
TransportServiceCallback call = this.getPubAckCallbackSendAttrTelemetry(postAttributeMsg);
transportService.process(sessionInfo, postAttributeMsg, this.getPubAckCallbackSendAttrTelemetry(call));
}
public JsonObject getTelemetryMsgObject(String logMsg) {
JsonObject telemetries = new JsonObject();
telemetries.addProperty(LOG_LW2M_TELEMETRY, logMsg);
return telemetries;
public void sendParametersOnThingsboardTelemetry(List<TransportProtos.KeyValueProto> result, SessionInfoProto sessionInfo) {
PostTelemetryMsg.Builder request = PostTelemetryMsg.newBuilder();
TransportProtos.TsKvListProto.Builder builder = TransportProtos.TsKvListProto.newBuilder();
builder.setTs(System.currentTimeMillis());
builder.addAllKv(result);
request.addTsKvList(builder.build());
PostTelemetryMsg postTelemetryMsg = request.build();
TransportServiceCallback call = this.getPubAckCallbackSendAttrTelemetry(postTelemetryMsg);
transportService.process(sessionInfo, postTelemetryMsg, this.getPubAckCallbackSendAttrTelemetry(call));
}
/**
* @return - sessionInfo after access connect client
*/
public SessionInfoProto getValidateSessionInfo(ValidateDeviceCredentialsResponseMsg msg, long mostSignificantBits, long leastSignificantBits) {
public SessionInfoProto getValidateSessionInfo(TransportProtos.ValidateDeviceCredentialsResponseMsg msg, long mostSignificantBits, long leastSignificantBits) {
return SessionInfoProto.newBuilder()
.setNodeId(this.getNodeId())
.setSessionIdMSB(mostSignificantBits)
@ -159,4 +157,90 @@ public class LwM2mTransportContextServer extends TransportContext {
return null;
}
}
/**
*
* @param logMsg - info about Logs
* @return- KeyValueProto for telemetry (Logs)
*/
public List <TransportProtos.KeyValueProto> getKvLogyToThingsboard(String logMsg) {
List <TransportProtos.KeyValueProto> result = new ArrayList<>();
result.add(TransportProtos.KeyValueProto.newBuilder()
.setKey(LOG_LW2M_TELEMETRY)
.setType(TransportProtos.KeyValueType.STRING_V)
.setStringV(logMsg).build());
return result;
}
/**
* @return - KeyValueProto for attribute/telemetry (change value)
* @throws CodecException -
*/
public TransportProtos.KeyValueProto getKvAttrTelemetryToThingsboard(ResourceModel.Type resourceType, String resourceName, Object value, boolean isMultiInstances) {
TransportProtos.KeyValueProto.Builder kvProto = TransportProtos.KeyValueProto.newBuilder().setKey(resourceName);
if (isMultiInstances) {
kvProto.setType(TransportProtos.KeyValueType.JSON_V)
.setJsonV((String) value);
}
else {
switch (resourceType) {
case BOOLEAN:
kvProto.setType(BOOLEAN_V).setBoolV((Boolean) value).build();
break;
case STRING:
case TIME:
case OPAQUE:
case OBJLNK:
kvProto.setType(TransportProtos.KeyValueType.STRING_V).setStringV((String) value);
break;
case INTEGER:
kvProto.setType(TransportProtos.KeyValueType.LONG_V).setLongV((Long) value);
break;
case FLOAT:
kvProto.setType(TransportProtos.KeyValueType.DOUBLE_V).setDoubleV((Double) value);
}
}
return kvProto.build();
}
/**
*
* @param currentType -
* @param resourcePath -
* @return
*/
public ResourceModel.Type getResourceModelTypeEqualsKvProtoValueType(ResourceModel.Type currentType, String resourcePath) {
switch (currentType) {
case BOOLEAN:
return ResourceModel.Type.BOOLEAN;
case STRING:
case TIME:
case OPAQUE:
case OBJLNK:
return ResourceModel.Type.STRING;
case INTEGER:
return ResourceModel.Type.INTEGER;
case FLOAT:
return ResourceModel.Type.FLOAT;
default:
}
throw new CodecException("Invalid ResourceModel_Type for resource %s, got %s", resourcePath, currentType);
}
public Object getValueFromKvProto (TransportProtos.KeyValueProto kv) {
switch (kv.getType()) {
case BOOLEAN_V:
return kv.getBoolV();
case LONG_V:
return kv.getLongV();
case DOUBLE_V:
return kv.getDoubleV();
case STRING_V:
return kv.getStringV();
case JSON_V:
return kv.getJsonV();
}
return null;
}
}

16
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportHandler.java

@ -75,6 +75,8 @@ public class LwM2mTransportHandler {
public static final String KEY_NAME = "keyName";
public static final String OBSERVE = "observe";
public static final String ATTRIBUTE_LWM2M = "attributeLwm2m";
public static final String RESOURCE_VALUE = "resValue";
public static final String RESOURCE_TYPE = "resType";
private static final String REQUEST = "/request";
private static final String RESPONSE = "/response";
@ -333,28 +335,30 @@ public class LwM2mTransportHandler {
};
}
public static String convertToObjectIdFromIdVer(String key) {
public static String convertPathFromIdVerToObjectId(String pathIdVer) {
try {
String[] keyArray = key.split(LWM2M_SEPARATOR_PATH);
String[] keyArray = pathIdVer.split(LWM2M_SEPARATOR_PATH);
if (keyArray.length > 1 && keyArray[1].split(LWM2M_SEPARATOR_KEY).length == 2) {
keyArray[1] = keyArray[1].split(LWM2M_SEPARATOR_KEY)[0];
return StringUtils.join(keyArray, LWM2M_SEPARATOR_PATH);
} else {
return key;
}
else {
return pathIdVer;
}
} catch (Exception e) {
return null;
}
}
public static String convertToIdVerFromObjectId(String path, Registration registration) {
public static String convertPathFromObjectIdToIdVer(String path, Registration registration) {
String ver = registration.getSupportedObject().get(new LwM2mPath(path).getObjectId());
try {
String[] keyArray = path.split(LWM2M_SEPARATOR_PATH);
if (keyArray.length > 1) {
keyArray[1] = keyArray[1] + LWM2M_SEPARATOR_KEY + ver;
return StringUtils.join(keyArray, LWM2M_SEPARATOR_PATH);
} else {
}
else {
return path;
}
} catch (Exception e) {

12
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportRequest.java

@ -69,8 +69,8 @@ import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandle
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.PUT_TYPE_OPER_WRITE_ATTRIBUTES;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.PUT_TYPE_OPER_WRITE_UPDATE;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.RESPONSE_CHANNEL;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.convertToIdVerFromObjectId;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.convertToObjectIdFromIdVer;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.convertPathFromIdVerToObjectId;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.convertPathFromObjectIdToIdVer;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.createWriteAttributeRequest;
@Slf4j
@ -114,7 +114,7 @@ public class LwM2mTransportRequest {
*/
public void sendAllRequest(Registration registration, String targetIdVer, String typeOper,
String contentFormatParam, Observation observation, Object params, long timeoutInMs) {
String target = convertToObjectIdFromIdVer(targetIdVer);
String target = convertPathFromIdVerToObjectId(targetIdVer);
LwM2mPath resultIds = new LwM2mPath(target);
if (registration != null && resultIds.getObjectId() >= 0) {
DownlinkRequest request = null;
@ -204,7 +204,7 @@ public class LwM2mTransportRequest {
private void sendRequest(Registration registration, LwM2mClient lwM2MClient, DownlinkRequest request, long timeoutInMs) {
leshanServer.send(registration, request, timeoutInMs, (ResponseCallback<?>) response -> {
if (!lwM2MClient.isInit()) {
lwM2MClient.initValue(this.serviceImpl, convertToIdVerFromObjectId(request.getPath().toString(), registration));
lwM2MClient.initValue(this.serviceImpl, convertPathFromObjectIdToIdVer(request.getPath().toString(), registration));
}
if (CoAP.ResponseCode.isSuccess(((Response) response.getCoapResponse()).getCode())) {
this.handleResponse(registration, request.getPath().toString(), response, request);
@ -228,7 +228,7 @@ public class LwM2mTransportRequest {
}
}, e -> {
if (!lwM2MClient.isInit()) {
lwM2MClient.initValue(this.serviceImpl, convertToIdVerFromObjectId(request.getPath().toString(), registration));
lwM2MClient.initValue(this.serviceImpl, convertPathFromObjectIdToIdVer(request.getPath().toString(), registration));
}
String msg = String.format("%s: sendRequest: Resource path - %s msg error - %s SendRequest to Client",
LOG_LW2M_ERROR, request.getPath().toString(), e.toString());
@ -287,7 +287,7 @@ public class LwM2mTransportRequest {
* @param response -
*/
private void sendResponse(Registration registration, String path, LwM2mResponse response, DownlinkRequest request) {
String pathIdVer = convertToIdVerFromObjectId(path, registration);
String pathIdVer = convertPathFromObjectIdToIdVer(path, registration);
if (response instanceof ReadResponse) {
serviceImpl.onObservationResponse(registration, pathIdVer, (ReadResponse) response);
} else if (response instanceof CancelObservationResponse) {

276
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportServiceImpl.java

@ -18,6 +18,7 @@ package org.thingsboard.server.transport.lwm2m.server;
import com.fasterxml.jackson.core.type.TypeReference;
import com.google.common.collect.Sets;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
@ -42,7 +43,6 @@ import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.DeviceProfile;
import org.thingsboard.server.common.transport.TransportService;
import org.thingsboard.server.common.transport.adaptor.AdaptorException;
import org.thingsboard.server.common.transport.adaptor.JsonConverter;
import org.thingsboard.server.common.transport.service.DefaultTransportService;
import org.thingsboard.server.gen.transport.TransportProtos;
import org.thingsboard.server.gen.transport.TransportProtos.AttributeUpdateNotificationMsg;
@ -52,12 +52,12 @@ import org.thingsboard.server.queue.util.TbLwM2mTransportComponent;
import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient;
import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientContext;
import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientProfile;
import org.thingsboard.server.transport.lwm2m.server.client.ResultsAddKeyValueProto;
import org.thingsboard.server.transport.lwm2m.server.client.ResultsAnalyzerParameters;
import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl;
import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.LinkedHashSet;
@ -76,24 +76,19 @@ import java.util.stream.Collectors;
import static org.eclipse.leshan.core.attributes.Attribute.OBJECT_VERSION;
import static org.thingsboard.server.common.data.lwm2m.LwM2mConstants.LWM2M_SEPARATOR_PATH;
import static org.thingsboard.server.common.transport.util.JsonUtils.getJsonObject;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.CLIENT_NOT_AUTHORIZED;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.DEVICE_ATTRIBUTES_REQUEST;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.DEVICE_ATTRIBUTES_TOPIC;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.DEVICE_TELEMETRY_TOPIC;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.GET_TYPE_OPER_DISCOVER;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.GET_TYPE_OPER_OBSERVE;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.GET_TYPE_OPER_READ;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.LOG_LW2M_ERROR;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.LOG_LW2M_INFO;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.LOG_LW2M_TELEMETRY;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.LWM2M_STRATEGY_2;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.POST_TYPE_OPER_EXECUTE;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.POST_TYPE_OPER_WRITE_REPLACE;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.PUT_TYPE_OPER_WRITE_ATTRIBUTES;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.SERVICE_CHANNEL;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.convertToIdVerFromObjectId;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.convertToObjectIdFromIdVer;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.convertPathFromIdVerToObjectId;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.getAckCallback;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.validateObjectVerFromKey;
@ -163,6 +158,7 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
transportService.registerAsyncSession(sessionInfo, new LwM2mSessionMsgListener(this, sessionInfo));
transportService.process(sessionInfo, DefaultTransportService.getSessionEventMsg(SessionEvent.OPEN), null);
transportService.process(sessionInfo, TransportProtos.SubscribeToAttributeUpdatesMsg.newBuilder().build(), null);
transportService.process(sessionInfo, TransportProtos.SubscribeToRPCMsg.newBuilder().build(), null);
this.initLwM2mFromClientValue(registration, lwM2MClient);
this.sendLogsToThingsboard(LOG_LW2M_INFO + ": Client create after Registration", registration);
} else {
@ -309,33 +305,32 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
@Override
public void onAttributeUpdate(AttributeUpdateNotificationMsg msg, TransportProtos.SessionInfoProto sessionInfo) {
if (msg.getSharedUpdatedCount() > 0) {
JsonElement el = JsonConverter.toJson(msg);
el.getAsJsonObject().entrySet().forEach(de -> {
String pathIdVer = this.getPathAttributeUpdate(sessionInfo, de.getKey());
String value = de.getValue().getAsString();
msg.getSharedUpdatedList().forEach(tsKvProto -> {
String pathName = tsKvProto.getKv().getKey();
String pathIdVer = this.validatePathIntoProfile(sessionInfo, pathName);
Object valueNew = this.lwM2mTransportContextServer.getValueFromKvProto(tsKvProto.getKv());
LwM2mClient lwM2MClient = lwM2mClientContext.getLwM2mClient(new UUID(sessionInfo.getSessionIdMSB(), sessionInfo.getSessionIdLSB()));
LwM2mClientProfile clientProfile = lwM2mClientContext.getProfile(new UUID(sessionInfo.getDeviceProfileIdMSB(), sessionInfo.getDeviceProfileIdLSB()));
if (pathIdVer != null && !pathIdVer.isEmpty() && (this.validatePathInAttrProfile(clientProfile, pathIdVer) || this.validatePathInTelemetryProfile(clientProfile, pathIdVer))) {
if (pathIdVer != null) {
ResourceModel resourceModel = lwM2MClient.getResourceModel(pathIdVer);
if (resourceModel != null && resourceModel.operations.isWritable()) {
lwM2mTransportRequest.sendAllRequest(lwM2MClient.getRegistration(), pathIdVer, POST_TYPE_OPER_WRITE_REPLACE,
ContentFormat.TLV.getName(), null, value, this.lwM2mTransportContextServer.getLwM2MTransportConfigServer().getTimeout());
this.updateResourcesValueToClient(lwM2MClient, this.getResourceValueFormatKv(lwM2MClient, pathIdVer), valueNew, pathIdVer);
} else {
log.error("Resource path - [{}] value - [{}] is not Writable and cannot be updated", pathIdVer, value);
log.error("Resource path - [{}] value - [{}] is not Writable and cannot be updated", pathIdVer, valueNew);
String logMsg = String.format("%s: attributeUpdate: Resource path - %s value - %s is not Writable and cannot be updated",
LOG_LW2M_ERROR, pathIdVer, value);
LOG_LW2M_ERROR, pathIdVer, valueNew);
this.sendLogsToThingsboard(logMsg, lwM2MClient.getRegistration());
}
} else {
log.error("Attribute name - [{}] value - [{}] is not present as attribute in profile and cannot be updated", de.getKey(), value);
log.error("Resource name name - [{}] value - [{}] is not present as attribute/telemetry in profile and cannot be updated", pathName, valueNew);
String logMsg = String.format("%s: attributeUpdate: attribute name - %s value - %s is not present as attribute in profile and cannot be updated",
LOG_LW2M_ERROR, de.getKey(), value);
LOG_LW2M_ERROR, pathName, valueNew);
this.sendLogsToThingsboard(logMsg, lwM2MClient.getRegistration());
}
});
} else if (msg.getSharedDeletedCount() > 0) {
log.info("[{}] delete [{}] onAttributeUpdate", msg.getSharedDeletedList(), sessionInfo);
}
}
/**
@ -462,32 +457,13 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
}
/**
* @param msg - text msg
* @param logMsg - text msg
* @param registration - Id of Registration LwM2M Client
*/
public void sendLogsToThingsboard(String msg, Registration registration) {
if (msg != null) {
JsonObject telemetries = new JsonObject();
telemetries.addProperty(LOG_LW2M_TELEMETRY, msg);
this.updateParametersOnThingsboard(telemetries, DEVICE_TELEMETRY_TOPIC, registration);
}
}
/**
* // !!! Ok
* Prepare send to Thigsboard callback - Attribute or Telemetry
*
* @param msg - JsonArray: [{name: value}]
* @param topicName - Api Attribute or Telemetry
* @param registration - Id of Registration LwM2M Client
*/
public void updateParametersOnThingsboard(JsonElement msg, String topicName, Registration registration) {
public void sendLogsToThingsboard(String logMsg, Registration registration) {
SessionInfoProto sessionInfo = this.getValidateSessionInfo(registration);
if (sessionInfo != null) {
lwM2mTransportContextServer.sendParametersOnThingsboard(msg, topicName, sessionInfo);
} else {
log.error("Client: [{}] updateParametersOnThingsboard [{}] sessionInfo ", registration, null);
if (logMsg != null && sessionInfo != null) {
this.lwM2mTransportContextServer.sendParametersOnThingsboardTelemetry(this.lwM2mTransportContextServer.getKvLogyToThingsboard(logMsg), sessionInfo);
}
}
@ -517,7 +493,7 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
this.initReadAttrTelemetryObserveToClient(registration, lwM2MClient, GET_TYPE_OPER_READ, clientObjects);
this.initReadAttrTelemetryObserveToClient(registration, lwM2MClient, GET_TYPE_OPER_OBSERVE, clientObjects);
this.initReadAttrTelemetryObserveToClient(registration, lwM2MClient, PUT_TYPE_OPER_WRITE_ATTRIBUTES, clientObjects);
// this.initReadAttrTelemetryObserveToClient(registration, lwM2MClient, GET_TYPE_OPER_DISCOVER, clientObjects);
this.initReadAttrTelemetryObserveToClient(registration, lwM2MClient, GET_TYPE_OPER_DISCOVER, clientObjects);
}
}
@ -577,17 +553,20 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
* @param registration - Registration LwM2M Client
*/
private void updateAttrTelemetry(Registration registration, Set<String> paths) {
JsonObject attributes = new JsonObject();
JsonObject telemetries = new JsonObject();
try {
this.getParametersFromProfile(attributes, telemetries, registration, paths);
ResultsAddKeyValueProto results = getParametersFromProfile(registration, paths);
SessionInfoProto sessionInfo = this.getValidateSessionInfo(registration);
if (results != null && sessionInfo != null) {
if (results.getResultAttributes().size() > 0) {
this.lwM2mTransportContextServer.sendParametersOnThingsboardAttribute(results.getResultAttributes(), sessionInfo);
}
if (results.getResultTelemetries().size() > 0) {
this.lwM2mTransportContextServer.sendParametersOnThingsboardTelemetry(results.getResultTelemetries(), sessionInfo);
}
}
} catch (Exception e) {
log.error("UpdateAttrTelemetry", e);
}
if (attributes.getAsJsonObject().entrySet().size() > 0)
this.updateParametersOnThingsboard(attributes, DEVICE_ATTRIBUTES_TOPIC, registration);
if (telemetries.getAsJsonObject().entrySet().size() > 0)
this.updateParametersOnThingsboard(telemetries, DEVICE_TELEMETRY_TOPIC, registration);
}
/**
@ -700,73 +679,99 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
}
/**
* @param registration -
* @return all instances in client
*/
private Set<String> getAllInstancesInClient(Registration registration) {
Set<String> clientInstances = ConcurrentHashMap.newKeySet();
Arrays.stream(registration.getObjectLinks()).forEach(url -> {
LwM2mPath pathIds = new LwM2mPath(url.getUrl());
if (pathIds.isObjectInstance()) {
clientInstances.add(convertToIdVerFromObjectId(url.getUrl(), registration));
}
});
return (clientInstances.size() > 0) ? clientInstances : null;
}
/**
* @param attributes - new JsonObject
* @param telemetry - new JsonObject
* // * @param attributes - new JsonObject
* // * @param telemetry - new JsonObject
*
* @param registration - Registration LwM2M Client
* @param path -
*/
private void getParametersFromProfile(JsonObject attributes, JsonObject telemetry, Registration registration, Set<String> path) {
private ResultsAddKeyValueProto getParametersFromProfile(Registration registration, Set<String> path) {
if (path != null && path.size() > 0) {
ResultsAddKeyValueProto results = new ResultsAddKeyValueProto();
LwM2mClientProfile lwM2MClientProfile = lwM2mClientContext.getProfile(registration);
lwM2MClientProfile.getPostAttributeProfile().forEach(idVer -> {
if (path.contains(idVer.getAsString())) {
this.addParameters(idVer.getAsString(), attributes, registration);
List<TransportProtos.KeyValueProto> resultAttributes = new ArrayList<>();
lwM2MClientProfile.getPostAttributeProfile().forEach(pathIdVer -> {
if (path.contains(pathIdVer.getAsString())) {
TransportProtos.KeyValueProto kvAttr = this.getKvToThingsboard(pathIdVer.getAsString(), registration);
if (kvAttr != null) {
resultAttributes.add(kvAttr);
}
}
});
lwM2MClientProfile.getPostTelemetryProfile().forEach(idVer -> {
if (path.contains(idVer.getAsString())) {
this.addParameters(idVer.getAsString(), telemetry, registration);
List<TransportProtos.KeyValueProto> resultTelemetries = new ArrayList<>();
lwM2MClientProfile.getPostTelemetryProfile().forEach(pathIdVer -> {
if (path.contains(pathIdVer.getAsString())) {
TransportProtos.KeyValueProto kvAttr = this.getKvToThingsboard(pathIdVer.getAsString(), registration);
if (kvAttr != null) {
resultTelemetries.add(kvAttr);
}
}
});
if (resultAttributes.size() > 0) {
results.setResultAttributes(resultAttributes);
}
if (resultTelemetries.size() > 0) {
results.setResultTelemetries(resultTelemetries);
}
return results;
}
return null;
}
/**
* @param parameters - JsonObject attributes/telemetry
* @param registration - Registration LwM2M Client
*/
private void addParameters(String path, JsonObject parameters, Registration registration) {
LwM2mClient lwM2MClient = lwM2mClientContext.getLwM2mClientWithReg(registration, null);
// public TransportProtos.KeyValueProto getKvToThingsboard(String pathIdVer, Registration registration) {
// ResultsResourceValue resultsResourceValue = getResultsResourceValue(pathIdVer, registration);
// return resultsResourceValue != null ? this.lwM2mTransportContextServer.getKvAttrTelemetryToThingsboard(resultsResourceValue) : null;
// }
private TransportProtos.KeyValueProto getKvToThingsboard(String pathIdVer, Registration registration) {
LwM2mClient lwM2MClient = this.lwM2mClientContext.getLwM2mClientWithReg(null, registration.getId());
JsonObject names = lwM2mClientContext.getProfiles().get(lwM2MClient.getProfileId()).getPostKeyNameProfile();
if (names != null && names.has(path)) {
String resName = names.get(path).getAsString();
if (resName != null && !resName.isEmpty()) {
if (names != null && names.has(pathIdVer)) {
String resourceName = names.get(pathIdVer).getAsString();
if (resourceName != null && !resourceName.isEmpty()) {
try {
String resValue = this.getResourceValueToString(lwM2MClient, path);
parameters.addProperty(resName, resValue);
LwM2mResource resourceValue = lwM2MClient != null ? getResourceValueFromLwM2MClient(lwM2MClient, pathIdVer) : null;
if (resourceValue != null) {
ResourceModel.Type currentType = resourceValue.getType();
ResourceModel.Type expectedType = this.lwM2mTransportContextServer.getResourceModelTypeEqualsKvProtoValueType(currentType, pathIdVer);
Object valueKvProto = null;
if (resourceValue.isMultiInstances()) {
valueKvProto = new JsonObject();
Object finalvalueKvProto = valueKvProto;
Gson gson = new GsonBuilder().create();
resourceValue.getValues().forEach((k, v) -> {
Object val = this.converter.convertValue(resourceValue.getValue(), currentType, expectedType,
new LwM2mPath(convertPathFromIdVerToObjectId(pathIdVer)));
JsonElement element = gson.toJsonTree(val, val.getClass());
((JsonObject) finalvalueKvProto).add(String.valueOf(k), element);
});
valueKvProto = gson.toJson(valueKvProto);
} else {
valueKvProto = this.converter.convertValue(resourceValue.getValue(), currentType, expectedType,
new LwM2mPath(convertPathFromIdVerToObjectId(pathIdVer)));
}
return valueKvProto != null ? this.lwM2mTransportContextServer.getKvAttrTelemetryToThingsboard(currentType, resourceName, valueKvProto, resourceValue.isMultiInstances()) : null;
}
} catch (Exception e) {
log.error("Failed to add parameters.", e);
}
}
} else {
log.error("Failed to add parameters. path: [{}], names: [{}]", path, names);
log.error("Failed to add parameters. path: [{}], names: [{}]", pathIdVer, names);
}
return null;
}
/**
* @param path - path resource
* @return - value of Resource or null
* @param pathIdVer - path resource
* @return - value of Resource into format KvProto or null
*/
private String getResourceValueToString(LwM2mClient lwM2MClient, String path) {
LwM2mPath pathIds = new LwM2mPath(convertToObjectIdFromIdVer(path));
LwM2mResource resourceValue = this.returnResourceValueFromLwM2MClient(lwM2MClient, path);
return resourceValue == null ? null :
this.converter.convertValue(resourceValue.isMultiInstances() ? resourceValue.getValues() : resourceValue.getValue(), resourceValue.getType(), ResourceModel.Type.STRING, pathIds).toString();
private Object getResourceValueFormatKv(LwM2mClient lwM2MClient, String pathIdVer) {
LwM2mResource resourceValue = this.getResourceValueFromLwM2MClient(lwM2MClient, pathIdVer);
ResourceModel.Type currentType = resourceValue.getType();
ResourceModel.Type expectedType = this.lwM2mTransportContextServer.getResourceModelTypeEqualsKvProtoValueType(currentType, pathIdVer);
return this.converter.convertValue(resourceValue.getValue(), currentType, expectedType,
new LwM2mPath(convertPathFromIdVerToObjectId(pathIdVer)));
}
/**
@ -774,9 +779,9 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
* @param path -
* @return - return value of Resource by idPath
*/
private LwM2mResource returnResourceValueFromLwM2MClient(LwM2mClient lwM2MClient, String path) {
private LwM2mResource getResourceValueFromLwM2MClient(LwM2mClient lwM2MClient, String path) {
LwM2mResource resourceValue = null;
if (new LwM2mPath(convertToObjectIdFromIdVer(path)).isResource()) {
if (new LwM2mPath(convertPathFromIdVerToObjectId(path)).isResource()) {
resourceValue = lwM2MClient.getResources().get(path).getLwM2mResource();
}
return resourceValue;
@ -959,7 +964,7 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
*/
private void readResourceValueObserve(Registration registration, Set<String> targets, String typeOper) {
targets.forEach(target -> {
LwM2mPath pathIds = new LwM2mPath(convertToObjectIdFromIdVer(target));
LwM2mPath pathIds = new LwM2mPath(convertPathFromIdVerToObjectId(target));
if (pathIds.isResource()) {
if (GET_TYPE_OPER_READ.equals(typeOper)) {
lwM2mTransportRequest.sendAllRequest(registration, target, typeOper,
@ -1050,19 +1055,23 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
private void cancelObserveIsValue(Registration registration, Set<String> paramAnallyzer) {
LwM2mClient lwM2MClient = lwM2mClientContext.getLwM2mClientWithReg(registration, null);
paramAnallyzer.forEach(p -> {
if (this.returnResourceValueFromLwM2MClient(lwM2MClient, p) != null) {
this.setCancelObservationRecourse(registration, convertToObjectIdFromIdVer(p));
if (this.getResourceValueFromLwM2MClient(lwM2MClient, p) != null) {
this.setCancelObservationRecourse(registration, convertPathFromIdVerToObjectId(p));
}
}
);
}
private void putDelayedUpdateResourcesClient(LwM2mClient lwM2MClient, Object valueOld, Object valueNew, String path) {
private void updateResourcesValueToClient(LwM2mClient lwM2MClient, Object valueOld, Object valueNew, String path) {
if (valueNew != null && (valueOld == null || !valueNew.toString().equals(valueOld.toString()))) {
lwM2mTransportRequest.sendAllRequest(lwM2MClient.getRegistration(), path, POST_TYPE_OPER_WRITE_REPLACE,
ContentFormat.TLV.getName(), null, valueNew, this.lwM2mTransportContextServer.getLwM2MTransportConfigServer().getTimeout());
} else {
log.error("05 delayError");
log.error("Failed update resource [{}] [{}]", path, valueNew);
String logMsg = String.format("%s: Failed update resource path - %s value - %s. Value is not changed or bad",
LOG_LW2M_ERROR, path, valueNew);
this.sendLogsToThingsboard(logMsg, lwM2MClient.getRegistration());
log.info("Failed update resource [{}] [{}]", path, valueNew);
}
}
@ -1082,9 +1091,9 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
* @param name -
* @return path if path isPresent in postProfile
*/
private String getPathAttributeUpdate(TransportProtos.SessionInfoProto sessionInfo, String name) {
String profilePath = this.getPathAttributeUpdateProfile(sessionInfo, name);
return !profilePath.isEmpty() ? profilePath : null;
private String validatePathIntoProfile(TransportProtos.SessionInfoProto sessionInfo, String name) {
String pathIdVer = this.getPresentPathIntoProfile(sessionInfo, name);
return !pathIdVer.isEmpty() ? pathIdVer : null;
}
/**
@ -1094,7 +1103,7 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
* @param name -
* @return -
*/
private String getPathAttributeUpdateProfile(TransportProtos.SessionInfoProto sessionInfo, String name) {
private String getPresentPathIntoProfile(TransportProtos.SessionInfoProto sessionInfo, String name) {
LwM2mClientProfile profile = lwM2mClientContext.getProfile(new UUID(sessionInfo.getDeviceProfileIdMSB(), sessionInfo.getDeviceProfileIdLSB()));
LwM2mClient lwM2mClient = lwM2mClientContext.getLwM2MClient(sessionInfo);
return profile.getPostKeyNameProfile().getAsJsonObject().entrySet().stream()
@ -1105,40 +1114,49 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
/**
* Update resource value on client: if there is a difference in values between the current resource values and the shared attribute values
* #1 Get path resource by result attributesResponse
* #1.1 If two names have equal path => last time attribute
* #2.1 if there is a difference in values between the current resource values and the shared attribute values
* => send to client Request Update of value (new value from shared attribute)
* and LwM2MClient.delayedRequests.add(path)
* #2.1 if there is not a difference in values between the current resource values and the shared attribute values
*
* @param attributesResponse -
* @param sessionInfo -
*/
public void onGetAttributesResponse(TransportProtos.GetAttributeResponseMsg attributesResponse, TransportProtos.SessionInfoProto sessionInfo) {
try {
LwM2mClient lwM2MClient = lwM2mClientContext.getLwM2MClient(sessionInfo);
attributesResponse.getSharedAttributeListList().forEach(attr -> {
String path = this.getPathAttributeUpdate(sessionInfo, attr.getKv().getKey());
if (path != null) {
// #1.1
if (lwM2MClient.getDelayedRequests().containsKey(path) && attr.getTs() > lwM2MClient.getDelayedRequests().get(path).getTs()) {
lwM2MClient.getDelayedRequests().put(path, attr);
} else {
lwM2MClient.getDelayedRequests().put(path, attr);
}
}
});
// #2.1
lwM2MClient.getDelayedRequests().forEach((k, v) -> {
ArrayList<TransportProtos.KeyValueProto> listV = new ArrayList<>();
listV.add(v.getKv());
this.putDelayedUpdateResourcesClient(lwM2MClient, this.getResourceValueToString(lwM2MClient, k), getJsonObject(listV).get(v.getKv().getKey()), k);
});
List<TransportProtos.TsKvProto> tsKvProtos = attributesResponse.getSharedAttributeListList();
this.updateAttriuteFromThingsboard(tsKvProtos, sessionInfo);
} catch (Exception e) {
log.error(String.valueOf(e));
}
}
/**
* #1.1 If two names have equal path => last time attribute
* #2.1 if there is a difference in values between the current resource values and the shared attribute values
* => send to client Request Update of value (new value from shared attribute)
* and LwM2MClient.delayedRequests.add(path)
* #2.1 if there is not a difference in values between the current resource values and the shared attribute values
*
* @param tsKvProtos
* @param sessionInfo
*/
public void updateAttriuteFromThingsboard(List<TransportProtos.TsKvProto> tsKvProtos, TransportProtos.SessionInfoProto sessionInfo) {
LwM2mClient lwM2MClient = lwM2mClientContext.getLwM2MClient(sessionInfo);
tsKvProtos.forEach(tsKvProto -> {
String pathIdVer = this.validatePathIntoProfile(sessionInfo, tsKvProto.getKv().getKey());
if (pathIdVer != null) {
// #1.1
if (lwM2MClient.getDelayedRequests().containsKey(pathIdVer) && tsKvProto.getTs() > lwM2MClient.getDelayedRequests().get(pathIdVer).getTs()) {
lwM2MClient.getDelayedRequests().put(pathIdVer, tsKvProto);
} else if (!lwM2MClient.getDelayedRequests().containsKey(pathIdVer)) {
lwM2MClient.getDelayedRequests().put(pathIdVer, tsKvProto);
}
}
});
// #2.1
lwM2MClient.getDelayedRequests().forEach((pathIdVer, tsKvProto) -> {
this.updateResourcesValueToClient(lwM2MClient, this.getResourceValueFormatKv(lwM2MClient, pathIdVer),
this.lwM2mTransportContextServer.getValueFromKvProto(tsKvProto.getKv()), pathIdVer);
});
}
/**
* @param lwM2MClient -
* @return SessionInfoProto -
@ -1257,7 +1275,7 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
private boolean validateResourceInModel(LwM2mClient lwM2mClient, String pathIdVer, boolean isWritableNotOptional) {
ResourceModel resourceModel = lwM2mClient.getResourceModel(pathIdVer);
Integer objectId = new LwM2mPath(convertToObjectIdFromIdVer(pathIdVer)).getObjectId();
Integer objectId = new LwM2mPath(convertPathFromIdVerToObjectId(pathIdVer)).getObjectId();
String objectVer = validateObjectVerFromKey(pathIdVer);
return resourceModel != null && (isWritableNotOptional ?
objectId != null && objectVer != null && objectVer.equals(lwM2mClient.getRegistration().getSupportedVersion(objectId)) && resourceModel.operations.isWritable() :

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

@ -39,7 +39,7 @@ import java.util.concurrent.CopyOnWriteArrayList;
import java.util.stream.Collectors;
import static org.thingsboard.server.common.data.lwm2m.LwM2mConstants.LWM2M_SEPARATOR_PATH;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.convertToObjectIdFromIdVer;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.convertPathFromIdVerToObjectId;
@Slf4j
@Data
@ -83,7 +83,7 @@ public class LwM2mClient implements Cloneable {
this.resources.get(pathRez).setLwM2mResource(rez);
return true;
} else {
LwM2mPath pathIds = new LwM2mPath(convertToObjectIdFromIdVer(pathRez));
LwM2mPath pathIds = new LwM2mPath(convertPathFromIdVerToObjectId(pathRez));
ResourceModel resourceModel = modelProvider.getObjectModel(registration).getResourceModel(pathIds.getObjectId(), pathIds.getResourceId());
if (resourceModel != null) {
this.resources.put(pathRez, new ResourceValue(rez, resourceModel));
@ -110,7 +110,7 @@ public class LwM2mClient implements Cloneable {
public void deleteResources(String pathIdVer, LwM2mModelProvider modelProvider) {
Set<String> key = getKeysEqualsIdVer(pathIdVer);
key.forEach(pathRez -> {
LwM2mPath pathIds = new LwM2mPath(convertToObjectIdFromIdVer(pathRez));
LwM2mPath pathIds = new LwM2mPath(convertPathFromIdVerToObjectId(pathRez));
ResourceModel resourceModel = modelProvider.getObjectModel(registration).getResourceModel(pathIds.getObjectId(), pathIds.getResourceId());
if (resourceModel != null) {
this.resources.get(pathRez).setResourceModel(resourceModel);
@ -132,7 +132,7 @@ public class LwM2mClient implements Cloneable {
}
private void saveResourceModel(String pathRez, LwM2mModelProvider modelProvider) {
LwM2mPath pathIds = new LwM2mPath(convertToObjectIdFromIdVer(pathRez));
LwM2mPath pathIds = new LwM2mPath(convertPathFromIdVerToObjectId(pathRez));
ResourceModel resourceModel = modelProvider.getObjectModel(registration).getResourceModel(pathIds.getObjectId(), pathIds.getResourceId());
this.resources.get(pathRez).setResourceModel(resourceModel);
}

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

@ -35,7 +35,7 @@ import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import static org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode.NO_SEC;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.convertToIdVerFromObjectId;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.convertPathFromObjectIdToIdVer;
@Service
@TbLwM2mTransportComponent
@ -185,7 +185,7 @@ public class LwM2mClientContextImpl implements LwM2mClientContext {
Arrays.stream(registration.getObjectLinks()).forEach(url -> {
LwM2mPath pathIds = new LwM2mPath(url.getUrl());
if (!pathIds.isRoot()) {
clientObjects.add(convertToIdVerFromObjectId(url.getUrl(), registration));
clientObjects.add(convertPathFromObjectIdToIdVer(url.getUrl(), registration));
}
});
return (clientObjects.size() > 0) ? clientObjects : null;

34
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/ResultsAddKeyValueProto.java

@ -0,0 +1,34 @@
/**
* Copyright © 2016-2021 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.transport.lwm2m.server.client;
import lombok.Data;
import org.thingsboard.server.gen.transport.TransportProtos;
import java.util.ArrayList;
import java.util.List;
@Data
public class ResultsAddKeyValueProto {
List<TransportProtos.KeyValueProto> resultAttributes;
List<TransportProtos.KeyValueProto> resultTelemetries;
public ResultsAddKeyValueProto() {
this.resultAttributes = new ArrayList<>();
this.resultTelemetries = new ArrayList<>();
}
}

32
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/ResultsResourceValue.java

@ -0,0 +1,32 @@
/**
* Copyright © 2016-2021 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.transport.lwm2m.server.client;
import lombok.Data;
import org.thingsboard.server.common.data.kv.DataType;
@Data
public class ResultsResourceValue {
DataType dataType;
Object value;
String resourceName;
public ResultsResourceValue (DataType dataType, Object value, String resourceName) {
this.dataType = dataType;
this.value = value;
this.resourceName = resourceName;
}
}

23
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2mValueConverterImpl.java

@ -18,14 +18,12 @@ package org.thingsboard.server.transport.lwm2m.utils;
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.eclipse.leshan.core.util.StringUtils;
import javax.xml.datatype.DatatypeConfigurationException;
import javax.xml.datatype.DatatypeFactory;
import javax.xml.datatype.XMLGregorianCalendar;
import java.math.BigInteger;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
@ -111,15 +109,16 @@ public class LwM2mValueConverterImpl implements LwM2mValueConverter {
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((Long) value);
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 {
DatatypeFactory datatypeFactory = DatatypeFactory.newInstance();
XMLGregorianCalendar cal = datatypeFactory.newXMLGregorianCalendar((String) value);
return cal.toGregorianCalendar().getTime();
} catch (DatatypeConfigurationException | IllegalArgumentException e) {
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);
@ -147,6 +146,8 @@ public class LwM2mValueConverterImpl implements LwM2mValueConverter {
return formatter.format(new Date(timeValue));
case OPAQUE:
return Hex.encodeHexString((byte[])value);
case OBJLNK:
return ObjectLink.decodeFromString((String) value);
default:
break;
}
@ -164,10 +165,14 @@ public class LwM2mValueConverterImpl implements LwM2mValueConverter {
}
}
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);
}
}
}

21
transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml

@ -119,6 +119,18 @@ redis:
# LWM2M server parameters
transport:
sessions:
inactivity_timeout: "${TB_TRANSPORT_SESSIONS_INACTIVITY_TIMEOUT:300000}"
report_timeout: "${TB_TRANSPORT_SESSIONS_REPORT_TIMEOUT:30000}"
json:
# Cast String data types to Numeric if possible when processing Telemetry/Attributes JSON
type_cast_enabled: "${JSON_TYPE_CAST_ENABLED:false}"
# Maximum allowed string value length when processing Telemetry/Attributes JSON (0 value disables string value length check)
max_string_value_length: "${JSON_MAX_STRING_VALUE_LENGTH:0}"
client_side_rpc:
timeout: "${CLIENT_SIDE_RPC_TIMEOUT:60000}"
# Enable/disable http/mqtt/coap transport protocols (has higher priority than certain protocol's 'enabled' property)
api_enabled: "${TB_TRANSPORT_API_ENABLED:true}"
# Local LwM2M transport parameters
lwm2m:
# Enable/disable lvm2m transport protocol.
@ -180,15 +192,6 @@ transport:
# Use redis for Security and Registration stores
redis.enabled: "${LWM2M_REDIS_ENABLED:false}"
sessions:
inactivity_timeout: "${TB_TRANSPORT_SESSIONS_INACTIVITY_TIMEOUT:300000}"
report_timeout: "${TB_TRANSPORT_SESSIONS_REPORT_TIMEOUT:30000}"
json:
# Cast String data types to Numeric if possible when processing Telemetry/Attributes JSON
type_cast_enabled: "${JSON_TYPE_CAST_ENABLED:true}"
# Maximum allowed string value length when processing Telemetry/Attributes JSON (0 value disables string value length check)
max_string_value_length: "${JSON_MAX_STRING_VALUE_LENGTH:0}"
queue:
type: "${TB_QUEUE_TYPE:kafka}" # kafka (Apache Kafka) or aws-sqs (AWS SQS) or pubsub (PubSub) or service-bus (Azure Service Bus) or rabbitmq (RabbitMQ)
kafka:

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

@ -82,8 +82,6 @@
<strong>{{ 'device-profile.lwm2m.required' | translate }}</strong>
</mat-error>
</mat-form-field>
</div>
<div fxLayout="row" fxLayoutGap="8px">
<mat-form-field fxFlex>
<mat-label>{{ 'device-profile.lwm2m.default-min-period' | translate }}</mat-label>
<input matInput type="number" formControlName="defaultMinPeriod" required>
@ -93,13 +91,16 @@
<strong>{{ 'device-profile.lwm2m.required' | translate }}</strong>
</mat-error>
</mat-form-field>
<mat-form-field fxFlex>
</div>
<div fxLayout="row" fxLayoutGap="8px">
<mat-form-field class="mat-block" fxFlex="100">
<mat-label>{{ 'device-profile.lwm2m.binding' | translate }}</mat-label>
<input matInput type="text" formControlName="binding" required>
<mat-error *ngIf="lwm2mDeviceProfileFormGroup.get('binding').hasError('required')">
{{ 'device-profile.lwm2m.binding' | translate }}
<strong>{{ 'device-profile.lwm2m.required' | translate }}</strong>
</mat-error>
<mat-select formControlName="binding">
<mat-option *ngFor="let bindingMode of bindingModeTypes"
[value]="bindingMode">
{{ bindingModeTypeNamesMap.get(bindingModeType[bindingMode]) }}
</mat-option>
</mat-select>
</mat-form-field>
</div>
<div>

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

@ -22,7 +22,8 @@ import { AppState } from '@app/core/core.state';
import { coerceBooleanProperty } from '@angular/cdk/coercion';
import {
ATTRIBUTE,
DEFAULT_BINDING,
BINDING_MODE,
BINDING_MODE_NAMES,
getDefaultProfileConfig,
INSTANCES,
KEY_NAME,
@ -55,6 +56,9 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro
private requiredValue: boolean;
private disabled = false;
bindingModeType = BINDING_MODE;
bindingModeTypes = Object.keys(BINDING_MODE);
bindingModeTypeNamesMap = BINDING_MODE_NAMES;
lwm2mDeviceProfileFormGroup: FormGroup;
lwm2mDeviceConfigFormGroup: FormGroup;
bootstrapServers: string;
@ -86,7 +90,7 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro
lifetime: [null, Validators.required],
defaultMinPeriod: [null, Validators.required],
notifIfDisabled: [true, []],
binding: [DEFAULT_BINDING, Validators.required],
binding:[],
bootstrapServer: [null, Validators.required],
lwm2mServer: [null, Validators.required],
});

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

@ -44,6 +44,35 @@ export const KEY_REGEXP_NUMBER = /^(\-?|\+?)\d*$/;
export const INSTANCES_ID_VALUE_MIN = 0;
export const INSTANCES_ID_VALUE_MAX = 65535;
export enum BINDING_MODE {
U = 'U',
UQ = 'UQ',
T = 'T',
TQ = 'TQ',
S = 'S',
SQ = 'SQ',
US = 'US',
TS = 'TS',
UQS = 'UQS',
TQS = 'TQS'
}
export const BINDING_MODE_NAMES = new Map<BINDING_MODE, string>(
[
[BINDING_MODE.U, 'U: UDP connection in standard mode'],
[BINDING_MODE.UQ, 'UQ: UDP connection in queue mode'],
[BINDING_MODE.US, 'US: both UDP and SMS connections active, both in standard mode'],
[BINDING_MODE.UQS, 'UQS: both UDP and SMS connections active; UDP in queue mode, SMS in standard mode'],
[BINDING_MODE.T,'T: TCP connection in standard mode'],
[BINDING_MODE.TQ, 'TQ: TCP connection in queue mode'],
[BINDING_MODE.TS, 'TS: both TCP and SMS connections active, both in standard mode'],
[BINDING_MODE.TQS, 'TQS: both TCP and SMS connections active; TCP in queue mode, SMS in standard mode'],
[BINDING_MODE.S, 'S: SMS connection in standard mode'],
[BINDING_MODE.SQ, 'SQ: SMS connection in queue mode']
]
);
export enum ATTRIBUTE_LWM2M_ENUM {
dim = 'dim',
ver = 'ver',
@ -62,8 +91,7 @@ export const ATTRIBUTE_LWM2M_LABEL = new Map<ATTRIBUTE_LWM2M_ENUM, string>(
[ATTRIBUTE_LWM2M_ENUM.pmax, 'pmax='],
[ATTRIBUTE_LWM2M_ENUM.gt, '>'],
[ATTRIBUTE_LWM2M_ENUM.lt, '<'],
[ATTRIBUTE_LWM2M_ENUM.st, 'st='],
[ATTRIBUTE_LWM2M_ENUM.st, 'st=']
]
);

Loading…
Cancel
Save