Browse Source

Merge branch 'master' of github.com:thingsboard/thingsboard

pull/4844/head
Igor Kulikov 5 years ago
parent
commit
f045e428d1
  1. 9
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/config/LwM2mVersion.java
  2. 79
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportUtil.java
  3. 36
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java
  4. 2
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContext.java
  5. 7
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContextImpl.java
  6. 12
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/ResourceValue.java
  7. 34
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/DefaultLwM2mDownlinkMsgHandler.java
  8. 7
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/LwM2mDownlinkMsgHandler.java
  9. 43
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/DefaultLwM2MRpcRequestHandler.java
  10. 15
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcReadResponseCallback.java
  11. 5
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/composite/RpcReadResponseCompositeCallback.java
  12. 3
      ui-ngx/src/app/modules/home/components/profile/device/device-profile-transport-configuration.component.ts
  13. 45
      ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.ts
  14. 20
      ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-list.component.ts
  15. 5
      ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-observe-attr-telemetry-instances.component.html
  16. 16
      ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-observe-attr-telemetry-instances.component.ts
  17. 18
      ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-observe-attr-telemetry-resources.component.ts
  18. 6
      ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-profile-config.models.ts

9
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/config/LwM2mVersion.java

@ -20,8 +20,8 @@ import org.eclipse.leshan.core.LwM2m.Version;
import org.eclipse.leshan.core.request.ContentFormat;
public enum LwM2mVersion {
VERSION_1_0(0, Version.V1_0, ContentFormat.TLV),
VERSION_1_1(1, Version.V1_1, ContentFormat.TEXT);
VERSION_1_0(0, Version.V1_0, ContentFormat.TLV, false),
VERSION_1_1(1, Version.V1_1, ContentFormat.TEXT, true);
@Getter
private final int code;
@ -29,11 +29,14 @@ public enum LwM2mVersion {
private final Version version;
@Getter
private final ContentFormat contentFormat;
@Getter
private final boolean composite;
LwM2mVersion(int code, Version version, ContentFormat contentFormat) {
LwM2mVersion(int code, Version version, ContentFormat contentFormat, boolean composite) {
this.code = code;
this.version = version;
this.contentFormat = contentFormat;
this.composite = composite;
}
public static LwM2mVersion fromVersion(Version version) {

79
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportUtil.java

@ -22,8 +22,10 @@ import org.eclipse.leshan.core.attributes.Attribute;
import org.eclipse.leshan.core.attributes.AttributeSet;
import org.eclipse.leshan.core.model.ObjectModel;
import org.eclipse.leshan.core.model.ResourceModel;
import org.eclipse.leshan.core.node.LwM2mMultipleResource;
import org.eclipse.leshan.core.node.LwM2mPath;
import org.eclipse.leshan.core.node.LwM2mResource;
import org.eclipse.leshan.core.node.LwM2mSingleResource;
import org.eclipse.leshan.core.node.codec.CodecException;
import org.eclipse.leshan.core.request.SimpleDownlinkRequest;
import org.eclipse.leshan.core.request.WriteAttributesRequest;
@ -48,6 +50,7 @@ import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import static org.eclipse.leshan.core.attributes.Attribute.DIMENSION;
@ -371,4 +374,80 @@ public class LwM2mTransportUtil {
return lwm2mResourceValue;
}
public static Optional<String> contentToString(Object content) {
try {
String value = null;
LwM2mResource resource = null;
String key = null;
if (content instanceof Map) {
Map<Object, Object> contentAsMap = (Map<Object, Object>) content;
if (contentAsMap.size() == 1) {
for (Map.Entry<Object, Object> kv : contentAsMap.entrySet()) {
if (kv.getValue() instanceof LwM2mResource) {
key = kv.getKey().toString();
resource = (LwM2mResource) kv.getValue();
}
}
}
} else if (content instanceof LwM2mResource) {
resource = (LwM2mResource) content;
}
if (resource != null && resource.getType() == OPAQUE) {
value = opaqueResourceToString(resource, key);
}
value = value == null ? content.toString() : value;
return Optional.of(value);
} catch (Exception e) {
log.debug("Failed to convert content " + content + " to string", e);
return Optional.ofNullable(content != null ? content.toString() : null);
}
}
private static String opaqueResourceToString(LwM2mResource resource, String key) {
String value = null;
StringBuilder builder = new StringBuilder();
if (resource instanceof LwM2mSingleResource) {
builder.append("LwM2mSingleResource");
if (key == null) {
builder.append(" id=").append(String.valueOf(resource.getId()));
} else {
builder.append(" key=").append(key);
}
builder.append(" value=").append(opaqueToString((byte[]) resource.getValue()));
builder.append(" type=").append(OPAQUE.toString());
value = builder.toString();
} else if (resource instanceof LwM2mMultipleResource) {
builder.append("LwM2mMultipleResource");
if (key == null) {
builder.append(" id=").append(String.valueOf(resource.getId()));
} else {
builder.append(" key=").append(key);
}
builder.append(" values={");
if (resource.getInstances().size() > 0) {
builder.append(multiInstanceOpaqueToString((LwM2mMultipleResource) resource));
}
builder.append("}");
builder.append(" type=").append(OPAQUE.toString());
value = builder.toString();
}
return value;
}
private static String multiInstanceOpaqueToString(LwM2mMultipleResource resource) {
StringBuilder builder = new StringBuilder();
resource.getInstances().values()
.forEach(v -> builder.append(" id=").append(v.getId()).append(" value=").append(Hex.encodeHexString((byte[]) v.getValue())).append(", "));
int startInd = builder.lastIndexOf(", ");
if (startInd > 0) {
builder.delete(startInd, startInd + 2);
}
return builder.toString();
}
private static String opaqueToString(byte[] value) {
String opaque = Hex.encodeHexString(value);
return opaque.length() > 1024 ? opaque.substring(0, 1024) : opaque;
}
}

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

@ -21,13 +21,13 @@ import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.leshan.core.model.ObjectModel;
import org.eclipse.leshan.core.model.ResourceModel;
import org.eclipse.leshan.core.node.LwM2mObject;
import org.eclipse.leshan.core.node.LwM2mObjectInstance;
import org.eclipse.leshan.core.node.LwM2mMultipleResource;
import org.eclipse.leshan.core.node.LwM2mPath;
import org.eclipse.leshan.core.node.LwM2mResource;
import org.eclipse.leshan.core.node.LwM2mSingleResource;
import org.eclipse.leshan.core.node.codec.LwM2mValueConverter;
import org.eclipse.leshan.core.request.ContentFormat;
import org.eclipse.leshan.core.util.Hex;
import org.eclipse.leshan.server.model.LwM2mModelProvider;
import org.eclipse.leshan.server.registration.Registration;
import org.thingsboard.server.common.data.Device;
@ -44,6 +44,7 @@ import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.Serializable;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
@ -53,6 +54,7 @@ import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.Collectors;
import static org.eclipse.leshan.core.model.ResourceModel.Type.OPAQUE;
import static org.thingsboard.server.common.data.lwm2m.LwM2mConstants.LWM2M_SEPARATOR_PATH;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LWM2M_OBJECT_VERSION_DEFAULT;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertObjectIdToVersionedId;
@ -241,37 +243,7 @@ public class LwM2mClient implements Serializable {
.getObjectModel(pathIds.getObjectId()) : null;
}
public String objectToString(LwM2mObject lwM2mObject) {
StringBuilder builder = new StringBuilder();
builder.append("LwM2mObject [id=").append(lwM2mObject.getId()).append(", instances={");
lwM2mObject.getInstances().forEach((instId, inst) -> {
builder.append(instId).append("=").append(this.instanceToString(inst)).append(", ");
});
int startInd = builder.lastIndexOf(", ");
if (startInd > 0) {
builder.delete(startInd, startInd + 2);
}
builder.append("}]");
return builder.toString();
}
public String instanceToString(LwM2mObjectInstance objectInstance) {
StringBuilder builder = new StringBuilder();
builder.append("LwM2mObjectInstance [id=").append(objectInstance.getId()).append(", resources={");
objectInstance.getResources().forEach((resId, res) -> {
builder.append(resId).append("=").append(this.resourceToString(res)).append(", ");
});
int startInd = builder.lastIndexOf(", ");
if (startInd > 0) {
builder.delete(startInd, startInd + 2);
}
builder.append("}]");
return builder.toString();
}
public String resourceToString(LwM2mResource lwM2mResource) {
return lwM2mResource.isMultiInstances() ? lwM2mResource.getInstances().toString() : lwM2mResource.getValue().toString();
}
public Collection<LwM2mResource> getNewResourceForInstance(String pathRezIdVer, Object params, LwM2mModelProvider modelProvider,
LwM2mValueConverter converter) {

2
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContext.java

@ -60,4 +60,6 @@ public interface LwM2mClientContext {
void removeCredentials(TransportProtos.SessionInfoProto sessionInfo);
void sendMsgsAfterSleeping(LwM2mClient lwM2MClient);
boolean isComposite(LwM2mClient client);
}

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

@ -35,6 +35,7 @@ import org.thingsboard.server.gen.transport.TransportProtos;
import org.thingsboard.server.queue.util.AfterStartUp;
import org.thingsboard.server.queue.util.TbLwM2mTransportComponent;
import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig;
import org.thingsboard.server.transport.lwm2m.config.LwM2mVersion;
import org.thingsboard.server.transport.lwm2m.secure.TbLwM2MSecurityInfo;
import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportContext;
import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil;
@ -339,6 +340,12 @@ public class LwM2mClientContextImpl implements LwM2mClientContext {
return lwM2mClientsByRegistrationId.values().stream().filter(e -> deviceId.equals(e.getDeviceId())).findFirst().orElse(null);
}
@Override
public boolean isComposite(LwM2mClient client) {
return LwM2mVersion.fromVersionStr(client.getRegistration().getLwM2mVersion()).isComposite() &
getProfile(client.getProfileId()).getClientLwM2mSettings().isCompositeOperationsSupport();
}
private boolean validateResourceInModel(LwM2mClient lwM2mClient, String pathIdVer, boolean isWritableNotOptional) {
ResourceModel resourceModel = lwM2mClient.getResourceModel(pathIdVer, this.config
.getModelProvider());

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

@ -21,6 +21,7 @@ import org.eclipse.leshan.core.node.LwM2mResource;
import org.eclipse.leshan.core.node.LwM2mResourceInstance;
import java.io.Serializable;
import java.util.stream.Collectors;
@Data
public class ResourceValue implements Serializable {
@ -45,9 +46,14 @@ public class ResourceValue implements Serializable {
private static TbLwM2MResource toTbLwM2MResource(LwM2mResource lwM2mResource) {
if (lwM2mResource.isMultiInstances()) {
TbLwM2MResourceInstance[] instances = (TbLwM2MResourceInstance[]) lwM2mResource.getInstances().values().stream().map(ResourceValue::toTbLwM2MResourceInstance).toArray();
return new TbLwM2MMultipleResource(lwM2mResource.getId(), lwM2mResource.getType(), instances);
} else {
if ( lwM2mResource.getInstances().values().size() > 0) {
TbLwM2MResourceInstance [] instances = lwM2mResource.getInstances().values().stream().map(ResourceValue::toTbLwM2MResourceInstance).collect(Collectors.toSet()).toArray(new TbLwM2MResourceInstance[0]);
return new TbLwM2MMultipleResource(lwM2mResource.getId(), lwM2mResource.getType(), instances);
}
else {
return new TbLwM2MMultipleResource(lwM2mResource.getId(), lwM2mResource.getType(), new TbLwM2MResourceInstance[0]);
}
} else {
return new TbLwM2MSingleResource(lwM2mResource.getId(), lwM2mResource.getValue(), lwM2mResource.getType());
}
}

34
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/DefaultLwM2mDownlinkMsgHandler.java

@ -61,9 +61,8 @@ import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportContext;
import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient;
import org.thingsboard.server.transport.lwm2m.server.common.LwM2MExecutorAwareService;
import org.thingsboard.server.transport.lwm2m.server.downlink.composite.TbLwM2MReadCompositeRequest;
import org.thingsboard.server.transport.lwm2m.server.downlink.composite.TbLwM2MWriteResponseCompositeCallback;
import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogService;
import org.thingsboard.server.transport.lwm2m.server.uplink.DefaultLwM2MUplinkMsgHandler;
import org.thingsboard.server.transport.lwm2m.server.rpc.composite.RpcWriteCompositeRequest;
import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl;
import javax.annotation.PostConstruct;
@ -73,7 +72,6 @@ import java.util.Collection;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import java.util.function.Predicate;
@ -136,19 +134,6 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im
sendCompositeRequest(client, downlink, this.config.getTimeout(), callback);
}
@Override
public void sendWriteCompositeRequest(LwM2mClient client, Map<String, Object> nodes, DefaultLwM2MUplinkMsgHandler handler) {
// ResourceModel resourceModelWrite = client.getResourceModel(request.getVersionedId(), this.config.getModelProvider());
TbLwM2MWriteResponseCompositeCallback callback = new TbLwM2MWriteResponseCompositeCallback(handler, logService, client, null);
ContentFormat contentFormat = ContentFormat.SENML_JSON;
try {
WriteCompositeRequest downlink = new WriteCompositeRequest(contentFormat, nodes);
sendWriteCompositeRequest(client, downlink, this.config.getTimeout(), callback);
} catch (Exception e) {
callback.onError(JacksonUtil.toString(nodes), e);
}
}
@Override
public void sendObserveRequest(LwM2mClient client, TbLwM2MObserveRequest request, DownlinkRequestCallback<ObserveRequest, ObserveResponse> callback) {
validateVersionedId(client, request);
@ -258,6 +243,17 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im
}
}
@Override
public void sendWriteCompositeRequest(LwM2mClient client, RpcWriteCompositeRequest rpcWriteCompositeRequest, DownlinkRequestCallback<WriteCompositeRequest, WriteCompositeResponse> callback) {
ContentFormat contentFormat = ContentFormat.SENML_JSON;
try {
WriteCompositeRequest downlink = new WriteCompositeRequest(contentFormat, rpcWriteCompositeRequest.getNodes());
sendWriteCompositeRequest(client, downlink, this.config.getTimeout(), callback);
} catch (Exception e) {
callback.onError(JacksonUtil.toString(rpcWriteCompositeRequest), e);
}
}
@Override
public void sendWriteUpdateRequest(LwM2mClient client, TbLwM2MWriteUpdateRequest request, DownlinkRequestCallback<WriteRequest, WriteResponse> callback) {
LwM2mPath resultIds = new LwM2mPath(request.getObjectId());
@ -330,7 +326,11 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im
context.getServer().send(registration, request, timeoutInMs, response -> {
executor.submit(() -> {
try {
callback.onSuccess(request, response);
if (response.isSuccess()) {
callback.onSuccess(request, response);
} else {
callback.onValidationError(request.getNodes().values().toString(), response.getErrorMessage());
}
} catch (Exception e) {
log.error("[{}] failed to process successful response [{}] ", registration.getEndpoint(), response, e);
}

7
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/LwM2mDownlinkMsgHandler.java

@ -23,6 +23,7 @@ import org.eclipse.leshan.core.request.ObserveRequest;
import org.eclipse.leshan.core.request.ReadCompositeRequest;
import org.eclipse.leshan.core.request.ReadRequest;
import org.eclipse.leshan.core.request.WriteAttributesRequest;
import org.eclipse.leshan.core.request.WriteCompositeRequest;
import org.eclipse.leshan.core.request.WriteRequest;
import org.eclipse.leshan.core.response.DeleteResponse;
import org.eclipse.leshan.core.response.DiscoverResponse;
@ -31,13 +32,13 @@ import org.eclipse.leshan.core.response.ObserveResponse;
import org.eclipse.leshan.core.response.ReadCompositeResponse;
import org.eclipse.leshan.core.response.ReadResponse;
import org.eclipse.leshan.core.response.WriteAttributesResponse;
import org.eclipse.leshan.core.response.WriteCompositeResponse;
import org.eclipse.leshan.core.response.WriteResponse;
import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient;
import org.thingsboard.server.transport.lwm2m.server.downlink.composite.TbLwM2MReadCompositeRequest;
import org.thingsboard.server.transport.lwm2m.server.uplink.DefaultLwM2MUplinkMsgHandler;
import org.thingsboard.server.transport.lwm2m.server.rpc.composite.RpcWriteCompositeRequest;
import java.util.List;
import java.util.Map;
import java.util.Set;
public interface LwM2mDownlinkMsgHandler {
@ -66,7 +67,7 @@ public interface LwM2mDownlinkMsgHandler {
void sendWriteReplaceRequest(LwM2mClient client, TbLwM2MWriteReplaceRequest request, DownlinkRequestCallback<WriteRequest, WriteResponse> callback);
void sendWriteCompositeRequest(LwM2mClient client, Map<String, Object> nodes, DefaultLwM2MUplinkMsgHandler handler);
void sendWriteCompositeRequest(LwM2mClient client, RpcWriteCompositeRequest nodes, DownlinkRequestCallback<WriteCompositeRequest, WriteCompositeResponse> callback);
void sendWriteUpdateRequest(LwM2mClient client, TbLwM2MWriteUpdateRequest request, DownlinkRequestCallback<WriteRequest, WriteResponse> callback);

43
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/DefaultLwM2MRpcRequestHandler.java

@ -52,6 +52,7 @@ import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MWriteRespon
import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MWriteUpdateRequest;
import org.thingsboard.server.transport.lwm2m.server.downlink.composite.TbLwM2MReadCompositeCallback;
import org.thingsboard.server.transport.lwm2m.server.downlink.composite.TbLwM2MReadCompositeRequest;
import org.thingsboard.server.transport.lwm2m.server.downlink.composite.TbLwM2MWriteResponseCompositeCallback;
import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogService;
import org.thingsboard.server.transport.lwm2m.server.rpc.composite.RpcReadCompositeRequest;
import org.thingsboard.server.transport.lwm2m.server.rpc.composite.RpcReadResponseCompositeCallback;
@ -131,15 +132,20 @@ public class DefaultLwM2MRpcRequestHandler implements LwM2MRpcRequestHandler {
throw new IllegalArgumentException("Unsupported operation: " + operationType.name());
}
} else if (operationType.isComposite()) {
switch (operationType) {
case READ_COMPOSITE:
sendReadCompositeRequest(client, rpcRequst);
break;
case WRITE_COMPOSITE:
sendWriteCompositeRequest(client, rpcRequst);
break;
default:
throw new IllegalArgumentException("Unsupported operation: " + operationType.name());
if (clientContext.isComposite(client)) {
switch (operationType) {
case READ_COMPOSITE:
sendReadCompositeRequest(client, rpcRequst);
break;
case WRITE_COMPOSITE:
sendWriteCompositeRequest(client, rpcRequst);
break;
default:
throw new IllegalArgumentException("Unsupported operation: " + operationType.name());
}
} else {
this.sendErrorRpcResponse(sessionInfo, rpcRequst.getRequestId(),
ResponseCode.INTERNAL_SERVER_ERROR.getName(), "This device does not support Composite Operation");
}
} else {
switch (operationType) {
@ -239,14 +245,19 @@ public class DefaultLwM2MRpcRequestHandler implements LwM2MRpcRequestHandler {
downlinkHandler.sendWriteReplaceRequest(client, request, rpcCallback);
}
/**
* WriteComposite {"nodes":{"/3/0/14":"+04", "/1/0/2":100, "/5/0/1":"coap://localhost:5685"}}
* {"result":"CHANGED"}
* Map<String, Object> nodes = new HashMap<>();
* nodes.put("/3/0/14", "+02");
* nodes.put("/1/0/2", 100);
* nodes.put("/5/0/1", "coap://localhost:5685");
*/
private void sendWriteCompositeRequest(LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg) {
RpcWriteCompositeRequest nodes = JacksonUtil.fromString(requestMsg.getParams(), RpcWriteCompositeRequest.class);
// TbLwM2MWriteReplaceRequest request = TbLwM2MWriteReplaceRequest.builder().versionedId(versionedId)
// .value(requestBody.getValue())
// .timeout(this.config.getTimeout()).build();
// var mainCallback = new TbLwM2MWriteResponseCallback(uplinkHandler, logService, client, versionedId);
// var rpcCallback = new RpcEmptyResponseCallback<>(transportService, client, requestMsg, mainCallback);
// downlinkHandler.sendWriteReplaceRequest(client, request, rpcCallback);
RpcWriteCompositeRequest rpcWriteCompositeRequest = JacksonUtil.fromString(requestMsg.getParams(), RpcWriteCompositeRequest.class);
var mainCallback = new TbLwM2MWriteResponseCompositeCallback(uplinkHandler, logService, client, null);
var rpcCallback = new RpcEmptyResponseCallback<>(transportService, client, requestMsg, mainCallback);
downlinkHandler.sendWriteCompositeRequest(client, rpcWriteCompositeRequest, rpcCallback);
}
private void sendCancelObserveRequest(LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, String versionedId) {

15
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcReadResponseCallback.java

@ -15,9 +15,6 @@
*/
package org.thingsboard.server.transport.lwm2m.server.rpc;
import org.eclipse.leshan.core.node.LwM2mObject;
import org.eclipse.leshan.core.node.LwM2mObjectInstance;
import org.eclipse.leshan.core.node.LwM2mResource;
import org.eclipse.leshan.core.request.LwM2mRequest;
import org.eclipse.leshan.core.response.ReadResponse;
import org.thingsboard.server.common.transport.TransportService;
@ -27,6 +24,8 @@ import org.thingsboard.server.transport.lwm2m.server.downlink.DownlinkRequestCal
import java.util.Optional;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.contentToString;
public class RpcReadResponseCallback<R extends LwM2mRequest<T>, T extends ReadResponse> extends RpcLwM2MDownlinkCallback<R, T> {
public RpcReadResponseCallback(TransportService transportService, LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, DownlinkRequestCallback<R, T> callback) {
@ -35,14 +34,6 @@ public class RpcReadResponseCallback<R extends LwM2mRequest<T>, T extends ReadRe
@Override
protected Optional<String> serializeSuccessfulResponse(T response) {
Object value = null;
if (response.getContent() instanceof LwM2mObject) {
value = client.objectToString((LwM2mObject) response.getContent());
} else if (response.getContent() instanceof LwM2mObjectInstance) {
value = client.instanceToString((LwM2mObjectInstance) response.getContent());
} else if (response.getContent() instanceof LwM2mResource) {
value = client.resourceToString((LwM2mResource) response.getContent());
}
return Optional.of(String.format("%s", value));
return contentToString(response.getContent());
}
}

5
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/composite/RpcReadResponseCompositeCallback.java

@ -16,7 +16,6 @@
package org.thingsboard.server.transport.lwm2m.server.rpc.composite;
import org.eclipse.leshan.core.request.LwM2mRequest;
import org.eclipse.leshan.core.request.ReadCompositeRequest;
import org.eclipse.leshan.core.response.ReadCompositeResponse;
import org.thingsboard.server.common.transport.TransportService;
import org.thingsboard.server.gen.transport.TransportProtos;
@ -26,6 +25,8 @@ import org.thingsboard.server.transport.lwm2m.server.rpc.RpcLwM2MDownlinkCallbac
import java.util.Optional;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.contentToString;
public class RpcReadResponseCompositeCallback<R extends LwM2mRequest<T>, T extends ReadCompositeResponse> extends RpcLwM2MDownlinkCallback<R, T> {
public RpcReadResponseCompositeCallback(TransportService transportService, LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, DownlinkRequestCallback<R, T> callback) {
@ -34,6 +35,6 @@ public class RpcReadResponseCompositeCallback<R extends LwM2mRequest<T>, T exten
@Override
protected Optional<String> serializeSuccessfulResponse(T response) {
return Optional.of(String.format("%s", response.getContent().toString()));
return contentToString(response.getContent());
}
}

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

@ -89,9 +89,8 @@ export class DeviceProfileTransportConfigurationComponent implements ControlValu
if (configuration) {
delete configuration.type;
}
this.deviceProfileTransportConfigurationFormGroup.patchValue({configuration}, {emitEvent: false});
setTimeout(() => {
this.deviceProfileTransportConfigurationFormGroup.updateValueAndValidity();
this.deviceProfileTransportConfigurationFormGroup.patchValue({configuration}, {emitEvent: false});
}, 0);
}

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

@ -38,10 +38,8 @@ import {
INSTANCES,
KEY_NAME,
Lwm2mProfileConfigModels,
ModelValue,
ObjectLwM2M,
OBSERVE,
OBSERVE_ATTR_TELEMETRY,
PowerMode,
PowerModeTranslationMap,
RESOURCES,
@ -49,7 +47,7 @@ import {
TELEMETRY
} from './lwm2m-profile-config.models';
import { DeviceProfileService } from '@core/http/device-profile.service';
import { deepClone, isDefinedAndNotNull, isEmpty, isUndefined } from '@core/utils';
import { deepClone, isDefinedAndNotNull, isEmpty } from '@core/utils';
import { JsonArray, JsonObject } from '@angular/compiler-cli/ngcc/src/packages/entry_point';
import { Direction } from '@shared/models/page/sort-order';
import _ from 'lodash';
@ -226,32 +224,30 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro
}
private initWriteValue = (): void => {
const modelValue = {objectIds: [], objectsList: []} as ModelValue;
modelValue.objectIds = this.getObjectsFromJsonAllConfig();
if (modelValue.objectIds.length > 0) {
const objectIds = this.getObjectsFromJsonAllConfig();
if (objectIds.length > 0) {
const sortOrder = {
property: 'id',
direction: Direction.ASC
};
this.deviceProfileService.getLwm2mObjects(sortOrder, modelValue.objectIds, null).subscribe(
this.deviceProfileService.getLwm2mObjects(sortOrder, objectIds, null).subscribe(
(objectsList) => {
modelValue.objectsList = objectsList;
this.updateWriteValue(modelValue);
this.updateWriteValue(objectsList);
}
);
} else {
this.updateWriteValue(modelValue);
this.updateWriteValue([]);
}
}
private updateWriteValue = (value: ModelValue): void => {
private updateWriteValue = (value: ObjectLwM2M[]): void => {
const fwResource = isDefinedAndNotNull(this.configurationValue.clientLwM2mSettings.fwUpdateResource) ?
this.configurationValue.clientLwM2mSettings.fwUpdateResource : '';
const swResource = isDefinedAndNotNull(this.configurationValue.clientLwM2mSettings.swUpdateResource) ?
this.configurationValue.clientLwM2mSettings.swUpdateResource : '';
this.lwm2mDeviceProfileFormGroup.patchValue({
objectIds: value,
observeAttrTelemetry: this.getObserveAttrTelemetryObjects(value.objectsList),
observeAttrTelemetry: this.getObserveAttrTelemetryObjects(value),
bootstrap: this.configurationValue.bootstrap,
clientLwM2mSettings: {
clientOnlyObserveAfterConnect: this.configurationValue.clientLwM2mSettings.clientOnlyObserveAfterConnect,
@ -334,6 +330,7 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro
const isNotZeroInstanceId = (instance) => !instance.includes('/0/');
return attribute.some(isNotZeroInstanceId) || telemetry.some(isNotZeroInstanceId);
}
private addInstances = (attribute: string[], telemetry: string[], clientObserveAttrTelemetry: ObjectLwM2M[]): void => {
const instancesPath = attribute.concat(telemetry)
.filter(instance => !instance.includes('/0/'))
@ -454,21 +451,13 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro
});
}
});
if (isUndefined(this.configurationValue.observeAttr)) {
this.configurationValue.observeAttr = {
observe: observeArray,
attribute: attributeArray,
telemetry: telemetryArray,
keyName: this.sortObjectKeyPathJson(KEY_NAME, keyNameNew),
attributeLwm2m: attributes
};
} else {
this.configurationValue.observeAttr.observe = observeArray;
this.configurationValue.observeAttr.attribute = attributeArray;
this.configurationValue.observeAttr.telemetry = telemetryArray;
this.configurationValue.observeAttr.keyName = this.sortObjectKeyPathJson(KEY_NAME, keyNameNew);
this.configurationValue.observeAttr.attributeLwm2m = attributes;
}
this.configurationValue.observeAttr = {
observe: observeArray,
attribute: attributeArray,
telemetry: telemetryArray,
keyName: this.sortObjectKeyPathJson(KEY_NAME, keyNameNew),
attributeLwm2m: attributes
};
}
sortObjectKeyPathJson = (key: string, value: object): object => {
@ -527,7 +516,7 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro
}
removeObjectsList = (value: ObjectLwM2M): void => {
const objectsOld = this.lwm2mDeviceProfileFormGroup.get(OBSERVE_ATTR_TELEMETRY).value.clientLwM2M;
const objectsOld = this.lwm2mDeviceProfileFormGroup.get('observeAttrTelemetry').value;
const isIdIndex = (element) => element.keyId === value.keyId;
const index = objectsOld.findIndex(isIdIndex);
if (index >= 0) {

20
ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-list.component.ts

@ -28,7 +28,7 @@ import {
import { coerceBooleanProperty } from '@angular/cdk/coercion';
import { Observable } from 'rxjs';
import { distinctUntilChanged, filter, mergeMap, share, tap } from 'rxjs/operators';
import { ModelValue, ObjectLwM2M, PAGE_SIZE_LIMIT } from './lwm2m-profile-config.models';
import { ObjectLwM2M, PAGE_SIZE_LIMIT } from './lwm2m-profile-config.models';
import { DeviceProfileService } from '@core/http/device-profile.service';
import { Direction } from '@shared/models/page/sort-order';
import { isDefined, isDefinedAndNotNull, isString } from '@core/utils';
@ -54,7 +54,6 @@ export class Lwm2mObjectListComponent implements ControlValueAccessor, OnInit, V
private requiredValue: boolean;
private dirty = false;
private modelValue: Array<string> = [];
lwm2mListFormGroup: FormGroup;
objectsList: Array<ObjectLwM2M> = [];
@ -92,7 +91,7 @@ export class Lwm2mObjectListComponent implements ControlValueAccessor, OnInit, V
this.lwm2mListFormGroup.valueChanges.subscribe((value) => {
let formValue = null;
if (this.lwm2mListFormGroup.valid) {
formValue = value;
formValue = value.objectsList;
}
this.propagateChange(formValue);
});
@ -139,15 +138,13 @@ export class Lwm2mObjectListComponent implements ControlValueAccessor, OnInit, V
}
}
writeValue(value: ModelValue): void {
writeValue(value: ObjectLwM2M[]): void {
this.searchText = '';
if (isDefinedAndNotNull(value)) {
if (Array.isArray(value.objectIds)) {
this.modelValue = value.objectIds;
this.objectsList = value.objectsList;
if (Array.isArray(value)) {
this.objectsList = value;
} else {
this.objectsList = [];
this.modelValue = [];
}
this.lwm2mListFormGroup.patchValue({objectsList: this.objectsList}, {emitEvent: false});
this.dirty = false;
@ -161,8 +158,7 @@ export class Lwm2mObjectListComponent implements ControlValueAccessor, OnInit, V
}
private add(object: ObjectLwM2M): void {
if (isDefinedAndNotNull(this.modelValue) && this.modelValue.indexOf(object.keyId) === -1) {
this.modelValue.push(object.keyId);
if (isDefinedAndNotNull(this.objectsList) && this.objectsList.findIndex(item => item.keyId === object.keyId) === -1) {
this.objectsList.push(object);
this.lwm2mListFormGroup.get('objectsList').setValue(this.objectsList);
this.addList.next(this.objectsList);
@ -171,12 +167,10 @@ export class Lwm2mObjectListComponent implements ControlValueAccessor, OnInit, V
}
remove = (object: ObjectLwM2M): void => {
let index = this.objectsList.indexOf(object);
const index = this.objectsList.indexOf(object);
if (index >= 0) {
this.objectsList.splice(index, 1);
this.lwm2mListFormGroup.get('objectsList').setValue(this.objectsList);
index = this.modelValue.indexOf(object.keyId);
this.modelValue.splice(index, 1);
this.removeList.next(object);
this.clear();
}

5
ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-observe-attr-telemetry-instances.component.html

@ -32,6 +32,7 @@
<mat-checkbox color="warn"
[disabled]="this.disabled"
[checked]="getChecked(instances, 'attribute')"
(click)="$event.stopPropagation()"
(change)="changeInstanceResourcesCheckBox($event.checked, instances, 'attribute')"
[indeterminate]="getIndeterminate(instances, 'attribute')">
</mat-checkbox>
@ -40,14 +41,16 @@
<mat-checkbox color="primary"
[disabled]="this.disabled"
[checked]="getChecked(instances, 'telemetry')"
(click)="$event.stopPropagation()"
(change)="changeInstanceResourcesCheckBox($event.checked, instances, 'telemetry')"
[indeterminate]="getIndeterminate(instances, 'telemetry')">
</mat-checkbox>
</div>
<div fxLayoutAlign="center center" fxFlex="10">
<mat-checkbox color="primary"
[disabled]="this.disabled || !(getIndeterminate(instances, 'telemetry') || getIndeterminate(instances, 'attribute'))"
[disabled]="disableObserve(instances)"
[checked]="getChecked(instances, 'observe')"
(click)="$event.stopPropagation()"
(change)="changeInstanceResourcesCheckBox($event.checked, instances, 'observe')"
[indeterminate]="getIndeterminate(instances, 'observe')">
</mat-checkbox>

16
ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-observe-attr-telemetry-instances.component.ts

@ -161,6 +161,13 @@ export class Lwm2mObserveAttrTelemetryInstancesComponent implements ControlValue
const resources = deepClone(instance.get('resources').value as ResourceLwM2M[]);
if (value && type === 'observe') {
resources.forEach(resource => resource[type] = resource.telemetry || resource.attribute);
} else if (!value && type !== 'observe') {
resources.forEach(resource => {
resource[type] = value;
if (resource.observe && !(resource.telemetry || resource.attribute)) {
resource.observe = false;
}
});
} else {
resources.forEach(resource => resource[type] = value);
}
@ -190,6 +197,15 @@ export class Lwm2mObserveAttrTelemetryInstancesComponent implements ControlValue
return isDefinedAndNotNull(resources) && resources.every(resource => resource[type]);
}
disableObserve(instance: AbstractControl): boolean {
return this.disabled || !(
this.getIndeterminate(instance, 'telemetry') ||
this.getIndeterminate(instance, 'attribute') ||
this.getChecked(instance, 'telemetry') ||
this.getChecked(instance, 'attribute')
);
}
get isExpend(): boolean {
return this.instancesFormArray.length === 1;
}

18
ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-observe-attr-telemetry-resources.component.ts

@ -129,7 +129,7 @@ export class Lwm2mObserveAttrTelemetryResourcesComponent implements ControlValue
private updatedResources(resources: ResourceLwM2M[]): void {
if (resources.length === this.resourcesFormArray.length) {
this.resourcesFormArray.patchValue(resources, {emitEvent: false});
this.resourcesFormArray.patchValue(resources, {onlySelf: true});
} else {
if (this.valueChange$) {
this.valueChange$.unsubscribe();
@ -144,7 +144,7 @@ export class Lwm2mObserveAttrTelemetryResourcesComponent implements ControlValue
if (this.disabled) {
this.resourcesFormGroup.disable({emitEvent: false});
}
this.valueChange$ = this.resourcesFormGroup.valueChanges.subscribe(value => {
this.valueChange$ = this.resourcesFormGroup.valueChanges.subscribe(() => {
this.updateModel(this.resourcesFormGroup.getRawValue().resources);
});
}
@ -164,12 +164,14 @@ export class Lwm2mObserveAttrTelemetryResourcesComponent implements ControlValue
form.get('attribute').valueChanges.pipe(startWith(resource.attribute), takeUntil(this.destroy$)),
form.get('telemetry').valueChanges.pipe(startWith(resource.telemetry), takeUntil(this.destroy$))
]).subscribe(([attribute, telemetry]) => {
if (attribute || telemetry) {
form.get('observe').enable({emitEvent: false});
} else {
form.get('observe').disable({emitEvent: false});
form.get('observe').patchValue(false, {emitEvent: false});
form.get('attributes').patchValue({}, {emitEvent: false});
if (!this.disabled) {
if (attribute || telemetry) {
form.get('observe').enable({emitEvent: false});
} else {
form.get('observe').disable({emitEvent: false});
form.get('observe').patchValue(false, {emitEvent: false});
form.get('attributes').patchValue({}, {emitEvent: false});
}
}
});
return form;

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

@ -20,7 +20,6 @@ export const PAGE_SIZE_LIMIT = 50;
export const INSTANCES = 'instances';
export const INSTANCE = 'instance';
export const RESOURCES = 'resources';
export const OBSERVE_ATTR_TELEMETRY = 'observeAttrTelemetry';
export const OBSERVE = 'observe';
export const ATTRIBUTE = 'attribute';
export const TELEMETRY = 'telemetry';
@ -127,11 +126,6 @@ export const PowerModeTranslationMap = new Map<PowerMode, string>(
]
);
export interface ModelValue {
objectIds: string[];
objectsList: ObjectLwM2M[];
}
export interface BootstrapServersSecurityConfig {
shortId: number;
lifetime: number;

Loading…
Cancel
Save