Browse Source

lwm2m: back: Write Attributes - start (#4402)

* lwm2m: back: Write Attributes - start

* lwm2m: front: fis bug disable instances

* lwm2m: transport: attr/discavery start

* lwm2m: transport: attributeLwm2m after update profile

* lwm2m: transport: attributeLwm2m after update profile (no delete attribute)

* Lwm2m: back: test

* Lwm2m: back: test2

* Lwm2m: back: test3
pull/4416/head
nickAS21 5 years ago
committed by GitHub
parent
commit
d6979e54da
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 5
      application/src/main/java/org/thingsboard/server/service/install/DefaultSystemDataLoaderService.java
  2. 2
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapServers.java
  3. 11
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mSessionMsgListener.java
  4. 123
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportHandler.java
  5. 47
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportRequest.java
  6. 4
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportService.java
  7. 236
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportServiceImpl.java
  8. 3
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContext.java
  9. 23
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContextImpl.java
  10. 8
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientProfile.java
  11. 7
      ui-ngx/src/app/core/http/resource.service.ts
  12. 18
      ui-ngx/src/app/core/services/time.service.ts
  13. 2
      ui-ngx/src/app/core/utils.ts
  14. 25
      ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-profile-transport-configuration.component.ts
  15. 3
      ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-observe-attr-telemetry.component.html
  16. 8
      ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-observe-attr-telemetry.component.scss
  17. 6
      ui-ngx/src/app/modules/home/components/widget/lib/json-input-widget.component.ts
  18. 3
      ui-ngx/src/app/modules/home/components/widget/widget-components.module.ts
  19. 2
      ui-ngx/src/app/modules/home/pages/asset/assets-table-config.resolver.ts
  20. 7
      ui-ngx/src/app/modules/home/pages/dashboard/dashboards-table-config.resolver.ts
  21. 54
      ui-ngx/src/app/modules/home/pages/device/devices-table-config.resolver.ts
  22. 12
      ui-ngx/src/app/modules/home/pages/edge/edge-routing.module.ts
  23. 5
      ui-ngx/src/app/modules/home/pages/entity-view/entity-views-table-config.resolver.ts
  24. 6
      ui-ngx/src/app/modules/home/pages/resource/resources-library.component.ts
  25. 72
      ui-ngx/src/app/modules/home/pages/rulechain/rulechains-table-config.resolver.ts
  26. 4
      ui-ngx/src/app/shared/components/file-input.component.ts
  27. 2
      ui-ngx/src/app/shared/components/json-object-edit.component.ts
  28. 2
      ui-ngx/src/app/shared/models/resource.models.ts

5
application/src/main/java/org/thingsboard/server/service/install/DefaultSystemDataLoaderService.java

@ -17,10 +17,8 @@ package org.thingsboard.server.service.install;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Profile;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
@ -60,11 +58,8 @@ import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.common.data.query.BooleanFilterPredicate;
import org.thingsboard.server.common.data.query.DynamicValue;
import org.thingsboard.server.common.data.query.DynamicValueSourceType;
import org.thingsboard.server.common.data.query.EntityKey;
import org.thingsboard.server.common.data.query.EntityKeyType;
import org.thingsboard.server.common.data.query.EntityKeyValueType;
import org.thingsboard.server.common.data.query.FilterPredicateValue;
import org.thingsboard.server.common.data.query.KeyFilter;
import org.thingsboard.server.common.data.query.NumericFilterPredicate;
import org.thingsboard.server.common.data.rule.RuleChainType;
import org.thingsboard.server.common.data.security.Authority;

2
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapServers.java

@ -23,5 +23,5 @@ public class LwM2MBootstrapServers {
private Integer lifetime = 300;
private Integer defaultMinPeriod = 1;
private boolean notifIfDisabled = true;
private String binding = "U";
private String binding = "UQ";
}

11
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mSessionMsgListener.java

@ -18,6 +18,7 @@ package org.thingsboard.server.transport.lwm2m.server;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.GenericFutureListener;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.DeviceProfile;
import org.thingsboard.server.common.data.ResourceType;
@ -74,12 +75,12 @@ public class LwM2mSessionMsgListener implements GenericFutureListener<Future<? s
@Override
public void onToDeviceRpcRequest(ToDeviceRpcRequestMsg toDeviceRequest) {
log.info("[{}] toDeviceRpcRequest", toDeviceRequest);
this.service.onToDeviceRpcRequest(toDeviceRequest);
}
@Override
public void onToServerRpcResponse(ToServerRpcResponseMsg toServerResponse) {
log.info("[{}] toServerRpcResponse", toServerResponse);
this.service.onToServerRpcResponse(toServerResponse);
}
@Override
@ -87,13 +88,15 @@ public class LwM2mSessionMsgListener implements GenericFutureListener<Future<? s
log.info("[{}] operationComplete", future);
}
public void onResourceUpdate(Optional<TransportProtos.ResourceUpdateMsg> resourceUpdateMsgOpt) {
@Override
public void onResourceUpdate(@NotNull Optional<TransportProtos.ResourceUpdateMsg> resourceUpdateMsgOpt) {
if (ResourceType.LWM2M_MODEL.name().equals(resourceUpdateMsgOpt.get().getResourceType())) {
this.service.onResourceUpdate(resourceUpdateMsgOpt);
}
}
public void onResourceDelete(Optional<TransportProtos.ResourceDeleteMsg> resourceDeleteMsgOpt) {
@Override
public void onResourceDelete(@NotNull Optional<TransportProtos.ResourceDeleteMsg> resourceDeleteMsgOpt) {
if (ResourceType.LWM2M_MODEL.name().equals(resourceDeleteMsgOpt.get().getResourceType())) {
this.service.onResourceDelete(resourceDeleteMsgOpt);
}

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

@ -22,15 +22,14 @@ import com.google.gson.JsonSyntaxException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.californium.core.network.config.NetworkConfig;
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.LwM2mNode;
import org.eclipse.leshan.core.node.LwM2mObject;
import org.eclipse.leshan.core.node.LwM2mObjectInstance;
import org.eclipse.leshan.core.node.LwM2mPath;
import org.eclipse.leshan.core.node.LwM2mSingleResource;
import org.eclipse.leshan.core.node.codec.CodecException;
import org.eclipse.leshan.core.request.DownlinkRequest;
import org.eclipse.leshan.core.request.WriteAttributesRequest;
import org.eclipse.leshan.core.util.Hex;
import org.eclipse.leshan.server.californium.LeshanServerBuilder;
import org.eclipse.leshan.server.registration.Registration;
@ -44,11 +43,19 @@ import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientProfile;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.LinkedList;
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;
import static org.eclipse.leshan.core.attributes.Attribute.MAXIMUM_PERIOD;
import static org.eclipse.leshan.core.attributes.Attribute.MINIMUM_PERIOD;
import static org.eclipse.leshan.core.attributes.Attribute.OBJECT_VERSION;
import static org.thingsboard.server.common.data.lwm2m.LwM2mConstants.LWM2M_SEPARATOR_KEY;
import static org.thingsboard.server.common.data.lwm2m.LwM2mConstants.LWM2M_SEPARATOR_PATH;
@ -56,8 +63,19 @@ import static org.thingsboard.server.common.data.lwm2m.LwM2mConstants.LWM2M_SEPA
public class LwM2mTransportHandler {
public static final String BASE_DEVICE_API_TOPIC = "v1/devices/me";
public static final String CLIENT_LWM2M_SETTINGS = "clientLwM2mSettings";
public static final String BOOTSTRAP = "bootstrap";
public static final String SERVERS = "servers";
public static final String LWM2M_SERVER = "lwm2mServer";
public static final String BOOTSTRAP_SERVER = "bootstrapServer";
public static final String OBSERVE_ATTRIBUTE_TELEMETRY = "observeAttr";
public static final String ATTRIBUTE = "attribute";
public static final String TELEMETRY = "telemetry";
public static final String KEY_NAME = "keyName";
public static final String OBSERVE = "observe";
public static final String ATTRIBUTE_LWM2M = "attributeLwm2m";
private static final String REQUEST = "/request";
private static final String RESPONSE = "/response";
private static final String ATTRIBUTES = "/" + ATTRIBUTE;
@ -70,14 +88,6 @@ public class LwM2mTransportHandler {
public static final String DEVICE_TELEMETRY_TOPIC = BASE_DEVICE_API_TOPIC + TELEMETRIES;
public static final long DEFAULT_TIMEOUT = 2 * 60 * 1000L; // 2min in ms
public static final String OBSERVE_ATTRIBUTE_TELEMETRY = "observeAttr";
public static final String CLIENT_LWM2M_SETTINGS = "clientLwM2mSettings";
public static final String KEY_NAME = "keyName";
public static final String OBSERVE = "observe";
public static final String BOOTSTRAP = "bootstrap";
public static final String SERVERS = "servers";
public static final String LWM2M_SERVER = "lwm2mServer";
public static final String BOOTSTRAP_SERVER = "bootstrapServer";
public static final String LOG_LW2M_TELEMETRY = "logLwm2m";
public static final String LOG_LW2M_INFO = "info";
@ -144,19 +154,19 @@ public class LwM2mTransportHandler {
throw new CodecException("Invalid value type for resource %s, type %s", resourcePath, type);
}
}
public static LwM2mNode getLvM2mNodeToObject(LwM2mNode content) {
if (content instanceof LwM2mObject) {
return (LwM2mObject) content;
} else if (content instanceof LwM2mObjectInstance) {
return (LwM2mObjectInstance) content;
} else if (content instanceof LwM2mSingleResource) {
return (LwM2mSingleResource) content;
} else if (content instanceof LwM2mMultipleResource) {
return (LwM2mMultipleResource) content;
}
return null;
}
//
// public static LwM2mNode getLvM2mNodeToObject(LwM2mNode content) {
// if (content instanceof LwM2mObject) {
// return (LwM2mObject) content;
// } else if (content instanceof LwM2mObjectInstance) {
// return (LwM2mObjectInstance) content;
// } else if (content instanceof LwM2mSingleResource) {
// return (LwM2mSingleResource) content;
// } else if (content instanceof LwM2mMultipleResource) {
// return (LwM2mMultipleResource) content;
// }
// return null;
// }
public static LwM2mClientProfile getNewProfileParameters(JsonObject profilesConfigData, TenantId tenantId) {
LwM2mClientProfile lwM2MClientProfile = new LwM2mClientProfile();
@ -166,6 +176,7 @@ public class LwM2mTransportHandler {
lwM2MClientProfile.setPostAttributeProfile(profilesConfigData.get(OBSERVE_ATTRIBUTE_TELEMETRY).getAsJsonObject().get(ATTRIBUTE).getAsJsonArray());
lwM2MClientProfile.setPostTelemetryProfile(profilesConfigData.get(OBSERVE_ATTRIBUTE_TELEMETRY).getAsJsonObject().get(TELEMETRY).getAsJsonArray());
lwM2MClientProfile.setPostObserveProfile(profilesConfigData.get(OBSERVE_ATTRIBUTE_TELEMETRY).getAsJsonObject().get(OBSERVE).getAsJsonArray());
lwM2MClientProfile.setPostAttributeLwm2mProfile(profilesConfigData.get(OBSERVE_ATTRIBUTE_TELEMETRY).getAsJsonObject().get(ATTRIBUTE_LWM2M).getAsJsonObject());
return lwM2MClientProfile;
}
@ -184,6 +195,9 @@ public class LwM2mTransportHandler {
* "attribute":["/2/0/1","/3/0/9"],
* "telemetry":["/1/0/1","/2/0/1","/6/0/1"],
* "observe":["/2/0","/2/0/0","/4/0/2"]}
* "attributeLwm2m": {"/3_1.0": {"ver": "currentTimeTest11"},
* "/3_1.0/0": {"gt": 17},
* "/3_1.0/0/9": {"pmax": 45}, "/3_1.2": {ver": "3_1.2"}}
*/
public static LwM2mClientProfile getLwM2MClientProfileFromThingsboard(DeviceProfile deviceProfile) {
if (deviceProfile != null && ((Lwm2mDeviceProfileTransportConfiguration) deviceProfile.getProfileData().getTransportConfiguration()).getProperties().size() > 0) {
@ -192,7 +206,7 @@ public class LwM2mTransportHandler {
ObjectMapper mapper = new ObjectMapper();
String profileStr = mapper.writeValueAsString(profile);
JsonObject profileJson = (profileStr != null) ? validateJson(profileStr) : null;
return (getValidateCredentialsBodyFromThingsboard(profileJson)) ? LwM2mTransportHandler.getNewProfileParameters(profileJson, deviceProfile.getTenantId()) : null;
return getValidateCredentialsBodyFromThingsboard(profileJson) ? LwM2mTransportHandler.getNewProfileParameters(profileJson, deviceProfile.getTenantId()) : null;
} catch (IOException e) {
log.error("", e);
}
@ -240,7 +254,10 @@ public class LwM2mTransportHandler {
objectMsg.get(OBSERVE_ATTRIBUTE_TELEMETRY).getAsJsonObject().get(TELEMETRY).isJsonArray() &&
objectMsg.get(OBSERVE_ATTRIBUTE_TELEMETRY).getAsJsonObject().has(OBSERVE) &&
!objectMsg.get(OBSERVE_ATTRIBUTE_TELEMETRY).getAsJsonObject().get(OBSERVE).isJsonNull() &&
objectMsg.get(OBSERVE_ATTRIBUTE_TELEMETRY).getAsJsonObject().get(OBSERVE).isJsonArray());
objectMsg.get(OBSERVE_ATTRIBUTE_TELEMETRY).getAsJsonObject().get(OBSERVE).isJsonArray() &&
objectMsg.get(OBSERVE_ATTRIBUTE_TELEMETRY).getAsJsonObject().has(ATTRIBUTE_LWM2M) &&
!objectMsg.get(OBSERVE_ATTRIBUTE_TELEMETRY).getAsJsonObject().get(ATTRIBUTE_LWM2M).isJsonNull() &&
objectMsg.get(OBSERVE_ATTRIBUTE_TELEMETRY).getAsJsonObject().get(ATTRIBUTE_LWM2M).isJsonObject());
}
private static boolean getValidateBootstrapProfileFromThingsboard(JsonObject objectMsg) {
@ -360,4 +377,54 @@ public class LwM2mTransportHandler {
return ObjectModel.DEFAULT_VERSION;
}
}
/**
* As example:
* a)Write-Attributes/3/0/9?pmin=1 means the Battery Level value will be notified
* to the Server with a minimum interval of 1sec;
* this value is set at theResource level.
* b)Write-Attributes/3/0/9?pmin means the Battery Level will be notified
* to the Server with a minimum value (pmin) given by the default one
* (resource 2 of Object Server ID=1),
* or with another value if this Attribute has been set at another level
* (Object or Object Instance: see section5.1.1).
* c)Write-Attributes/3/0?pmin=10 means that all Resources of Instance 0 of the Object Device (ID:3)
* will be notified to the Server with a minimum interval of 10 sec;
* this value is set at the Object Instance level.
* d)Write-Attributes /3/0/9?gt=45&st=10 means the Battery Level will be notified to the Server
* when:
* a.old value is 20 and new value is 35 due to step condition
* b.old value is 45 and new value is 50 due to gt condition
* c.old value is 50 and new value is 40 due to both gt and step conditions
* d.old value is 35 and new value is 20 due to step conditione)
* Write-Attributes /3/0/9?lt=20&gt=85&st=10 means the Battery Level will be notified to the Server
* when:
* a.old value is 17 and new value is 24 due to lt condition
* b.old value is 75 and new value is 90 due to both gt and step conditions
* String uriQueries = "pmin=10&pmax=60";
* AttributeSet attributes = AttributeSet.parse(uriQueries);
* WriteAttributesRequest request = new WriteAttributesRequest(target, attributes);
* Attribute gt = new Attribute(GREATER_THAN, Double.valueOf("45"));
* Attribute st = new Attribute(LESSER_THAN, Double.valueOf("10"));
* Attribute pmax = new Attribute(MAXIMUM_PERIOD, "60");
* Attribute [] attrs = {gt, st};
*/
public static DownlinkRequest createWriteAttributeRequest(String target, Object params) {
AttributeSet attrSet = new AttributeSet(createWriteAttributes(params));
return attrSet.getAttributes().size() > 0 ? new WriteAttributesRequest(target, attrSet) : null;
}
private static Attribute[] createWriteAttributes(Object params) {
List attributeLists = new ArrayList<Attribute>();
ObjectMapper oMapper = new ObjectMapper();
Map<String, Object> map = oMapper.convertValue(params, ConcurrentHashMap.class);
map.forEach((k, v) -> {
if (!v.toString().isEmpty() || (v.toString().isEmpty() && OBJECT_VERSION.equals(k))) {
attributeLists.add(new Attribute(k,
(DIMENSION.equals(k) || MINIMUM_PERIOD.equals(k) || MAXIMUM_PERIOD.equals(k)) ?
((Double) v).longValue() : v));
}
});
return (Attribute[]) attributeLists.toArray(Attribute[]::new);
}
}

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

@ -18,8 +18,6 @@ package org.thingsboard.server.transport.lwm2m.server;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.californium.core.coap.CoAP;
import org.eclipse.californium.core.coap.Response;
import org.eclipse.leshan.core.attributes.Attribute;
import org.eclipse.leshan.core.attributes.AttributeSet;
import org.eclipse.leshan.core.model.ResourceModel;
import org.eclipse.leshan.core.node.LwM2mNode;
import org.eclipse.leshan.core.node.LwM2mPath;
@ -33,7 +31,6 @@ import org.eclipse.leshan.core.request.DownlinkRequest;
import org.eclipse.leshan.core.request.ExecuteRequest;
import org.eclipse.leshan.core.request.ObserveRequest;
import org.eclipse.leshan.core.request.ReadRequest;
import org.eclipse.leshan.core.request.WriteAttributesRequest;
import org.eclipse.leshan.core.request.WriteRequest;
import org.eclipse.leshan.core.request.exception.ClientSleepingException;
import org.eclipse.leshan.core.response.CancelObservationResponse;
@ -60,7 +57,6 @@ import java.util.Date;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import static org.eclipse.leshan.core.attributes.Attribute.MINIMUM_PERIOD;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.DEFAULT_TIMEOUT;
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;
@ -75,6 +71,7 @@ import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandle
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.createWriteAttributeRequest;
@Slf4j
@Service
@ -174,47 +171,7 @@ public class LwM2mTransportRequest {
}
break;
case PUT_TYPE_OPER_WRITE_ATTRIBUTES:
/**
* As example:
* a)Write-Attributes/3/0/9?pmin=1 means the Battery Level value will be notified
* to the Server with a minimum interval of 1sec;
* this value is set at theResource level.
* b)Write-Attributes/3/0/9?pmin means the Battery Level will be notified
* to the Server with a minimum value (pmin) given by the default one
* (resource 2 of Object Server ID=1),
* or with another value if this Attribute has been set at another level
* (Object or Object Instance: see section5.1.1).
* c)Write-Attributes/3/0?pmin=10 means that all Resources of Instance 0 of the Object Device (ID:3)
* will be notified to the Server with a minimum interval of 10 sec;
* this value is set at the Object Instance level.
* d)Write-Attributes /3/0/9?gt=45&st=10 means the Battery Level will be notified to the Server
* when:
* a.old value is 20 and new value is 35 due to step condition
* b.old value is 45 and new value is 50 due to gt condition
* c.old value is 50 and new value is 40 due to both gt and step conditions
* d.old value is 35 and new value is 20 due to step conditione)
* Write-Attributes /3/0/9?lt=20&gt=85&st=10 means the Battery Level will be notified to the Server
* when:
* a.old value is 17 and new value is 24 due to lt condition
* b.old value is 75 and new value is 90 due to both gt and step conditions
* String uriQueries = "pmin=10&pmax=60";
* AttributeSet attributes = AttributeSet.parse(uriQueries);
* WriteAttributesRequest request = new WriteAttributesRequest(target, attributes);
* Attribute gt = new Attribute(GREATER_THAN, Double.valueOf("45"));
* Attribute st = new Attribute(LESSER_THAN, Double.valueOf("10"));
* Attribute pmax = new Attribute(MAXIMUM_PERIOD, "60");
* Attribute [] attrs = {gt, st};
*/
Attribute pmin = new Attribute(MINIMUM_PERIOD, Integer.toUnsignedLong(Integer.parseInt("1")));
Attribute[] attrs = {pmin};
AttributeSet attrSet = new AttributeSet(attrs);
if (resultIds.isResource()) {
request = new WriteAttributesRequest(resultIds.getObjectId(), resultIds.getObjectInstanceId(), resultIds.getResourceId(), attrSet);
} else if (resultIds.isObjectInstance()) {
request = new WriteAttributesRequest(resultIds.getObjectId(), resultIds.getObjectInstanceId(), attrSet);
} else if (resultIds.getObjectId() >= 0) {
request = new WriteAttributesRequest(resultIds.getObjectId(), attrSet);
}
request = createWriteAttributeRequest (target, params);
break;
}

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

@ -51,6 +51,10 @@ public interface LwM2mTransportService {
void onResourceDelete(Optional<TransportProtos.ResourceDeleteMsg> resourceDeleteMsgOpt);
void onToDeviceRpcRequest(TransportProtos.ToDeviceRpcRequestMsg toDeviceRequest);
void onToServerRpcResponse(TransportProtos.ToServerRpcResponseMsg toServerResponse);
void doTrigger(Registration registration, String path);
void doDisconnect(TransportProtos.SessionInfoProto sessionInfo);

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

@ -74,11 +74,14 @@ import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
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;
@ -87,6 +90,7 @@ import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandle
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;
@ -213,7 +217,7 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
* !!! Warn: if have not finishing unReg, then this operation will be finished on next Client`s connect
*/
public void unReg(Registration registration, Collection<Observation> observations) {
executorUnRegistered.submit(() -> {
executorUnRegistered.submit(() -> {
try {
this.setCancelObservations(registration);
this.sendLogsToThingsboard(LOG_LW2M_INFO + ": Client unRegistration", registration);
@ -365,17 +369,15 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
}
/**
*
* @param resourceUpdateMsgOpt -
*/
@Override
public void onResourceUpdate (Optional<TransportProtos.ResourceUpdateMsg> resourceUpdateMsgOpt) {
public void onResourceUpdate(Optional<TransportProtos.ResourceUpdateMsg> resourceUpdateMsgOpt) {
String idVer = resourceUpdateMsgOpt.get().getResourceKey();
lwM2mClientContext.getLwM2mClients().values().stream().forEach(e -> e.updateResourceModel(idVer, this.lwM2mTransportContextServer.getLwM2MTransportConfigServer().getModelProvider()));
}
/**
*
* @param resourceDeleteMsgOpt -
*/
@Override
@ -384,6 +386,14 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
lwM2mClientContext.getLwM2mClients().values().stream().forEach(e -> e.deleteResources(pathIdVer, this.lwM2mTransportContextServer.getLwM2MTransportConfigServer().getModelProvider()));
}
public void onToDeviceRpcRequest(TransportProtos.ToDeviceRpcRequestMsg toDeviceRequest) {
log.info("[{}] toDeviceRpcRequest", toDeviceRequest);
}
public void onToServerRpcResponse(TransportProtos.ToServerRpcResponseMsg toServerResponse) {
log.info("[{}] toServerRpcResponse", toServerResponse);
}
/**
* Trigger Server path = "/1/0/8"
* <p>
@ -496,15 +506,19 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
*/
private void initLwM2mFromClientValue(Registration registration, LwM2mClient lwM2MClient) {
LwM2mClientProfile lwM2MClientProfile = lwM2mClientContext.getProfile(registration);
Set<String> clientObjects = this.getAllOjectsInClient(registration);
if (clientObjects != null && LWM2M_STRATEGY_2 == LwM2mTransportHandler.getClientOnlyObserveAfterConnect(lwM2MClientProfile)) {
// #2
lwM2MClient.getPendingRequests().addAll(clientObjects);
clientObjects.forEach(path -> lwM2mTransportRequest.sendAllRequest(registration, path, GET_TYPE_OPER_READ, ContentFormat.TLV.getName(),
null, null, this.lwM2mTransportContextServer.getLwM2MTransportConfigServer().getTimeout()));
Set<String> clientObjects = lwM2mClientContext.getSupportedIdVerInClient(registration);
if (clientObjects != null && clientObjects.size() > 0) {
if (LWM2M_STRATEGY_2 == LwM2mTransportHandler.getClientOnlyObserveAfterConnect(lwM2MClientProfile)) {
// #2
lwM2MClient.getPendingRequests().addAll(clientObjects);
clientObjects.forEach(path -> lwM2mTransportRequest.sendAllRequest(registration, path, GET_TYPE_OPER_READ, ContentFormat.TLV.getName(),
null, null, this.lwM2mTransportContextServer.getLwM2MTransportConfigServer().getTimeout()));
}
// #1
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);
}
// #1
this.initReadAttrTelemetryObserveToClient(registration, lwM2MClient, GET_TYPE_OPER_OBSERVE);
}
/**
@ -611,41 +625,61 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
/**
* Start observe/read: Attr/Telemetry
* #1 - Analyze:
* #1.1 path in resource profile == client resource
* #1 - Analyze: path in resource profile == client resource
*
* @param registration -
*/
private void initReadAttrTelemetryObserveToClient(Registration registration, LwM2mClient lwM2MClient, String typeOper) {
private void initReadAttrTelemetryObserveToClient(Registration registration, LwM2mClient lwM2MClient,
String typeOper, Set<String> clientObjects) {
LwM2mClientProfile lwM2MClientProfile = lwM2mClientContext.getProfile(registration);
Set<String> clientInstances = this.getAllInstancesInClient(registration);
Set<String> result;
Set<String> result = null;
ConcurrentHashMap<String, Object> params = null;
if (GET_TYPE_OPER_READ.equals(typeOper)) {
result = JacksonUtil.fromString(lwM2MClientProfile.getPostAttributeProfile().toString(), new TypeReference<>() {
});
result.addAll(JacksonUtil.convertValue(lwM2MClientProfile.getPostTelemetryProfile().toString(), new TypeReference<>() {
}));
} else {
result = JacksonUtil.fromString(lwM2MClientProfile.getPostObserveProfile().toString(), new TypeReference<>() {
});
result = JacksonUtil.fromString(lwM2MClientProfile.getPostAttributeProfile().toString(),
new TypeReference<>() {
});
result.addAll(JacksonUtil.fromString(lwM2MClientProfile.getPostTelemetryProfile().toString(),
new TypeReference<>() {
}));
} else if (GET_TYPE_OPER_OBSERVE.equals(typeOper)) {
result = JacksonUtil.fromString(lwM2MClientProfile.getPostObserveProfile().toString(),
new TypeReference<>() {
});
} else if (GET_TYPE_OPER_DISCOVER.equals(typeOper)) {
result = this.getPathForWriteAttributes(lwM2MClientProfile.getPostAttributeLwm2mProfile()).keySet();
;
} else if (PUT_TYPE_OPER_WRITE_ATTRIBUTES.equals(typeOper)) {
params = this.getPathForWriteAttributes(lwM2MClientProfile.getPostAttributeLwm2mProfile());
result = params.keySet();
}
Set<String> pathSend = ConcurrentHashMap.newKeySet();
result.forEach(target -> {
// #1.1
String[] resPath = target.split("/");
String instance = "/" + resPath[1] + "/" + resPath[2];
if (clientInstances != null && clientInstances.size() > 0 && clientInstances.contains(instance)) {
pathSend.add(target);
if (!result.isEmpty()) {
// #1
Set<String> pathSend = result.stream().filter(target -> {
return target.split(LWM2M_SEPARATOR_PATH).length < 3 ?
clientObjects.contains("/" + target.split(LWM2M_SEPARATOR_PATH)[1]) :
clientObjects.contains("/" + target.split(LWM2M_SEPARATOR_PATH)[1] + "/" + target.split(LWM2M_SEPARATOR_PATH)[2]);
}
)
.collect(Collectors.toUnmodifiableSet());
if (!pathSend.isEmpty()) {
lwM2MClient.getPendingRequests().addAll(pathSend);
ConcurrentHashMap<String, Object> finalParams = params;
pathSend.forEach(target -> lwM2mTransportRequest.sendAllRequest(registration, target, typeOper, ContentFormat.TLV.getName(),
null, finalParams != null ? finalParams.get(target) : null, this.lwM2mTransportContextServer.getLwM2MTransportConfigServer().getTimeout()));
if (GET_TYPE_OPER_OBSERVE.equals(typeOper)) {
lwM2MClient.initValue(this, null);
}
}
});
lwM2MClient.getPendingRequests().addAll(pathSend);
pathSend.forEach(target -> lwM2mTransportRequest.sendAllRequest(registration, target, typeOper, ContentFormat.TLV.getName(),
null, null, this.lwM2mTransportContextServer.getLwM2MTransportConfigServer().getTimeout()));
if (GET_TYPE_OPER_OBSERVE.equals(typeOper)) {
lwM2MClient.initValue(this, null);
}
}
private ConcurrentHashMap<String, Object> getPathForWriteAttributes(JsonObject objectJson) {
ConcurrentHashMap<String, Object> pathAttributes = new Gson().fromJson(objectJson.toString(),
new TypeToken<ConcurrentHashMap<String, Object>>() {
}.getType());
return pathAttributes;
}
/**
* Update parameters device in LwM2MClient
* If new deviceProfile != old deviceProfile => update deviceProfile
@ -665,21 +699,6 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
lwM2MClient.setProfileId(device.getDeviceProfileId().getId());
}
/**
* @param registration -
* @return - all object in client
*/
private Set<String> getAllOjectsInClient(Registration registration) {
Set<String> clientObjects = ConcurrentHashMap.newKeySet();
Arrays.stream(registration.getObjectLinks()).forEach(url -> {
LwM2mPath pathIds = new LwM2mPath(url.getUrl());
if (pathIds.isObjectInstance()) {
clientObjects.add("/" + pathIds.getObjectId());
}
});
return (clientObjects.size() > 0) ? clientObjects : null;
}
/**
* @param registration -
* @return all instances in client
@ -724,16 +743,20 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
private void addParameters(String path, JsonObject parameters, Registration registration) {
LwM2mClient lwM2MClient = lwM2mClientContext.getLwM2mClientWithReg(registration, null);
JsonObject names = lwM2mClientContext.getProfiles().get(lwM2MClient.getProfileId()).getPostKeyNameProfile();
String resName = names.get(path).getAsString();
if (resName != null && !resName.isEmpty()) {
try {
String resValue = this.getResourceValueToString(lwM2MClient, path);
if (resValue != null) {
parameters.addProperty(resName, resValue);
if (names != null && names.has(path)) {
String resName = names.get(path).getAsString();
if (resName != null && !resName.isEmpty()) {
try {
String resValue = this.getResourceValueToString(lwM2MClient, path);
if (resValue != null) {
parameters.addProperty(resName, resValue);
}
} catch (Exception e) {
log.error("Failed to add parameters.", e);
}
} catch (Exception e) {
log.error("Failed to add parameters.", e);
}
} else {
log.error("Failed to add parameters. path: [{}], names: [{}]", path, names);
}
}
@ -750,7 +773,7 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
/**
* @param lwM2MClient -
* @param path -
* @param path -
* @return - return value of Resource by idPath
*/
private LwM2mResource returnResourceValueFromLwM2MClient(LwM2mClient lwM2MClient, String path) {
@ -779,6 +802,7 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
* #3.1 Attribute isChange (add&del)
* #3.2 Telemetry isChange (add&del)
* #3.3 KeyName isChange (add)
* #3.4 attributeLwm2m isChange (update WrightAttribute: add/update/del)
* #4 update
* #4.1 add If #3 isChange, then analyze and update Value in Transport form Client and send Value to thingsboard
* #4.2 del
@ -789,6 +813,9 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
* -- path Attr/Telemetry includes newObserve and does not include oldObserve: send Request observe to Client
* #5.3 Observe.del
* -- different between newObserve and oldObserve: send Request cancel observe to client
* #6
* #6.1 - update WriteAttribute
* #6.2 - del WriteAttribute
*
* @param registrationIds -
* @param deviceProfile -
@ -803,6 +830,7 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
Set<String> telemetrySetOld = this.convertJsonArrayToSet(telemetryOld);
JsonArray observeOld = lwM2MClientProfileOld.getPostObserveProfile();
JsonObject keyNameOld = lwM2MClientProfileOld.getPostKeyNameProfile();
JsonObject attributeLwm2mOld = lwM2MClientProfileOld.getPostAttributeLwm2mProfile();
LwM2mClientProfile lwM2MClientProfileNew = lwM2mClientContext.getProfiles().get(deviceProfile.getUuidId());
JsonArray attributeNew = lwM2MClientProfileNew.getPostAttributeProfile();
@ -811,32 +839,41 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
Set<String> telemetrySetNew = this.convertJsonArrayToSet(telemetryNew);
JsonArray observeNew = lwM2MClientProfileNew.getPostObserveProfile();
JsonObject keyNameNew = lwM2MClientProfileNew.getPostKeyNameProfile();
JsonObject attributeLwm2mNew = lwM2MClientProfileNew.getPostAttributeLwm2mProfile();
// #3
ResultsAnalyzerParameters sendAttrToThingsboard = new ResultsAnalyzerParameters();
// #3.1
if (!attributeOld.equals(attributeNew)) {
ResultsAnalyzerParameters postAttributeAnalyzer = this.getAnalyzerParameters(new Gson().fromJson(attributeOld, new TypeToken<Set<String>>() {
}.getType()), attributeSetNew);
ResultsAnalyzerParameters postAttributeAnalyzer = this.getAnalyzerParameters(new Gson().fromJson(attributeOld,
new TypeToken<Set<String>>() {
}.getType()), attributeSetNew);
sendAttrToThingsboard.getPathPostParametersAdd().addAll(postAttributeAnalyzer.getPathPostParametersAdd());
sendAttrToThingsboard.getPathPostParametersDel().addAll(postAttributeAnalyzer.getPathPostParametersDel());
}
// #3.2
if (!telemetryOld.equals(telemetryNew)) {
ResultsAnalyzerParameters postTelemetryAnalyzer = this.getAnalyzerParameters(new Gson().fromJson(telemetryOld, new TypeToken<Set<String>>() {
}.getType()), telemetrySetNew);
ResultsAnalyzerParameters postTelemetryAnalyzer = this.getAnalyzerParameters(new Gson().fromJson(telemetryOld,
new TypeToken<Set<String>>() {
}.getType()), telemetrySetNew);
sendAttrToThingsboard.getPathPostParametersAdd().addAll(postTelemetryAnalyzer.getPathPostParametersAdd());
sendAttrToThingsboard.getPathPostParametersDel().addAll(postTelemetryAnalyzer.getPathPostParametersDel());
}
// #3.3
if (!keyNameOld.equals(keyNameNew)) {
ResultsAnalyzerParameters keyNameChange = this.getAnalyzerKeyName(new Gson().fromJson(keyNameOld.toString(), new TypeToken<ConcurrentHashMap<String, String>>() {
ResultsAnalyzerParameters keyNameChange = this.getAnalyzerKeyName(new Gson().fromJson(keyNameOld.toString(),
new TypeToken<ConcurrentHashMap<String, String>>() {
}.getType()),
new Gson().fromJson(keyNameNew.toString(), new TypeToken<ConcurrentHashMap<String, String>>() {
}.getType()));
sendAttrToThingsboard.getPathPostParametersAdd().addAll(keyNameChange.getPathPostParametersAdd());
}
// #3.4, #6
if (!attributeLwm2mOld.equals(attributeLwm2mNew)) {
this.getAnalyzerAttributeLwm2m(registrationIds, attributeLwm2mOld, attributeLwm2mNew);
}
// #4.1 add
if (sendAttrToThingsboard.getPathPostParametersAdd().size() > 0) {
// update value in Resources
@ -933,7 +970,7 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
});
}
private ResultsAnalyzerParameters getAnalyzerKeyName(ConcurrentMap<String, String> keyNameOld, ConcurrentMap<String, String> keyNameNew) {
private ResultsAnalyzerParameters getAnalyzerKeyName(ConcurrentHashMap<String, String> keyNameOld, ConcurrentHashMap<String, String> keyNameNew) {
ResultsAnalyzerParameters analyzerParameters = new ResultsAnalyzerParameters();
Set<String> paths = keyNameNew.entrySet()
.stream()
@ -943,6 +980,71 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
return analyzerParameters;
}
/**
* #3.4, #6
* #6
* #6.1 - send update WriteAttribute
* #6.2 - send empty WriteAttribute
*
* @param attributeLwm2mOld -
* @param attributeLwm2mNew -
* @return
*/
private void getAnalyzerAttributeLwm2m(Set<String> registrationIds, JsonObject attributeLwm2mOld, JsonObject attributeLwm2mNew) {
ResultsAnalyzerParameters analyzerParameters = new ResultsAnalyzerParameters();
ConcurrentHashMap<String, Object> lwm2mAttributesOld = new Gson().fromJson(attributeLwm2mOld.toString(),
new TypeToken<ConcurrentHashMap<String, Object>>() {
}.getType());
ConcurrentHashMap<String, Object> lwm2mAttributesNew = new Gson().fromJson(attributeLwm2mNew.toString(),
new TypeToken<ConcurrentHashMap<String, Object>>() {
}.getType());
Set<String> pathOld = lwm2mAttributesOld.keySet();
Set<String> pathNew = lwm2mAttributesNew.keySet();
analyzerParameters.setPathPostParametersAdd(pathNew
.stream().filter(p -> !pathOld.contains(p)).collect(Collectors.toSet()));
analyzerParameters.setPathPostParametersDel(pathOld
.stream().filter(p -> !pathNew.contains(p)).collect(Collectors.toSet()));
Set<String> pathCommon = pathNew
.stream().filter(p -> pathOld.contains(p)).collect(Collectors.toSet());
Set<String> pathCommonChange = pathCommon
.stream().filter(p -> !lwm2mAttributesOld.get(p).equals(lwm2mAttributesNew.get(p))).collect(Collectors.toSet());
analyzerParameters.getPathPostParametersAdd().addAll(pathCommonChange);
// #6
// #6.2
if (analyzerParameters.getPathPostParametersAdd().size() > 0) {
registrationIds.forEach(registrationId -> {
Registration registration = this.lwM2mClientContext.getRegistration(registrationId);
Set<String> clientObjects = lwM2mClientContext.getSupportedIdVerInClient(registration);
Set<String> pathSend = analyzerParameters.getPathPostParametersAdd().stream().filter(target -> clientObjects.contains("/" + target.split(LWM2M_SEPARATOR_PATH)[1]))
.collect(Collectors.toUnmodifiableSet());
if (!pathSend.isEmpty()) {
ConcurrentHashMap<String, Object> finalParams = lwm2mAttributesNew;
pathSend.forEach(target -> lwM2mTransportRequest.sendAllRequest(registration, target, PUT_TYPE_OPER_WRITE_ATTRIBUTES, ContentFormat.TLV.getName(),
null, finalParams.get(target), this.lwM2mTransportContextServer.getLwM2MTransportConfigServer().getTimeout()));
}
});
}
// #6.2
if (analyzerParameters.getPathPostParametersDel().size() > 0) {
registrationIds.forEach(registrationId -> {
Registration registration = this.lwM2mClientContext.getRegistration(registrationId);
Set<String> clientObjects = lwM2mClientContext.getSupportedIdVerInClient(registration);
Set<String> pathSend = analyzerParameters.getPathPostParametersDel().stream().filter(target -> clientObjects.contains("/" + target.split(LWM2M_SEPARATOR_PATH)[1]))
.collect(Collectors.toUnmodifiableSet());
if (!pathSend.isEmpty()) {
pathSend.forEach(target -> {
Map<String, Object> params = (Map<String, Object>) lwm2mAttributesOld.get(target);
params.clear();
params.put(OBJECT_VERSION, "");
lwM2mTransportRequest.sendAllRequest(registration, target, PUT_TYPE_OPER_WRITE_ATTRIBUTES, ContentFormat.TLV.getName(),
null, params, this.lwM2mTransportContextServer.getLwM2MTransportConfigServer().getTimeout());
});
}
});
}
}
private void cancelObserveIsValue(Registration registration, Set<String> paramAnallyzer) {
LwM2mClient lwM2MClient = lwM2mClientContext.getLwM2mClientWithReg(registration, null);
paramAnallyzer.forEach(p -> {

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

@ -20,6 +20,7 @@ import org.thingsboard.server.common.data.DeviceProfile;
import org.thingsboard.server.gen.transport.TransportProtos;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
public interface LwM2mClientContext {
@ -51,4 +52,6 @@ public interface LwM2mClientContext {
Map<UUID, LwM2mClientProfile> setProfiles(Map<UUID, LwM2mClientProfile> profiles);
boolean addUpdateProfileParameters(DeviceProfile deviceProfile);
Set<String> getSupportedIdVerInClient(Registration registration);
}

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

@ -15,6 +15,7 @@
*/
package org.thingsboard.server.transport.lwm2m.server.client;
import org.eclipse.leshan.core.node.LwM2mPath;
import org.eclipse.leshan.server.registration.Registration;
import org.eclipse.leshan.server.security.EditableSecurityStore;
import org.springframework.stereotype.Service;
@ -27,11 +28,14 @@ import org.thingsboard.server.transport.lwm2m.secure.ReadResultSecurityStore;
import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler;
import org.thingsboard.server.transport.lwm2m.utils.TypeServer;
import java.util.Arrays;
import java.util.Map;
import java.util.Set;
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;
@Service
@TbLwM2mTransportComponent
@ -90,7 +94,7 @@ public class LwM2mClientContextImpl implements LwM2mClientContext {
@Override
public LwM2mClient updateInSessionsLwM2MClient(Registration registration) {
if (this.lwM2mClients.get(registration.getEndpoint()) == null) {
addLwM2mClientToSession(registration.getEndpoint());
this.addLwM2mClientToSession(registration.getEndpoint());
}
LwM2mClient lwM2MClient = lwM2mClients.get(registration.getEndpoint());
lwM2MClient.setRegistration(registration);
@ -169,4 +173,21 @@ public class LwM2mClientContextImpl implements LwM2mClientContext {
}
return false;
}
/**
* if isVer - ok or default ver=DEFAULT_LWM2M_VERSION
* @param registration -
* @return - all objectIdVer in client
*/
@Override
public Set<String> getSupportedIdVerInClient(Registration registration) {
Set<String> clientObjects = ConcurrentHashMap.newKeySet();
Arrays.stream(registration.getObjectLinks()).forEach(url -> {
LwM2mPath pathIds = new LwM2mPath(url.getUrl());
if (!pathIds.isRoot()) {
clientObjects.add(convertToIdVerFromObjectId(url.getUrl(), registration));
}
});
return (clientObjects.size() > 0) ? clientObjects : null;
}
}

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

@ -56,6 +56,13 @@ public class LwM2mClientProfile {
*/
private JsonArray postObserveProfile;
/**
* "attributeLwm2m": {"/3_1.0": {"ver": "currentTimeTest11"},
* "/3_1.0/0": {"gt": 17},
* "/3_1.0/0/9": {"pmax": 45}, "/3_1.2": {ver": "3_1.2"}}
*/
private JsonObject postAttributeLwm2mProfile;
public LwM2mClientProfile clone() {
LwM2mClientProfile lwM2mClientProfile = new LwM2mClientProfile();
lwM2mClientProfile.postClientLwM2mSettings = this.deepCopy(this.postClientLwM2mSettings, JsonObject.class);
@ -63,6 +70,7 @@ public class LwM2mClientProfile {
lwM2mClientProfile.postAttributeProfile = this.deepCopy(this.postAttributeProfile, JsonArray.class);
lwM2mClientProfile.postTelemetryProfile = this.deepCopy(this.postTelemetryProfile, JsonArray.class);
lwM2mClientProfile.postObserveProfile = this.deepCopy(this.postObserveProfile, JsonArray.class);
lwM2mClientProfile.postAttributeLwm2mProfile = this.deepCopy(this.postAttributeLwm2mProfile, JsonObject.class);
return lwM2mClientProfile;
}

7
ui-ngx/src/app/core/http/resource.service.ts

@ -43,14 +43,17 @@ export class ResourceService {
}
public downloadResource(resourceId: string): Observable<any> {
return this.http.get(`/api/resource/${resourceId}/download`, { responseType: 'arraybuffer', observe: 'response' }).pipe(
return this.http.get(`/api/resource/${resourceId}/download`, {
responseType: 'arraybuffer',
observe: 'response'
}).pipe(
map((response) => {
const headers = response.headers;
const filename = headers.get('x-filename');
const contentType = headers.get('content-type');
const linkElement = document.createElement('a');
try {
const blob = new Blob([response.body], { type: contentType });
const blob = new Blob([response.body], {type: contentType});
const url = URL.createObjectURL(blob);
linkElement.setAttribute('href', url);
linkElement.setAttribute('download', filename);

18
ui-ngx/src/app/core/services/time.service.ts

@ -31,7 +31,7 @@ import { isDefined } from '@core/utils';
export interface TimeInterval {
name: string;
translateParams: {[key: string]: any};
translateParams: { [key: string]: any };
value: number;
}
@ -56,14 +56,14 @@ export class TimeService {
public loadMaxDatapointsLimit(): Observable<number> {
return this.http.get<number>('/api/dashboard/maxDatapointsLimit',
defaultHttpOptions(true)).pipe(
map( (limit) => {
this.maxDatapointsLimit = limit;
if (!this.maxDatapointsLimit || this.maxDatapointsLimit <= MIN_LIMIT) {
this.maxDatapointsLimit = MIN_LIMIT + 1;
}
return this.maxDatapointsLimit;
})
);
map((limit) => {
this.maxDatapointsLimit = limit;
if (!this.maxDatapointsLimit || this.maxDatapointsLimit <= MIN_LIMIT) {
this.maxDatapointsLimit = MIN_LIMIT + 1;
}
return this.maxDatapointsLimit;
})
);
}
public matchesExistingInterval(min: number, max: number, intervalMs: number): boolean {

2
ui-ngx/src/app/core/utils.ts

@ -291,7 +291,7 @@ export function deepClone<T>(target: T, ignoreFields?: string[]): T {
return cp.map((n: any) => deepClone<any>(n)) as any;
}
if (typeof target === 'object' && target !== {}) {
const cp = { ...(target as { [key: string]: any }) } as { [key: string]: any };
const cp = {...(target as { [key: string]: any })} as { [key: string]: any };
Object.keys(cp).forEach(k => {
if (!ignoreFields || ignoreFields.indexOf(k) === -1) {
cp[k] = deepClone<any>(cp[k]);

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

@ -14,12 +14,12 @@
/// limitations under the License.
///
import {DeviceProfileTransportConfiguration, DeviceTransportType} from '@shared/models/device.models';
import {Component, forwardRef, Inject, Input} from '@angular/core';
import {ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR, Validators} from '@angular/forms';
import {Store} from '@ngrx/store';
import {AppState} from '@app/core/core.state';
import {coerceBooleanProperty} from '@angular/cdk/coercion';
import { DeviceProfileTransportConfiguration } from '@shared/models/device.models';
import { Component, forwardRef, Inject, Input } from '@angular/core';
import { ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR, Validators } from '@angular/forms';
import { Store } from '@ngrx/store';
import { AppState } from '@app/core/core.state';
import { coerceBooleanProperty } from '@angular/cdk/coercion';
import {
ATTRIBUTE,
DEFAULT_BINDING,
@ -34,11 +34,11 @@ import {
RESOURCES,
TELEMETRY
} from './lwm2m-profile-config.models';
import {DeviceProfileService} from '@core/http/device-profile.service';
import {deepClone, isDefinedAndNotNull, isEmpty, isUndefined} from '@core/utils';
import {WINDOW} from '@core/services/window.service';
import {JsonArray, JsonObject} from '@angular/compiler-cli/ngcc/src/packages/entry_point';
import {Direction} from '@shared/models/page/sort-order';
import { DeviceProfileService } from '@core/http/device-profile.service';
import { deepClone, isDefinedAndNotNull, isEmpty, isUndefined } from '@core/utils';
import { WINDOW } from '@core/services/window.service';
import { JsonArray, JsonObject } from '@angular/compiler-cli/ngcc/src/packages/entry_point';
import { Direction } from '@shared/models/page/sort-order';
@Component({
selector: 'tb-profile-lwm2m-device-transport-configuration',
@ -173,7 +173,7 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro
}
private updateObserveAttrTelemetryObjectFormGroup = (objectsList: ObjectLwM2M[]): void => {
this.lwm2mDeviceProfileFormGroup.patchValue({
this.lwm2mDeviceProfileFormGroup.patchValue({
observeAttrTelemetry: deepClone(this.getObserveAttrTelemetryObjects(objectsList))
},
{emitEvent: false});
@ -358,6 +358,7 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro
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 = attributeLwm2m;
}
}

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

@ -47,6 +47,7 @@
<ng-template matExpansionPanelContent>
<div fxLayout="column" fxLayoutGap="8px" formArrayName="instances">
<mat-expansion-panel
class="instance-list"
*ngFor="let instances of instancesLwm2mFormArray(objectLwM2M).controls; let y = index;"
[formGroupName]="y"
[expanded]="getExpended(objectLwM2M)"
@ -96,7 +97,7 @@
</div>
<div fxFlex="10">
</div>
<div fxFlex="37" class="resource-name-lw-end" fxFlexOffset="5" disabled="false">
<div fxFlex="37" class="resource-name-lw-end" fxFlexOffset="5">
<tb-profile-lwm2m-attributes
formControlName="attributeLwm2m"
[attributeLwm2m]="instances.get('attributeLwm2m').value"

8
ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-observe-attr-telemetry.component.scss

@ -22,3 +22,11 @@
padding-left: 22px;
text-align:center;
}
:host{
.instance-list {
mat-expansion-panel-header {
color: inherit;
}
}
}

6
ui-ngx/src/app/modules/home/components/widget/lib/json-input-widget.component.ts

@ -146,7 +146,7 @@ export class JsonInputWidgetComponent extends PageComponent implements OnInit {
this.attributeUpdateFormGroup = this.fb.group({
currentValue: [{}, validators]
});
this.attributeUpdateFormGroup.valueChanges.subscribe( () => {
this.attributeUpdateFormGroup.valueChanges.subscribe(() => {
this.ctx.detectChanges();
});
}
@ -191,14 +191,14 @@ export class JsonInputWidgetComponent extends PageComponent implements OnInit {
saveAttributeObservable = this.attributeService.saveEntityAttributes(
entityId,
this.settings.attributeScope,
[ attributeToSave ],
[attributeToSave],
{}
);
} else {
saveAttributeObservable = this.attributeService.saveEntityTimeseries(
entityId,
LatestTelemetry.LATEST_TELEMETRY,
[ attributeToSave ],
[attributeToSave],
{}
);
}

3
ui-ngx/src/app/modules/home/components/widget/widget-components.module.ts

@ -87,4 +87,5 @@ import { JsonInputWidgetComponent } from '@home/components/widget/lib/json-input
ImportExportService
]
})
export class WidgetComponentsModule { }
export class WidgetComponentsModule {
}

2
ui-ngx/src/app/modules/home/pages/asset/assets-table-config.resolver.ts

@ -89,7 +89,7 @@ export class AssetsTableConfigResolver implements Resolve<EntityTableConfig<Asse
this.config.entityTranslations = entityTypeTranslations.get(EntityType.ASSET);
this.config.entityResources = entityTypeResources.get(EntityType.ASSET);
this.config.deleteEntityTitle = asset => this.translate.instant('asset.delete-asset-title', { assetName: asset.name });
this.config.deleteEntityTitle = asset => this.translate.instant('asset.delete-asset-title', {assetName: asset.name});
this.config.deleteEntityContent = () => this.translate.instant('asset.delete-asset-text');
this.config.deleteEntitiesTitle = count => this.translate.instant('asset.delete-assets-title', {count});
this.config.deleteEntitiesContent = () => this.translate.instant('asset.delete-assets-text');

7
ui-ngx/src/app/modules/home/pages/dashboard/dashboards-table-config.resolver.ts

@ -93,7 +93,7 @@ export class DashboardsTableConfigResolver implements Resolve<EntityTableConfig<
this.config.entityResources = entityTypeResources.get(EntityType.DASHBOARD);
this.config.deleteEntityTitle = dashboard =>
this.translate.instant('dashboard.delete-dashboard-title', { dashboardTitle: dashboard.title });
this.translate.instant('dashboard.delete-dashboard-title', {dashboardTitle: dashboard.title});
this.config.deleteEntityContent = () => this.translate.instant('dashboard.delete-dashboard-text');
this.config.deleteEntitiesTitle = count => this.translate.instant('dashboard.delete-dashboards-title', {count});
this.config.deleteEntitiesContent = () => this.translate.instant('dashboard.delete-dashboards-text');
@ -363,8 +363,7 @@ export class DashboardsTableConfigResolver implements Resolve<EntityTableConfig<
this.router.navigateByUrl(`customers/${this.config.componentsData.customerId}/dashboards/${dashboard.id.id}`);
} else if (this.config.componentsData.dashboardScope === 'edge') {
this.router.navigateByUrl(`edges/${this.config.componentsData.edgeId}/dashboards/${dashboard.id.id}`);
}
else {
} else {
this.router.navigateByUrl(`dashboards/${dashboard.id.id}`);
}
}
@ -421,7 +420,7 @@ export class DashboardsTableConfigResolver implements Resolve<EntityTableConfig<
}
}).afterClosed()
.subscribe(() => {
this.config.table.updateData();
this.config.table.updateData();
});
}
);

54
ui-ngx/src/app/modules/home/pages/device/devices-table-config.resolver.ts

@ -97,7 +97,7 @@ export class DevicesTableConfigResolver implements Resolve<EntityTableConfig<Dev
this.config.addDialogStyle = {width: '600px'};
this.config.deleteEntityTitle = device => this.translate.instant('device.delete-device-title', { deviceName: device.name });
this.config.deleteEntityTitle = device => this.translate.instant('device.delete-device-title', {deviceName: device.name});
this.config.deleteEntityContent = () => this.translate.instant('device.delete-device-text');
this.config.deleteEntitiesTitle = count => this.translate.instant('device.delete-devices-title', {count});
this.config.deleteEntitiesContent = () => this.translate.instant('device.delete-devices-text');
@ -109,7 +109,7 @@ export class DevicesTableConfigResolver implements Resolve<EntityTableConfig<Dev
this.broadcast.broadcast('deviceSaved');
}),
mergeMap((savedDevice) => this.deviceService.getDeviceInfo(savedDevice.id.id)
));
));
};
this.config.onEntityAction = action => this.onDeviceAction(action);
this.config.detailsReadonly = () => (this.config.componentsData.deviceScope === 'customer_user' || this.config.componentsData.deviceScope === 'edge_customer_user');
@ -208,7 +208,7 @@ export class DevicesTableConfigResolver implements Resolve<EntityTableConfig<Dev
this.config.entitiesFetchFunction = pageLink =>
this.deviceService.getCustomerDeviceInfosByDeviceProfileId(this.customerId, pageLink,
this.config.componentsData.deviceProfileId !== null ?
this.config.componentsData.deviceProfileId.id : '');
this.config.componentsData.deviceProfileId.id : '');
this.config.deleteEntity = id => this.deviceService.unassignDeviceFromCustomer(id.id);
}
}
@ -250,26 +250,26 @@ export class DevicesTableConfigResolver implements Resolve<EntityTableConfig<Dev
);
}
if (deviceScope === 'customer') {
actions.push(
{
name: this.translate.instant('device.unassign-from-customer'),
icon: 'assignment_return',
isEnabled: (entity) => (entity.customerId && entity.customerId.id !== NULL_UUID && !entity.customerIsPublic),
onAction: ($event, entity) => this.unassignFromCustomer($event, entity)
},
{
name: this.translate.instant('device.make-private'),
icon: 'reply',
isEnabled: (entity) => (entity.customerId && entity.customerId.id !== NULL_UUID && entity.customerIsPublic),
onAction: ($event, entity) => this.unassignFromCustomer($event, entity)
},
{
name: this.translate.instant('device.manage-credentials'),
icon: 'security',
isEnabled: () => true,
onAction: ($event, entity) => this.manageCredentials($event, entity)
}
);
actions.push(
{
name: this.translate.instant('device.unassign-from-customer'),
icon: 'assignment_return',
isEnabled: (entity) => (entity.customerId && entity.customerId.id !== NULL_UUID && !entity.customerIsPublic),
onAction: ($event, entity) => this.unassignFromCustomer($event, entity)
},
{
name: this.translate.instant('device.make-private'),
icon: 'reply',
isEnabled: (entity) => (entity.customerId && entity.customerId.id !== NULL_UUID && entity.customerIsPublic),
onAction: ($event, entity) => this.unassignFromCustomer($event, entity)
},
{
name: this.translate.instant('device.manage-credentials'),
icon: 'security',
isEnabled: () => true,
onAction: ($event, entity) => this.manageCredentials($event, entity)
}
);
}
if (deviceScope === 'customer_user' || deviceScope === 'edge_customer_user') {
actions.push(
@ -452,10 +452,10 @@ export class DevicesTableConfigResolver implements Resolve<EntityTableConfig<Dev
}
}).afterClosed()
.subscribe((res) => {
if (res) {
this.config.table.updateData();
}
});
if (res) {
this.config.table.updateData();
}
});
}
unassignFromCustomer($event: Event, device: DeviceInfo) {

12
ui-ngx/src/app/modules/home/pages/edge/edge-routing.module.ts

@ -33,8 +33,11 @@ import { RuleChainType } from '@shared/models/rule-chain.models';
import {
importRuleChainBreadcumbLabelFunction,
ResolvedRuleChainMetaDataResolver,
ruleChainBreadcumbLabelFunction, RuleChainImportGuard,
RuleChainResolver, RuleNodeComponentsResolver, TooltipsterResolver
ruleChainBreadcumbLabelFunction,
RuleChainImportGuard,
RuleChainResolver,
RuleNodeComponentsResolver,
TooltipsterResolver
} from '@home/pages/rulechain/rulechain-routing.module';
const routes: Routes = [
@ -249,7 +252,7 @@ const routes: Routes = [
}
]
}
]
]
}];
@NgModule({
@ -259,4 +262,5 @@ const routes: Routes = [
EdgesTableConfigResolver
]
})
export class EdgeRoutingModule { }
export class EdgeRoutingModule {
}

5
ui-ngx/src/app/modules/home/pages/entity-view/entity-views-table-config.resolver.ts

@ -89,7 +89,7 @@ export class EntityViewsTableConfigResolver implements Resolve<EntityTableConfig
this.config.addDialogStyle = {maxWidth: '800px'};
this.config.deleteEntityTitle = entityView =>
this.translate.instant('entity-view.delete-entity-view-title', { entityViewName: entityView.name });
this.translate.instant('entity-view.delete-entity-view-title', {entityViewName: entityView.name});
this.config.deleteEntityContent = () => this.translate.instant('entity-view.delete-entity-view-text');
this.config.deleteEntitiesTitle = count => this.translate.instant('entity-view.delete-entity-views-title', {count});
this.config.deleteEntitiesContent = () => this.translate.instant('entity-view.delete-entity-views-text');
@ -143,8 +143,7 @@ export class EntityViewsTableConfigResolver implements Resolve<EntityTableConfig
this.edgeService.getEdge(this.config.componentsData.edgeId).subscribe(
edge => this.config.tableTitle = edge.name + ': ' + this.translate.instant('entity-view.entity-views')
);
}
else {
} else {
this.config.tableTitle = this.translate.instant('entity-view.entity-views');
}
this.config.columns = this.configureColumns(this.config.componentsData.entityViewScope);

6
ui-ngx/src/app/modules/home/pages/resource/resources-library.component.ts

@ -90,8 +90,10 @@ export class ResourcesLibraryComponent extends EntityComponent<Resource> impleme
buildForm(entity: Resource): FormGroup {
return this.fb.group(
{
resourceType: [{value: entity?.resourceType ? entity.resourceType : ResourceType.LWM2M_MODEL,
disabled: this.isEdit }, [Validators.required]],
resourceType: [{
value: entity?.resourceType ? entity.resourceType : ResourceType.LWM2M_MODEL,
disabled: this.isEdit
}, [Validators.required]],
data: [entity ? entity.data : null, [Validators.required]],
fileName: [entity ? entity.fileName : null, [Validators.required]],
title: [entity ? entity.title : '', []]

72
ui-ngx/src/app/modules/home/pages/rulechain/rulechains-table-config.resolver.ts

@ -73,7 +73,7 @@ export class RuleChainsTableConfigResolver implements Resolve<EntityTableConfig<
this.config.entityResources = entityTypeResources.get(EntityType.RULE_CHAIN);
this.config.deleteEntityTitle = ruleChain => this.translate.instant('rulechain.delete-rulechain-title',
{ ruleChainName: ruleChain.name });
{ruleChainName: ruleChain.name});
this.config.deleteEntityContent = () => this.translate.instant('rulechain.delete-rulechain-text');
this.config.deleteEntitiesTitle = count => this.translate.instant('rulechain.delete-rulechains-title', {count});
this.config.deleteEntitiesContent = () => this.translate.instant('rulechain.delete-rulechains-text');
@ -121,11 +121,11 @@ export class RuleChainsTableConfigResolver implements Resolve<EntityTableConfig<
columns.push(
new EntityTableColumn<RuleChain>('root', 'rulechain.root', '60px',
entity => {
if (ruleChainScope === 'edge') {
return checkBoxCell((this.config.componentsData.edge.rootRuleChainId.id === entity.id.id));
} else {
return checkBoxCell(entity.root);
}
if (ruleChainScope === 'edge') {
return checkBoxCell((this.config.componentsData.edge.rootRuleChainId.id === entity.id.id));
} else {
return checkBoxCell(entity.root);
}
})
);
} else if (ruleChainScope === 'edges') {
@ -421,32 +421,32 @@ export class RuleChainsTableConfigResolver implements Resolve<EntityTableConfig<
}
}).afterClosed()
.subscribe((res) => {
if (res) {
this.edgeService.findMissingToRelatedRuleChains(this.config.componentsData.edgeId).subscribe(
(missingRuleChains) => {
if (missingRuleChains && Object.keys(missingRuleChains).length > 0) {
const formattedMissingRuleChains: Array<string> = new Array<string>();
for (const missingRuleChain of Object.keys(missingRuleChains)) {
const arrayOfMissingRuleChains = missingRuleChains[missingRuleChain];
const tmp = '- \'' + missingRuleChain + '\': \'' + arrayOfMissingRuleChains.join('\', ') + '\'';
formattedMissingRuleChains.push(tmp);
}
const message = this.translate.instant('edge.missing-related-rule-chains-text',
{missingRuleChains: formattedMissingRuleChains.join('<br>')});
this.dialogService.alert(this.translate.instant('edge.missing-related-rule-chains-title'),
message, this.translate.instant('action.close'), true).subscribe(
() => {
this.config.table.updateData();
if (res) {
this.edgeService.findMissingToRelatedRuleChains(this.config.componentsData.edgeId).subscribe(
(missingRuleChains) => {
if (missingRuleChains && Object.keys(missingRuleChains).length > 0) {
const formattedMissingRuleChains: Array<string> = new Array<string>();
for (const missingRuleChain of Object.keys(missingRuleChains)) {
const arrayOfMissingRuleChains = missingRuleChains[missingRuleChain];
const tmp = '- \'' + missingRuleChain + '\': \'' + arrayOfMissingRuleChains.join('\', ') + '\'';
formattedMissingRuleChains.push(tmp);
}
);
} else {
this.config.table.updateData();
const message = this.translate.instant('edge.missing-related-rule-chains-text',
{missingRuleChains: formattedMissingRuleChains.join('<br>')});
this.dialogService.alert(this.translate.instant('edge.missing-related-rule-chains-title'),
message, this.translate.instant('action.close'), true).subscribe(
() => {
this.config.table.updateData();
}
);
} else {
this.config.table.updateData();
}
}
}
);
);
}
}
}
);
);
}
unassignFromEdge($event: Event, ruleChain: RuleChain) {
@ -510,13 +510,13 @@ export class RuleChainsTableConfigResolver implements Resolve<EntityTableConfig<
this.translate.instant('action.yes'),
true
).subscribe((res) => {
if (res) {
this.ruleChainService.setAutoAssignToEdgeRuleChain(ruleChain.id.id).subscribe(
() => {
this.config.table.updateData();
}
);
}
if (res) {
this.ruleChainService.setAutoAssignToEdgeRuleChain(ruleChain.id.id).subscribe(
() => {
this.config.table.updateData();
}
);
}
}
);
}

4
ui-ngx/src/app/shared/components/file-input.component.ts

@ -73,9 +73,11 @@ export class FileInputComponent extends PageComponent implements AfterViewInit,
contentConvertFunction: (content: string) => any;
private requiredValue: boolean;
get required(): boolean {
return this.requiredValue;
}
@Input()
set required(value: boolean) {
const newVal = coerceBooleanProperty(value);
@ -85,9 +87,11 @@ export class FileInputComponent extends PageComponent implements AfterViewInit,
}
private requiredAsErrorValue: boolean;
get requiredAsError(): boolean {
return this.requiredAsErrorValue;
}
@Input()
set requiredAsError(value: boolean) {
const newVal = coerceBooleanProperty(value);

2
ui-ngx/src/app/shared/components/json-object-edit.component.ts

@ -22,7 +22,7 @@ import { ActionNotificationHide, ActionNotificationShow } from '@core/notificati
import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state';
import { CancelAnimationFrame, RafService } from '@core/services/raf.service';
import { guid, isUndefined, isDefinedAndNotNull, isLiteralObject } from '@core/utils';
import { guid, isDefinedAndNotNull, isLiteralObject, isUndefined } from '@core/utils';
import { ResizeObserver } from '@juggle/resize-observer';
import { getAce } from '@shared/models/ace/ace.models';

2
ui-ngx/src/app/shared/models/resource.models.ts

@ -45,7 +45,7 @@ export const ResourceTypeTranslationMap = new Map<ResourceType, string>(
[ResourceType.LWM2M_MODEL, 'LWM2M model'],
[ResourceType.PKCS_12, 'PKCS #12'],
[ResourceType.JKS, 'JKS']
]
]
);
export interface ResourceInfo extends BaseData<TbResourceId> {

Loading…
Cancel
Save